1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - TortoiseGit
4 // Copyright (C) 2003-2008 - 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.
21 #include "TortoiseProc.h"
22 #include "messagebox.h"
23 #include "GITProgressDlg.h"
27 #include "GitStatus.h"
29 #include "PathUtils.h"
30 #include "StringUtils.h"
32 #include "UnicodeUtils.h"
33 #include "SoundUtils.h"
36 #include "DropFiles.h"
37 //#include "GitLogHelper.h"
38 #include "RegHistory.h"
39 //#include "ConflictResolveDlg.h"
41 #include "ShellUpdater.h"
43 #include "BugTraqAssociations.h"
45 #include "MassiveGitTask.h"
46 #include "SmartHandle.h"
49 IMPLEMENT_DYNAMIC(CGitProgressDlg
, CResizableStandAloneDialog
)
50 CGitProgressDlg::CGitProgressDlg(CWnd
* pParent
/*=NULL*/)
51 : CResizableStandAloneDialog(CGitProgressDlg::IDD
, pParent
)
54 , m_Revision(_T("HEAD"))
56 , m_bLockWarning(false)
57 , m_bLockExists(false)
58 , m_bThreadRunning(FALSE
)
60 , m_bMergesAddsDeletesOccurred(FALSE
)
61 , m_dwCloseOnEnd((DWORD
)-1)
62 , m_bFinishedItemAdded(false)
63 , m_bLastVisible(false)
64 // , m_depth(svn_depth_unknown)
66 , m_itemCountTotal(-1)
67 , m_AlwaysConflicted(false)
68 , m_BugTraqProvider(NULL
)
69 , sDryRun(MAKEINTRESOURCE(IDS_PROGRS_DRYRUN
))
70 , sRecordOnly(MAKEINTRESOURCE(IDS_MERGE_RECORDONLY
))
75 CGitProgressDlg::~CGitProgressDlg()
79 void CGitProgressDlg::DoDataExchange(CDataExchange
* pDX
)
81 CResizableStandAloneDialog::DoDataExchange(pDX
);
82 DDX_Control(pDX
, IDC_SVNPROGRESS
, m_ProgList
);
83 DDX_Control(pDX
, IDC_TITLE_ANIMATE
, m_Animate
);
84 DDX_Control(pDX
, IDC_PROGRESSBAR
, m_ProgCtrl
);
85 DDX_Control(pDX
, IDC_INFOTEXT
, m_InfoCtrl
);
86 DDX_Control(pDX
, IDC_PROGRESSLABEL
, m_ProgLableCtrl
);
89 BEGIN_MESSAGE_MAP(CGitProgressDlg
, CResizableStandAloneDialog
)
90 ON_BN_CLICKED(IDC_LOGBUTTON
, OnBnClickedLogbutton
)
93 ON_EN_SETFOCUS(IDC_INFOTEXT
, &CGitProgressDlg::OnEnSetfocusInfotext
)
94 ON_BN_CLICKED(IDC_NONINTERACTIVE
, &CGitProgressDlg::OnBnClickedNoninteractive
)
96 ON_MESSAGE(WM_PROG_CMD_FINISH
, OnCmdEnd
)
97 ON_MESSAGE(WM_PROG_CMD_START
, OnCmdStart
)
98 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED
, OnTaskbarBtnCreated
)
103 BOOL
CGitProgressDlg::OnInitDialog()
105 __super::OnInitDialog();
107 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
108 // do this, Explorer would be unable to send that message to our window if we
109 // were running elevated. It's OK to make the call all the time, since if we're
110 // not elevated, this is a no-op.
111 CHANGEFILTERSTRUCT cfs
= { sizeof(CHANGEFILTERSTRUCT
) };
112 typedef BOOL STDAPICALLTYPE
ChangeWindowMessageFilterExDFN(HWND hWnd
, UINT message
, DWORD action
, PCHANGEFILTERSTRUCT pChangeFilterStruct
);
113 CAutoLibrary hUser
= AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
116 ChangeWindowMessageFilterExDFN
*pfnChangeWindowMessageFilterEx
= (ChangeWindowMessageFilterExDFN
*)GetProcAddress(hUser
, "ChangeWindowMessageFilterEx");
117 if (pfnChangeWindowMessageFilterEx
)
119 pfnChangeWindowMessageFilterEx(m_hWnd
, WM_TASKBARBTNCREATED
, MSGFLT_ALLOW
, &cfs
);
122 m_ProgList
.m_pTaskbarList
.Release();
123 if (FAILED(m_ProgList
.m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
124 m_ProgList
.m_pTaskbarList
= nullptr;
128 AddAnchor(IDC_SVNPROGRESS
, TOP_LEFT
, BOTTOM_RIGHT
);
129 AddAnchor(IDC_TITLE_ANIMATE
, TOP_LEFT
, BOTTOM_RIGHT
);
130 AddAnchor(IDC_PROGRESSLABEL
, BOTTOM_LEFT
, BOTTOM_CENTER
);
131 AddAnchor(IDC_PROGRESSBAR
, BOTTOM_CENTER
, BOTTOM_RIGHT
);
132 AddAnchor(IDC_INFOTEXT
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
133 AddAnchor(IDC_NONINTERACTIVE
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
134 AddAnchor(IDCANCEL
, BOTTOM_RIGHT
);
135 AddAnchor(IDOK
, BOTTOM_RIGHT
);
136 AddAnchor(IDC_LOGBUTTON
, BOTTOM_RIGHT
);
137 //SetPromptParentWindow(this->m_hWnd);
139 m_Animate
.Open(IDR_DOWNLOAD
);
140 m_ProgList
.m_pAnimate
= &m_Animate
;
141 m_ProgList
.m_pProgControl
= &m_ProgCtrl
;
142 m_ProgList
.m_pProgressLabelCtrl
= &m_ProgLableCtrl
;
143 m_ProgList
.m_pInfoCtrl
= &m_InfoCtrl
;
144 m_ProgList
.m_pPostWnd
= this;
145 m_ProgList
.m_bSetTitle
= true;
148 CenterWindow(CWnd::FromHandle(hWndExplorer
));
149 EnableSaveRestore(_T("GITProgressDlg"));
151 m_background_brush
.CreateSolidBrush(GetSysColor(COLOR_WINDOW
));
157 LRESULT
CGitProgressDlg::OnTaskbarBtnCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
159 m_ProgList
.m_pTaskbarList
.Release();
160 m_ProgList
.m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
);
161 SetUUIDOverlayIcon(m_hWnd
);
165 void CGitProgressDlg::OnBnClickedLogbutton()
167 switch(m_ProgList
.m_Command
)
169 case CGitProgressList::GitProgress_Add
:
170 case CGitProgressList::GitProgress_Resolve
:
172 CString cmd
= _T(" /command:commit");
173 cmd
+= _T(" /path:\"")+g_Git
.m_CurrentDir
+_T("\"");
175 CAppUtils::RunTortoiseGitProc(cmd
);
176 this->EndDialog(IDOK
);
181 if (m_targetPathList
.GetCount() != 1)
183 StringRevMap::iterator it
= m_UpdateStartRevMap
.begin();
184 svn_revnum_t rev
= -1;
185 if (it
!= m_UpdateStartRevMap
.end())
190 dlg
.SetParams(m_targetPathList
[0], m_RevisionEnd
, m_RevisionEnd
, rev
, 0, TRUE
);
196 void CGitProgressDlg::OnClose()
198 DialogEnableWindow(IDCANCEL
, TRUE
);
202 void CGitProgressDlg::OnOK()
204 if ((m_ProgList
.IsCancelled())&&(!m_ProgList
.IsRunning()))
206 // I have made this wait a sensible amount of time (10 seconds) for the thread to finish
207 // You must be careful in the thread that after posting the WM_COMMAND/IDOK message, you
208 // don't do any more operations on the window which might require message passing
209 // If you try to send windows messages once we're waiting here, then the thread can't finished
210 // because the Window's message loop is blocked at this wait
211 WaitForSingleObject(m_ProgList
.m_pThread
->m_hThread
, 10000);
217 void CGitProgressDlg::OnCancel()
219 if ((m_ProgList
.IsCancelled())&&(!m_ProgList
.IsRunning()))
225 BOOL
CGitProgressDlg::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
227 if (!GetDlgItem(IDOK
)->IsWindowEnabled())
229 // only show the wait cursor over the list control
230 if ((pWnd
)&&(pWnd
== GetDlgItem(IDC_SVNPROGRESS
)))
232 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_WAIT
));
237 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_ARROW
));
239 return CResizableStandAloneDialog::OnSetCursor(pWnd
, nHitTest
, message
);
242 BOOL
CGitProgressDlg::PreTranslateMessage(MSG
* pMsg
)
244 if (pMsg
->message
== WM_KEYDOWN
)
246 if (pMsg
->wParam
== VK_ESCAPE
)
248 // pressing the ESC key should close the dialog. But since we disabled the escape
249 // key (so the user doesn't get the idea that he could simply undo an e.g. update)
251 // So if the user presses the ESC key, change it to VK_RETURN so the dialog gets
252 // the impression that the OK button was pressed.
253 if ((!m_ProgList
.IsRunning())&&(!GetDlgItem(IDCANCEL
)->IsWindowEnabled())
254 &&(GetDlgItem(IDOK
)->IsWindowEnabled())&&(GetDlgItem(IDOK
)->IsWindowVisible()))
256 // since we convert ESC to RETURN, make sure the OK button has the focus.
257 GetDlgItem(IDOK
)->SetFocus();
258 pMsg
->wParam
= VK_RETURN
;
262 return __super::PreTranslateMessage(pMsg
);
267 void CGitProgressDlg::OnEnSetfocusInfotext()
270 GetDlgItemText(IDC_INFOTEXT
, sTemp
);
272 GetDlgItem(IDC_INFOTEXT
)->HideCaret();
276 void CGitProgressDlg::OnBnClickedNoninteractive()
278 LRESULT res
= ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE
)->GetSafeHwnd(), BM_GETCHECK
, 0, 0);
279 m_ProgList
.m_AlwaysConflicted
= (res
== BST_CHECKED
);
280 CRegDWORD nonint
= CRegDWORD(_T("Software\\TortoiseGit\\MergeNonInteractive"), FALSE
);
281 nonint
= m_ProgList
.m_AlwaysConflicted
;
284 LRESULT
CGitProgressDlg::OnCtlColorStatic(WPARAM wParam
, LPARAM lParam
)
286 HDC hDC
= (HDC
)wParam
;
287 HWND hwndCtl
= (HWND
)lParam
;
289 if (::GetDlgCtrlID(hwndCtl
) == IDC_TITLE_ANIMATE
)
291 CDC
*pDC
= CDC::FromHandle(hDC
);
292 pDC
->SetBkColor(GetSysColor(COLOR_WINDOW
));
293 pDC
->SetBkMode(TRANSPARENT
);
294 return (LRESULT
)(HBRUSH
)m_background_brush
.GetSafeHandle();
299 HBRUSH
CGitProgressDlg::OnCtlColor(CDC
* pDC
, CWnd
* pWnd
, UINT nCtlColor
)
302 if (pWnd
->GetDlgCtrlID() == IDC_TITLE_ANIMATE
)
304 pDC
->SetBkColor(GetSysColor(COLOR_WINDOW
)); // add this
305 pDC
->SetBkMode(TRANSPARENT
);
306 return (HBRUSH
)m_background_brush
.GetSafeHandle();
309 hbr
= CResizableStandAloneDialog::OnCtlColor(pDC
, pWnd
, nCtlColor
);
311 // TODO: Return a different brush if the default is not desired
315 LRESULT
CGitProgressDlg::OnCmdEnd(WPARAM wParam
, LPARAM
/*lParam*/)
317 DialogEnableWindow(IDCANCEL
, FALSE
);
318 DialogEnableWindow(IDOK
, TRUE
);
322 case CGitProgressList::GitProgress_Add
:
323 case CGitProgressList::GitProgress_Revert
:
324 this->GetDlgItem(IDC_LOGBUTTON
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_COMMITBUTTON
)));
325 this->GetDlgItem(IDC_LOGBUTTON
)->ShowWindow(SW_SHOW
);
329 CWnd
* pWndOk
= GetDlgItem(IDOK
);
330 if (pWndOk
&& ::IsWindow(pWndOk
->GetSafeHwnd()))
332 SendMessage(DM_SETDEFID
, IDOK
);
333 GetDlgItem(IDOK
)->SetFocus();
338 LRESULT
CGitProgressDlg::OnCmdStart(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
340 DialogEnableWindow(IDOK
, FALSE
);
341 DialogEnableWindow(IDCANCEL
, TRUE
);