Minor cleanup
[TortoiseGit.git] / src / Utils / MiscUI / SysProgressDlg.cpp
blob903bc340549a6d25b88626539d3817a6228db278
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2010-2013 - 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)
29 , m_OrigProc(0)
31 EnsureValid();
34 CSysProgressDlg::~CSysProgressDlg()
36 if (IsValid())
38 if (m_isVisible) //still visible, so stop first before destroying
39 m_pIDlg->StopProgressDialog();
41 m_pIDlg.Release();
42 m_hWndProgDlg = NULL;
46 bool CSysProgressDlg::EnsureValid()
48 if(IsValid())
49 return true;
51 HRESULT hr = m_pIDlg.CoCreateInstance (CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER);
52 return (SUCCEEDED(hr));
55 void CSysProgressDlg::SetTitle(LPCTSTR szTitle)
57 USES_CONVERSION;
58 if (IsValid())
60 m_pIDlg->SetTitle(T2COLE(szTitle));
63 void CSysProgressDlg::SetTitle ( UINT idTitle)
65 SetTitle(CString(MAKEINTRESOURCE(idTitle)));
68 void CSysProgressDlg::SetLine(DWORD dwLine, LPCTSTR szText, bool bCompactPath /* = false */)
70 USES_CONVERSION;
71 if (IsValid())
73 m_pIDlg->SetLine(dwLine, T2COLE(szText), bCompactPath, NULL);
77 #ifdef _MFC_VER
78 void CSysProgressDlg::SetCancelMsg ( UINT idMessage )
80 SetCancelMsg(CString(MAKEINTRESOURCE(idMessage)));
82 #endif // _MFC_VER
84 void CSysProgressDlg::SetCancelMsg(LPCTSTR szMessage)
86 USES_CONVERSION;
87 if (IsValid())
89 m_pIDlg->SetCancelMsg(T2COLE(szMessage), NULL);
93 void CSysProgressDlg::SetAnimation(HINSTANCE hinst, UINT uRsrcID)
95 if (IsValid())
97 m_pIDlg->SetAnimation(hinst, uRsrcID);
100 #ifdef _MFC_VER
101 void CSysProgressDlg::SetAnimation(UINT uRsrcID)
103 if (IsValid())
105 m_pIDlg->SetAnimation(AfxGetResourceHandle(), uRsrcID);
108 #endif
109 void CSysProgressDlg::SetTime(bool bTime /* = true */)
111 m_dwDlgFlags &= ~(PROGDLG_NOTIME | PROGDLG_AUTOTIME);
113 if (bTime)
114 m_dwDlgFlags |= PROGDLG_AUTOTIME;
115 else
116 m_dwDlgFlags |= PROGDLG_NOTIME;
119 void CSysProgressDlg::SetShowProgressBar(bool bShow /* = true */)
121 if (bShow)
122 m_dwDlgFlags &= ~PROGDLG_NOPROGRESSBAR;
123 else
124 m_dwDlgFlags |= PROGDLG_NOPROGRESSBAR;
126 #ifdef _MFC_VER
127 HRESULT CSysProgressDlg::ShowModal (CWnd* pwndParent, BOOL immediately /* = true */)
129 EnsureValid();
130 return ShowModal(pwndParent->GetSafeHwnd(), immediately);
133 HRESULT CSysProgressDlg::ShowModeless(CWnd* pwndParent, BOOL immediately)
135 EnsureValid();
136 return ShowModeless(pwndParent->GetSafeHwnd(), immediately);
139 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, UINT idFormatText, ...)
141 va_list args;
142 va_start(args, idFormatText);
144 CString sText;
145 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
146 SetLine(dwLine, sText, true);
148 va_end(args);
151 void CSysProgressDlg::FormatPathLine ( DWORD dwLine, CString FormatText, ...)
153 va_list args;
154 va_start(args, FormatText);
156 CString sText;
157 sText.FormatV(FormatText, args);
158 SetLine(dwLine, sText, true);
160 va_end(args);
163 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, UINT idFormatText, ...)
165 va_list args;
166 va_start(args, idFormatText);
168 CString sText;
169 sText.FormatV(CString(MAKEINTRESOURCE(idFormatText)), args);
170 SetLine(dwLine, sText, false);
172 va_end(args);
175 void CSysProgressDlg::FormatNonPathLine(DWORD dwLine, CString FormatText, ...)
177 va_list args;
178 va_start(args, FormatText);
180 CString sText;
181 sText.FormatV(FormatText, args);
182 SetLine(dwLine, sText, false);
184 va_end(args);
187 #endif
188 HRESULT CSysProgressDlg::ShowModal(HWND hWndParent, BOOL immediately /* = true */)
190 EnsureValid();
191 m_hWndProgDlg = NULL;
192 if (!IsValid())
193 return E_FAIL;
194 m_hWndParent = hWndParent;
195 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags | PROGDLG_MODAL, NULL);
196 if(FAILED(hr))
197 return hr;
199 ATL::CComPtr<IOleWindow> pOleWindow;
200 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
201 if(SUCCEEDED(hr2))
203 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
204 if(SUCCEEDED(hr2))
206 // StartProgressDialog creates a new thread to host the progress window.
207 // When the window receives WM_DESTROY message StopProgressDialog() wrongly
208 // attempts to re-enable the parent in the calling thread (our thread),
209 // after the progress window is destroyed and the progress thread has died.
210 // When the progress window dies, the system tries to assign a new foreground window.
211 // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window.
212 // So the system hands the foreground activation to the next process that wants it in the
213 // system foreground queue. Thus we lose our right to recapture the foreground window.
214 // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY
215 // handler for the progress window in the progress thread.
217 // To do that, we Subclass the progress dialog
218 // Since the window and thread created by the progress dialog object live on a few
219 // milliseconds after calling Stop() and Release(), we must not store anything
220 // in member variables of this class but must only store everything in the window
221 // itself: thus we use SetProp()/GetProp() to store the data.
222 if (!m_isVisible)
224 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
225 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
226 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
228 if(immediately)
229 ShowWindow(m_hWndProgDlg, SW_SHOW);
233 m_isVisible = true;
234 return hr;
237 HRESULT CSysProgressDlg::ShowModeless(HWND hWndParent, BOOL immediately)
239 EnsureValid();
240 m_hWndProgDlg = NULL;
241 if (!IsValid())
242 return E_FAIL;
243 m_hWndParent = hWndParent;
244 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags, NULL);
245 if(FAILED(hr))
246 return hr;
248 ATL::CComPtr<IOleWindow> pOleWindow;
249 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
250 if(SUCCEEDED(hr2))
252 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
253 if(SUCCEEDED(hr2))
255 // see comment in ShowModal() for why we subclass the window
256 if (!m_isVisible)
258 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
259 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
260 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
262 if (immediately)
263 ShowWindow(m_hWndProgDlg, SW_SHOW);
266 m_isVisible = true;
267 return hr;
270 void CSysProgressDlg::SetProgress(DWORD dwProgress, DWORD dwMax)
272 if (IsValid())
274 m_pIDlg->SetProgress(dwProgress, dwMax);
278 void CSysProgressDlg::SetProgress64(ULONGLONG u64Progress, ULONGLONG u64ProgressMax)
280 if (IsValid())
282 m_pIDlg->SetProgress64(u64Progress, u64ProgressMax);
286 bool CSysProgressDlg::HasUserCancelled()
288 if (!IsValid())
289 return false;
291 return (0 != m_pIDlg->HasUserCancelled());
294 void CSysProgressDlg::Stop()
296 if ((m_isVisible)&&(IsValid()))
298 m_pIDlg->StopProgressDialog();
299 // Sometimes the progress dialog sticks around after stopping it,
300 // until the mouse pointer is moved over it or some other triggers.
301 // We hide the window here immediately.
302 if (m_hWndProgDlg)
304 ShowWindow(m_hWndProgDlg, SW_HIDE);
306 m_isVisible = false;
307 m_pIDlg.Release();
309 m_hWndProgDlg = NULL;
313 void CSysProgressDlg::ResetTimer()
315 if (IsValid())
317 m_pIDlg->Timer(PDTIMER_RESET, NULL);
321 LRESULT CSysProgressDlg::fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
323 LONG_PTR origproc = (LONG_PTR)GetProp(hwnd, L"OrigProc");
324 if (uMsg == WM_DESTROY)
326 HWND hParent = (HWND)GetProp(hwnd, L"ParentWindow");
327 EnableWindow(hParent, TRUE);
328 SetFocus(hParent);
329 SetWindowLongPtr (hwnd, GWLP_WNDPROC, origproc);
330 RemoveProp(hwnd, L"ParentWindow");
331 RemoveProp(hwnd, L"OrigProc");
333 return CallWindowProc ((WNDPROC)origproc, hwnd, uMsg, wParam, lParam);