Sync TortoiseIDiff and TortoiseUDiff from TortoiseSVN
[TortoiseGit.git] / src / Utils / MiscUI / SysProgressDlg.cpp
blobf2a59bc4b091384d6c051eab2a4e62f0da3f6ee0
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2010-2012 - TortoiseGit
4 // Copyright (C) 2003-2006,2008-2011 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "SysProgressDlg.h"
23 CSysProgressDlg::CSysProgressDlg()
24 : m_pIDlg(NULL)
25 , m_isVisible(false)
26 , m_dwDlgFlags(PROGDLG_NORMAL)
27 , m_hWndProgDlg(NULL)
28 , m_hWndParent(NULL)
30 EnsureValid();
33 CSysProgressDlg::~CSysProgressDlg()
35 if (IsValid())
37 if (m_isVisible) //still visible, so stop first before destroying
38 m_pIDlg->StopProgressDialog();
40 m_pIDlg.Release();
41 m_hWndProgDlg = NULL;
45 bool CSysProgressDlg::EnsureValid()
47 if(IsValid())
48 return true;
50 HRESULT hr = m_pIDlg.CoCreateInstance (CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER);
51 return (SUCCEEDED(hr));
54 void CSysProgressDlg::SetTitle(LPCTSTR szTitle)
56 USES_CONVERSION;
57 if (IsValid())
59 m_pIDlg->SetTitle(T2COLE(szTitle));
62 void CSysProgressDlg::SetTitle ( UINT idTitle)
64 SetTitle(CString(MAKEINTRESOURCE(idTitle)));
67 void CSysProgressDlg::SetLine(DWORD dwLine, LPCTSTR szText, bool bCompactPath /* = false */)
69 USES_CONVERSION;
70 if (IsValid())
72 m_pIDlg->SetLine(dwLine, T2COLE(szText), bCompactPath, NULL);
76 #ifdef _MFC_VER
77 void CSysProgressDlg::SetCancelMsg ( UINT idMessage )
79 SetCancelMsg(CString(MAKEINTRESOURCE(idMessage)));
81 #endif // _MFC_VER
83 void CSysProgressDlg::SetCancelMsg(LPCTSTR szMessage)
85 USES_CONVERSION;
86 if (IsValid())
88 m_pIDlg->SetCancelMsg(T2COLE(szMessage), NULL);
92 void CSysProgressDlg::SetAnimation(HINSTANCE hinst, UINT uRsrcID)
94 if (IsValid())
96 m_pIDlg->SetAnimation(hinst, uRsrcID);
99 #ifdef _MFC_VER
100 void CSysProgressDlg::SetAnimation(UINT uRsrcID)
102 if (IsValid())
104 m_pIDlg->SetAnimation(AfxGetResourceHandle(), uRsrcID);
107 #endif
108 void CSysProgressDlg::SetTime(bool bTime /* = true */)
110 m_dwDlgFlags &= ~(PROGDLG_NOTIME | PROGDLG_AUTOTIME);
112 if (bTime)
113 m_dwDlgFlags |= PROGDLG_AUTOTIME;
114 else
115 m_dwDlgFlags |= PROGDLG_NOTIME;
118 void CSysProgressDlg::SetShowProgressBar(bool bShow /* = true */)
120 if (bShow)
121 m_dwDlgFlags &= ~PROGDLG_NOPROGRESSBAR;
122 else
123 m_dwDlgFlags |= PROGDLG_NOPROGRESSBAR;
125 #ifdef _MFC_VER
126 HRESULT CSysProgressDlg::ShowModal (CWnd* pwndParent, BOOL immediately /* = true */)
128 EnsureValid();
129 return ShowModal(pwndParent->GetSafeHwnd(), immediately);
132 HRESULT CSysProgressDlg::ShowModeless(CWnd* pwndParent, BOOL immediately)
134 EnsureValid();
135 return ShowModeless(pwndParent->GetSafeHwnd(), immediately);
138 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, UINT idFormatText, ...)
140 va_list args;
141 va_start(args, idFormatText);
143 CString sText;
144 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
145 SetLine(dwLine, sText, true);
147 va_end(args);
150 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, CString FormatText, ...)
152 va_list args;
153 va_start(args, FormatText);
155 CString sText;
156 sText.FormatV(FormatText, args);
157 SetLine(dwLine, sText, true);
159 va_end(args);
162 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, UINT idFormatText, ...)
164 va_list args;
165 va_start(args, idFormatText);
167 CString sText;
168 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
169 SetLine(dwLine, sText, false);
171 va_end(args);
174 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, CString FormatText, ...)
176 va_list args;
177 va_start(args, FormatText);
179 CString sText;
180 sText.FormatV(FormatText, args);
181 SetLine(dwLine, sText, false);
183 va_end(args);
186 #endif
187 HRESULT CSysProgressDlg::ShowModal(HWND hWndParent, BOOL immediately /* = true */)
189 EnsureValid();
190 m_hWndProgDlg = NULL;
191 if (!IsValid())
192 return E_FAIL;
193 m_hWndParent = hWndParent;
194 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags | PROGDLG_MODAL, NULL);
195 if(FAILED(hr))
196 return hr;
198 ATL::CComPtr<IOleWindow> pOleWindow;
199 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
200 if(SUCCEEDED(hr2))
202 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
203 if(SUCCEEDED(hr2))
205 // StartProgressDialog creates a new thread to host the progress window.
206 // When the window receives WM_DESTROY message StopProgressDialog() wrongly
207 // attempts to re-enable the parent in the calling thread (our thread),
208 // after the progress window is destroyed and the progress thread has died.
209 // When the progress window dies, the system tries to assign a new foreground window.
210 // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window.
211 // So the system hands the foreground activation to the next process that wants it in the
212 // system foreground queue. Thus we lose our right to recapture the foreground window.
213 // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY
214 // handler for the progress window in the progress thread.
216 // To do that, we Subclass the progress dialog
217 // Since the window and thread created by the progress dialog object live on a few
218 // milliseconds after calling Stop() and Release(), we must not store anything
219 // in member variables of this class but must only store everything in the window
220 // itself: thus we use SetProp()/GetProp() to store the data.
221 if (!m_isVisible)
223 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
224 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
225 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
227 if(immediately)
228 ShowWindow(m_hWndProgDlg, SW_SHOW);
232 m_isVisible = true;
233 return hr;
236 HRESULT CSysProgressDlg::ShowModeless(HWND hWndParent, BOOL immediately)
238 EnsureValid();
239 m_hWndProgDlg = NULL;
240 if (!IsValid())
241 return E_FAIL;
242 m_hWndParent = hWndParent;
243 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags, NULL);
244 if(FAILED(hr))
245 return hr;
247 ATL::CComPtr<IOleWindow> pOleWindow;
248 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
249 if(SUCCEEDED(hr2))
251 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
252 if(SUCCEEDED(hr2))
254 // see comment in ShowModal() for why we subclass the window
255 if (!m_isVisible)
257 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
258 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
259 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
261 if (immediately)
262 ShowWindow(m_hWndProgDlg, SW_SHOW);
265 m_isVisible = true;
266 return hr;
269 void CSysProgressDlg::SetProgress(DWORD dwProgress, DWORD dwMax)
271 if (IsValid())
273 m_pIDlg->SetProgress(dwProgress, dwMax);
277 void CSysProgressDlg::SetProgress64(ULONGLONG u64Progress, ULONGLONG u64ProgressMax)
279 if (IsValid())
281 m_pIDlg->SetProgress64(u64Progress, u64ProgressMax);
285 bool CSysProgressDlg::HasUserCancelled()
287 if (!IsValid())
288 return false;
290 return (0 != m_pIDlg->HasUserCancelled());
293 void CSysProgressDlg::Stop()
295 if ((m_isVisible)&&(IsValid()))
297 m_pIDlg->StopProgressDialog();
298 // Sometimes the progress dialog sticks around after stopping it,
299 // until the mouse pointer is moved over it or some other triggers.
300 // We hide the window here immediately.
301 if (m_hWndProgDlg)
303 ShowWindow(m_hWndProgDlg, SW_HIDE);
305 m_isVisible = false;
306 m_pIDlg.Release();
308 m_hWndProgDlg = NULL;
312 void CSysProgressDlg::ResetTimer()
314 if (IsValid())
316 m_pIDlg->Timer(PDTIMER_RESET, NULL);
320 LRESULT CSysProgressDlg::fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
322 LONG_PTR origproc = (LONG_PTR)GetProp(hwnd, L"OrigProc");
323 if (uMsg == WM_DESTROY)
325 HWND hParent = (HWND)GetProp(hwnd, L"ParentWindow");
326 EnableWindow(hParent, TRUE);
327 SetFocus(hParent);
328 SetWindowLongPtr (hwnd, GWLP_WNDPROC, origproc);
329 RemoveProp(hwnd, L"ParentWindow");
330 RemoveProp(hwnd, L"OrigProc");
332 return CallWindowProc ((WNDPROC)origproc, hwnd, uMsg, wParam, lParam);