Correctly expand variables
[TortoiseGit.git] / src / Utils / MiscUI / SysProgressDlg.cpp
blob59c85c33bca7585e786c7b580ef33efa567c667f
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 #endif
174 HRESULT CSysProgressDlg::ShowModal(HWND hWndParent, BOOL immediately /* = true */)
176 EnsureValid();
177 m_hWndProgDlg = NULL;
178 if (!IsValid())
179 return E_FAIL;
180 m_hWndParent = hWndParent;
181 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags | PROGDLG_MODAL, NULL);
182 if(FAILED(hr))
183 return hr;
185 ATL::CComPtr<IOleWindow> pOleWindow;
186 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
187 if(SUCCEEDED(hr2))
189 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
190 if(SUCCEEDED(hr2))
192 // StartProgressDialog creates a new thread to host the progress window.
193 // When the window receives WM_DESTROY message StopProgressDialog() wrongly
194 // attempts to re-enable the parent in the calling thread (our thread),
195 // after the progress window is destroyed and the progress thread has died.
196 // When the progress window dies, the system tries to assign a new foreground window.
197 // It cannot assign to hwndParent because StartProgressDialog (w/PROGDLG_MODAL) disabled the parent window.
198 // So the system hands the foreground activation to the next process that wants it in the
199 // system foreground queue. Thus we lose our right to recapture the foreground window.
200 // The way to fix this bug is to insert a call to EnableWindow(hWndParent) in the WM_DESTROY
201 // handler for the progress window in the progress thread.
203 // To do that, we Subclass the progress dialog
204 // Since the window and thread created by the progress dialog object live on a few
205 // milliseconds after calling Stop() and Release(), we must not store anything
206 // in member variables of this class but must only store everything in the window
207 // itself: thus we use SetProp()/GetProp() to store the data.
208 if (!m_isVisible)
210 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
211 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
212 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
214 if(immediately)
215 ShowWindow(m_hWndProgDlg, SW_SHOW);
219 m_isVisible = true;
220 return hr;
223 HRESULT CSysProgressDlg::ShowModeless(HWND hWndParent, BOOL immediately)
225 EnsureValid();
226 m_hWndProgDlg = NULL;
227 if (!IsValid())
228 return E_FAIL;
229 m_hWndParent = hWndParent;
230 HRESULT hr = m_pIDlg->StartProgressDialog(hWndParent, NULL, m_dwDlgFlags, NULL);
231 if(FAILED(hr))
232 return hr;
234 ATL::CComPtr<IOleWindow> pOleWindow;
235 HRESULT hr2 = m_pIDlg.QueryInterface(&pOleWindow);
236 if(SUCCEEDED(hr2))
238 hr2 = pOleWindow->GetWindow(&m_hWndProgDlg);
239 if(SUCCEEDED(hr2))
241 // see comment in ShowModal() for why we subclass the window
242 if (!m_isVisible)
244 m_OrigProc = (WNDPROC) SetWindowLongPtr(m_hWndProgDlg, GWLP_WNDPROC, (LONG_PTR) fnSubclass);
245 SetProp(m_hWndProgDlg, L"ParentWindow", m_hWndParent);
246 SetProp(m_hWndProgDlg, L"OrigProc", m_OrigProc);
248 if (immediately)
249 ShowWindow(m_hWndProgDlg, SW_SHOW);
252 m_isVisible = true;
253 return hr;
256 void CSysProgressDlg::SetProgress(DWORD dwProgress, DWORD dwMax)
258 if (IsValid())
260 m_pIDlg->SetProgress(dwProgress, dwMax);
264 void CSysProgressDlg::SetProgress64(ULONGLONG u64Progress, ULONGLONG u64ProgressMax)
266 if (IsValid())
268 m_pIDlg->SetProgress64(u64Progress, u64ProgressMax);
272 bool CSysProgressDlg::HasUserCancelled()
274 if (!IsValid())
275 return false;
277 return (0 != m_pIDlg->HasUserCancelled());
280 void CSysProgressDlg::Stop()
282 if ((m_isVisible)&&(IsValid()))
284 m_pIDlg->StopProgressDialog();
285 // Sometimes the progress dialog sticks around after stopping it,
286 // until the mouse pointer is moved over it or some other triggers.
287 // We hide the window here immediately.
288 if (m_hWndProgDlg)
290 ShowWindow(m_hWndProgDlg, SW_HIDE);
292 m_isVisible = false;
293 m_pIDlg.Release();
295 m_hWndProgDlg = NULL;
299 void CSysProgressDlg::ResetTimer()
301 if (IsValid())
303 m_pIDlg->Timer(PDTIMER_RESET, NULL);
307 LRESULT CSysProgressDlg::fnSubclass(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
309 LONG_PTR origproc = (LONG_PTR)GetProp(hwnd, L"OrigProc");
310 if (uMsg == WM_DESTROY)
312 HWND hParent = (HWND)GetProp(hwnd, L"ParentWindow");
313 EnableWindow(hParent, TRUE);
314 SetFocus(hParent);
315 SetWindowLongPtr (hwnd, GWLP_WNDPROC, origproc);
316 RemoveProp(hwnd, L"ParentWindow");
317 RemoveProp(hwnd, L"OrigProc");
319 return CallWindowProc ((WNDPROC)origproc, hwnd, uMsg, wParam, lParam);