Cleanup
[TortoiseGit.git] / src / Utils / MiscUI / SysProgressDlg.cpp
blobb8b3b155ca8205f11e4f5d3af82b637270d54748
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)
29 EnsureValid();
32 CSysProgressDlg::~CSysProgressDlg()
34 if (IsValid())
36 if (m_isVisible) //still visible, so stop first before destroying
37 m_pIDlg->StopProgressDialog();
39 m_pIDlg.Release();
40 m_hWndProgDlg = NULL;
44 bool CSysProgressDlg::EnsureValid()
46 if(IsValid())
47 return true;
49 HRESULT hr = m_pIDlg.CoCreateInstance (CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER);
50 return (SUCCEEDED(hr));
53 void CSysProgressDlg::SetTitle(LPCTSTR szTitle)
55 USES_CONVERSION;
56 if (IsValid())
58 m_pIDlg->SetTitle(T2COLE(szTitle));
61 void CSysProgressDlg::SetTitle ( UINT idTitle)
63 SetTitle(CString(MAKEINTRESOURCE(idTitle)));
66 void CSysProgressDlg::SetLine(DWORD dwLine, LPCTSTR szText, bool bCompactPath /* = false */)
68 USES_CONVERSION;
69 if (IsValid())
71 m_pIDlg->SetLine(dwLine, T2COLE(szText), bCompactPath, NULL);
75 #ifdef _MFC_VER
76 void CSysProgressDlg::SetCancelMsg ( UINT idMessage )
78 SetCancelMsg(CString(MAKEINTRESOURCE(idMessage)));
80 #endif // _MFC_VER
82 void CSysProgressDlg::SetCancelMsg(LPCTSTR szMessage)
84 USES_CONVERSION;
85 if (IsValid())
87 m_pIDlg->SetCancelMsg(T2COLE(szMessage), NULL);
91 void CSysProgressDlg::SetAnimation(HINSTANCE hinst, UINT uRsrcID)
93 if (IsValid())
95 m_pIDlg->SetAnimation(hinst, uRsrcID);
98 #ifdef _MFC_VER
99 void CSysProgressDlg::SetAnimation(UINT uRsrcID)
101 if (IsValid())
103 m_pIDlg->SetAnimation(AfxGetResourceHandle(), uRsrcID);
106 #endif
107 void CSysProgressDlg::SetTime(bool bTime /* = true */)
109 m_dwDlgFlags &= ~(PROGDLG_NOTIME | PROGDLG_AUTOTIME);
111 if (bTime)
112 m_dwDlgFlags |= PROGDLG_AUTOTIME;
113 else
114 m_dwDlgFlags |= PROGDLG_NOTIME;
117 void CSysProgressDlg::SetShowProgressBar(bool bShow /* = true */)
119 if (bShow)
120 m_dwDlgFlags &= ~PROGDLG_NOPROGRESSBAR;
121 else
122 m_dwDlgFlags |= PROGDLG_NOPROGRESSBAR;
124 #ifdef _MFC_VER
125 HRESULT CSysProgressDlg::ShowModal (CWnd* pwndParent, BOOL immediately /* = true */)
127 EnsureValid();
128 return ShowModal(pwndParent->GetSafeHwnd(), immediately);
131 HRESULT CSysProgressDlg::ShowModeless(CWnd* pwndParent, BOOL immediately)
133 EnsureValid();
134 return ShowModeless(pwndParent->GetSafeHwnd(), immediately);
137 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, UINT idFormatText, ...)
139 va_list args;
140 va_start(args, idFormatText);
142 CString sText;
143 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
144 SetLine(dwLine, sText, true);
146 va_end(args);
149 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, CString FormatText, ...)
151 va_list args;
152 va_start(args, FormatText);
154 CString sText;
155 sText.FormatV(FormatText, args);
156 SetLine(dwLine, sText, true);
158 va_end(args);
161 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, UINT idFormatText, ...)
163 va_list args;
164 va_start(args, idFormatText);
166 CString sText;
167 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
168 SetLine(dwLine, sText, false);
170 va_end(args);
173 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, CString FormatText, ...)
175 va_list args;
176 va_start(args, FormatText);
178 CString sText;
179 sText.FormatV(FormatText, args);
180 SetLine(dwLine, sText, false);
182 va_end(args);
185 #endif
186 HRESULT CSysProgressDlg::ShowModal(HWND hWndParent, BOOL immediately /* = true */)
188 EnsureValid();
189 m_hWndProgDlg = NULL;
190 if (!IsValid())
191 return E_FAIL;
192 m_hWndParent = hWndParent;
193 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags | PROGDLG_MODAL, NULL);
194 if(FAILED(hr))
195 return hr;
197 ATL::CComPtr<IOleWindow> pOleWindow;
198 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
199 if(SUCCEEDED(hr2))
201 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
202 if(SUCCEEDED(hr2))
204 // StartProgressDialog creates a new thread to host the progress window.
205 // When the window receives WM_DESTROY message StopProgressDialog() wrongly
206 // attempts to re-enable the parent in the calling thread (our thread),
207 // after the progress window is destroyed and the progress thread has died.
208 // When the progress window dies, the system tries to assign a new foreground window.
209 // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window.
210 // So the system hands the foreground activation to the next process that wants it in the
211 // system foreground queue. Thus we lose our right to recapture the foreground window.
212 // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY
213 // handler for the progress window in the progress thread.
215 // To do that, we Subclass the progress dialog
216 // Since the window and thread created by the progress dialog object live on a few
217 // milliseconds after calling Stop() and Release(), we must not store anything
218 // in member variables of this class but must only store everything in the window
219 // itself: thus we use SetProp()/GetProp() to store the data.
220 if (!m_isVisible)
222 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
223 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
224 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
226 if(immediately)
227 ShowWindow(m_hWndProgDlg, SW_SHOW);
231 m_isVisible = true;
232 return hr;
235 HRESULT CSysProgressDlg::ShowModeless(HWND hWndParent, BOOL immediately)
237 EnsureValid();
238 m_hWndProgDlg = NULL;
239 if (!IsValid())
240 return E_FAIL;
241 m_hWndParent = hWndParent;
242 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags, NULL);
243 if(FAILED(hr))
244 return hr;
246 ATL::CComPtr<IOleWindow> pOleWindow;
247 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
248 if(SUCCEEDED(hr2))
250 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
251 if(SUCCEEDED(hr2))
253 // see comment in ShowModal() for why we subclass the window
254 if (!m_isVisible)
256 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
257 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
258 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
260 if (immediately)
261 ShowWindow(m_hWndProgDlg, SW_SHOW);
264 m_isVisible = true;
265 return hr;
268 void CSysProgressDlg::SetProgress(DWORD dwProgress, DWORD dwMax)
270 if (IsValid())
272 m_pIDlg->SetProgress(dwProgress, dwMax);
276 void CSysProgressDlg::SetProgress64(ULONGLONG u64Progress, ULONGLONG u64ProgressMax)
278 if (IsValid())
280 m_pIDlg->SetProgress64(u64Progress, u64ProgressMax);
284 bool CSysProgressDlg::HasUserCancelled()
286 if (!IsValid())
287 return false;
289 return (0 != m_pIDlg->HasUserCancelled());
292 void CSysProgressDlg::Stop()
294 if ((m_isVisible)&&(IsValid()))
296 m_pIDlg->StopProgressDialog();
297 // Sometimes the progress dialog sticks around after stopping it,
298 // until the mouse pointer is moved over it or some other triggers.
299 // We hide the window here immediately.
300 if (m_hWndProgDlg)
302 ShowWindow(m_hWndProgDlg, SW_HIDE);
304 m_isVisible = false;
305 m_pIDlg.Release();
307 m_hWndProgDlg = NULL;
311 void CSysProgressDlg::ResetTimer()
313 if (IsValid())
315 m_pIDlg->Timer(PDTIMER_RESET, NULL);
319 LRESULT CSysProgressDlg::fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
321 LONG_PTR origproc = (LONG_PTR)GetProp(hwnd, L"OrigProc");
322 if (uMsg == WM_DESTROY)
324 HWND hParent = (HWND)GetProp(hwnd, L"ParentWindow");
325 EnableWindow(hParent, TRUE);
326 SetFocus(hParent);
327 SetWindowLongPtr (hwnd, GWLP_WNDPROC, origproc);
328 RemoveProp(hwnd, L"ParentWindow");
329 RemoveProp(hwnd, L"OrigProc");
331 return CallWindowProc ((WNDPROC)origproc, hwnd, uMsg, wParam, lParam);