Add retry button when fetch failed
[TortoiseGit.git] / src / TortoiseProc / SyncDlg.cpp
blob65c4ffe181c62acd2a5bd366c9ef08f54a042a65
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // SyncDlg.cpp : implementation file
23 #include "stdafx.h"
24 #include "TortoiseProc.h"
25 #include "SyncDlg.h"
26 #include "AppUtils.h"
27 #include "progressdlg.h"
28 #include "MessageBox.h"
29 #include "ImportPatchDlg.h"
30 #include "RebaseDlg.h"
31 #include "hooks.h"
32 #include "SmartHandle.h"
33 #include "SoundUtils.h"
35 // CSyncDlg dialog
37 IMPLEMENT_DYNAMIC(CSyncDlg, CResizableStandAloneDialog)
39 CSyncDlg::CSyncDlg(CWnd* pParent /*=NULL*/)
40 : CResizableStandAloneDialog(CSyncDlg::IDD, pParent)
42 m_CurrentCmd = 0;
43 m_pTooltip=&this->m_tooltips;
44 m_bInited=false;
45 m_CmdOutCurrentPos=0;
46 m_bAutoLoadPuttyKey = CAppUtils::IsSSHPutty();
47 m_bForce=false;
48 m_Gitverion = 0;
49 m_bBlock = false;
50 m_BufStart = 0;
51 m_pThread = NULL;
52 m_bAbort = false;
53 m_bDone = false;
54 m_bWantToExit = false;
55 m_GitCmdStatus = -1;
56 m_startTick = GetTickCount();
57 m_seq = 0;
60 CSyncDlg::~CSyncDlg()
64 void CSyncDlg::DoDataExchange(CDataExchange* pDX)
66 CDialog::DoDataExchange(pDX);
67 DDX_Check(pDX, IDC_CHECK_PUTTY_KEY, m_bAutoLoadPuttyKey);
68 DDX_Check(pDX, IDC_CHECK_FORCE,m_bForce);
69 DDX_Control(pDX, IDC_COMBOBOXEX_URL, m_ctrlURL);
70 DDX_Control(pDX, IDC_BUTTON_TABCTRL, m_ctrlDumyButton);
71 DDX_Control(pDX, IDC_BUTTON_PULL, m_ctrlPull);
72 DDX_Control(pDX, IDC_BUTTON_PUSH, m_ctrlPush);
73 DDX_Control(pDX, IDC_STATIC_STATUS, m_ctrlStatus);
74 DDX_Control(pDX, IDC_PROGRESS_SYNC, m_ctrlProgress);
75 DDX_Control(pDX, IDC_ANIMATE_SYNC, m_ctrlAnimate);
76 DDX_Control(pDX, IDC_BUTTON_SUBMODULE,m_ctrlSubmodule);
77 DDX_Control(pDX, IDC_BUTTON_STASH, m_ctrlStash);
78 DDX_Control(pDX, IDC_PROG_LABEL, m_ctrlProgLabel);
79 BRANCH_COMBOX_DDX;
83 BEGIN_MESSAGE_MAP(CSyncDlg, CResizableStandAloneDialog)
84 ON_BN_CLICKED(IDC_BUTTON_PULL, &CSyncDlg::OnBnClickedButtonPull)
85 ON_BN_CLICKED(IDC_BUTTON_PUSH, &CSyncDlg::OnBnClickedButtonPush)
86 ON_BN_CLICKED(IDC_BUTTON_APPLY, &CSyncDlg::OnBnClickedButtonApply)
87 ON_BN_CLICKED(IDC_BUTTON_EMAIL, &CSyncDlg::OnBnClickedButtonEmail)
88 ON_BN_CLICKED(IDC_BUTTON_MANAGE, &CSyncDlg::OnBnClickedButtonManage)
89 BRANCH_COMBOX_EVENT
90 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_URL, &CSyncDlg::OnCbnEditchangeComboboxex)
91 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_REMOTE_BRANCH, &CSyncDlg::OnCbnEditchangeComboboxex)
92 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
93 ON_MESSAGE(WM_PROG_CMD_FINISH, OnProgCmdFinish)
94 ON_NOTIFY(LVN_COLUMNCLICK, IDC_IN_LOGLIST, OnLvnInLogListColumnClick)
95 ON_BN_CLICKED(IDC_BUTTON_COMMIT, &CSyncDlg::OnBnClickedButtonCommit)
96 ON_BN_CLICKED(IDC_BUTTON_SUBMODULE, &CSyncDlg::OnBnClickedButtonSubmodule)
97 ON_BN_CLICKED(IDC_BUTTON_STASH, &CSyncDlg::OnBnClickedButtonStash)
98 ON_WM_TIMER()
99 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
100 ON_BN_CLICKED(IDC_CHECK_FORCE, &CSyncDlg::OnBnClickedCheckForce)
101 ON_BN_CLICKED(IDC_LOG, &CSyncDlg::OnBnClickedLog)
102 ON_WM_DESTROY()
103 END_MESSAGE_MAP()
106 void CSyncDlg::EnableControlButton(bool bEnabled)
108 GetDlgItem(IDC_BUTTON_PULL)->EnableWindow(bEnabled);
109 GetDlgItem(IDC_BUTTON_PUSH)->EnableWindow(bEnabled);
110 GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(bEnabled);
111 GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(bEnabled);
112 GetDlgItem(IDOK)->EnableWindow(bEnabled);
113 GetDlgItem(IDC_BUTTON_SUBMODULE)->EnableWindow(bEnabled);
114 GetDlgItem(IDC_BUTTON_STASH)->EnableWindow(bEnabled);
116 // CSyncDlg message handlers
118 void CSyncDlg::OnBnClickedButtonPull()
120 int CurrentEntry;
121 CurrentEntry = (int)this->m_ctrlPull.GetCurrentEntry();
122 this->m_regPullButton = CurrentEntry;
124 this->m_bAbort=false;
125 this->m_GitCmdList.clear();
126 m_ctrlCmdOut.SetWindowTextW(_T(""));
127 m_LogText = "";
129 this->UpdateData();
130 UpdateCombox();
132 if (g_Git.GetHash(m_oldHash, _T("HEAD")))
134 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR);
135 return;
138 m_refList.Clear();
139 m_newHashMap.clear();
140 m_oldHashMap.clear();
142 if( CurrentEntry == 0)
144 CGitHash localBranchHash;
145 if (g_Git.GetHash(localBranchHash, m_strLocalBranch))
147 MessageBox(g_Git.GetGitLastErr(_T("Could not get hash of \"") + m_strLocalBranch + _T("\".")), _T("TortoiseGit"), MB_ICONERROR);
148 return;
150 if (localBranchHash != m_oldHash)
152 CMessageBox::Show(NULL, IDS_PROC_SYNC_PULLWRONGBRANCH, IDS_APPNAME, MB_OK | MB_ICONERROR);
153 return;
157 if(this->m_strURL.IsEmpty())
159 CMessageBox::Show(NULL, IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
160 return;
163 if (m_bAutoLoadPuttyKey && CurrentEntry != 3) // CurrentEntry (Remote Update) handles this on its own)
165 CAppUtils::LaunchPAgent(NULL,&this->m_strURL);
168 this->SwitchToRun();
169 if (g_Git.GetMapHashToFriendName(m_oldHashMap))
170 MessageBox(g_Git.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
172 CString force;
173 if(this->m_bForce)
174 force = _T(" --force ");
176 CString cmd;
178 ShowTab(IDC_CMD_LOG);
180 this->m_ctrlTabCtrl.ShowTab(IDC_REFLIST-1,true);
181 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,false);
182 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
183 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT-1,false);
185 ///Pull
186 if(CurrentEntry == 0) //Pull
188 CString remotebranch;
189 remotebranch = m_strRemoteBranch;
191 if(!IsURL())
193 CString pullRemote, pullBranch;
194 g_Git.GetRemoteTrackedBranch(m_strLocalBranch, pullRemote, pullBranch);
195 if(pullBranch == remotebranch && pullRemote == this->m_strURL)
196 remotebranch.Empty();
199 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
200 force += _T("--progress ");
202 cmd.Format(_T("git.exe pull -v %s \"%s\" %s"),
203 force,
204 m_strURL,
205 remotebranch);
207 m_CurrentCmd = GIT_COMMAND_PULL;
208 m_GitCmdList.push_back(cmd);
210 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
211 if (m_pThread==NULL)
213 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
215 else
217 m_pThread->m_bAutoDelete = TRUE;
218 m_pThread->ResumeThread();
223 ///Fetch
224 if(CurrentEntry == 1 || CurrentEntry ==2 ) //Fetch
226 CString remotebranch;
227 if(this->IsURL() || m_strRemoteBranch.IsEmpty())
229 remotebranch=this->m_strRemoteBranch;
232 else
234 remotebranch.Format(_T("remotes/%s/%s"),
235 m_strURL,m_strRemoteBranch);
236 CGitHash remoteBranchHash;
237 g_Git.GetHash(remoteBranchHash, remotebranch);
238 if (remoteBranchHash.IsEmpty())
239 remotebranch=m_strRemoteBranch;
240 else
241 remotebranch=m_strRemoteBranch+_T(":")+remotebranch;
244 if(CurrentEntry == 1)
245 m_CurrentCmd = GIT_COMMAND_FETCH;
246 else
247 m_CurrentCmd = GIT_COMMAND_FETCHANDREBASE;
249 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
251 CString refspec;
252 // current libgit2 only supports well formated refspec
253 refspec.Format(_T("refs/heads/%s:refs/remotes/%s/%s"), m_strRemoteBranch, m_strURL, m_strRemoteBranch);
254 m_GitProgressList.SetUrl(m_strURL);
255 m_GitProgressList.SetRefSpec(refspec);
256 m_GitProgressList.SetCommand(CGitProgressList::GitProgress_Fetch);
257 m_GitProgressList.Init();
258 ShowTab(IDC_CMD_GIT_PROG);
260 else
262 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
263 force += _T("--progress ");
265 cmd.Format(_T("git.exe fetch -v %s \"%s\" %s"),
266 force,
267 m_strURL,
268 remotebranch);
270 m_GitCmdList.push_back(cmd);
272 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
273 if (m_pThread==NULL)
275 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
277 else
279 m_pThread->m_bAutoDelete = TRUE;
280 m_pThread->ResumeThread();
285 ///Remote Update
286 if(CurrentEntry == 3)
288 if (m_bAutoLoadPuttyKey)
290 STRING_VECTOR list;
291 if (!g_Git.GetRemoteList(list))
293 for (size_t i = 0; i < list.size(); ++i)
294 CAppUtils::LaunchPAgent(NULL, &list[i]);
298 m_CurrentCmd = GIT_COMMAND_REMOTE;
299 cmd=_T("git.exe remote update");
300 m_GitCmdList.push_back(cmd);
302 InterlockedExchange(&m_bBlock, TRUE);
304 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
305 if (m_pThread==NULL)
307 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
308 InterlockedExchange(&m_bBlock, FALSE);
310 else
312 m_pThread->m_bAutoDelete = TRUE;
313 m_pThread->ResumeThread();
317 ///Cleanup stale remote banches
318 if(CurrentEntry == 4)
320 m_CurrentCmd = GIT_COMMAND_REMOTE;
321 cmd.Format(_T("git.exe remote prune \"%s\""), m_strURL);
322 m_GitCmdList.push_back(cmd);
324 InterlockedExchange(&m_bBlock, TRUE);
326 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
327 if (m_pThread==NULL)
329 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
330 InterlockedExchange(&m_bBlock, FALSE);
332 else
334 m_pThread->m_bAutoDelete = TRUE;
335 m_pThread->ResumeThread();
340 void CSyncDlg::PullComplete()
342 EnableControlButton(true);
343 SwitchToInput();
344 this->FetchOutList(true);
346 CGitHash newhash;
347 if (g_Git.GetHash(newhash, _T("HEAD")))
348 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash after pulling.")), _T("TortoiseGit"), MB_ICONERROR);
350 if( this ->m_GitCmdStatus )
352 CTGitPathList list;
353 if(g_Git.ListConflictFile(list))
355 this->m_ctrlCmdOut.SetSel(-1,-1);
356 this->m_ctrlCmdOut.ReplaceSel(_T("Get conflict files fail\n"));
358 this->ShowTab(IDC_CMD_LOG);
359 return;
362 if (!list.IsEmpty())
364 this->m_ConflictFileList.Clear();
365 CTGitPathList list;
366 CTGitPath path;
367 list.AddPath(path);
369 this->m_ConflictFileList.GetStatus(&list,true);
370 this->m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED,
371 CTGitPath::LOGACTIONS_UNMERGED);
373 this->ShowTab(IDC_IN_CONFLICT);
375 else
376 this->ShowTab(IDC_CMD_LOG);
379 else
381 if(newhash == this->m_oldHash)
383 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
384 this->m_InLogList.ShowText(CString(MAKEINTRESOURCE(IDS_UPTODATE)));
385 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
386 this->ShowTab(IDC_REFLIST);
388 else
390 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,true);
391 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
393 this->AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newhash.ToString(), m_oldHash.ToString());
395 CString range;
396 range.Format(_T("%s..%s"), m_oldHash.ToString(), newhash.ToString());
397 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
398 this->ShowTab(IDC_IN_LOGLIST);
403 void CSyncDlg::FetchComplete()
405 EnableControlButton(true);
406 SwitchToInput();
407 this->FetchOutList(true);
409 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
410 ShowTab(IDC_CMD_GIT_PROG);
411 else
412 ShowTab(IDC_REFLIST);
413 if( (!this->m_GitCmdStatus) && this->m_CurrentCmd == GIT_COMMAND_FETCHANDREBASE)
415 CRebaseDlg dlg;
416 CString remote, remotebranch;
417 m_ctrlURL.GetWindowText(remote);
418 if (!remote.IsEmpty())
420 STRING_VECTOR remotes;
421 g_Git.GetRemoteList(remotes);
422 if (std::find(remotes.begin(), remotes.end(), remote) == remotes.end())
423 remote.Empty();
425 m_ctrlRemoteBranch.GetWindowText(remotebranch);
426 if (!remote.IsEmpty() && !remotebranch.IsEmpty())
427 dlg.m_Upstream = _T("remotes/") + remote + _T("/") + remotebranch;
428 dlg.m_PostButtonTexts.Add(CString(MAKEINTRESOURCE(IDS_MENULOG)));
429 dlg.m_PostButtonTexts.Add(_T("Email &Patch..."));
430 INT_PTR response = dlg.DoModal();
431 if(response == IDOK)
433 return ;
436 if (response == IDC_REBASE_POST_BUTTON)
438 CString cmd = _T("/command:log");
439 cmd += _T(" /path:\"") + g_Git.m_CurrentDir + _T("\"");
440 CAppUtils::RunTortoiseGitProc(cmd);
442 if(response == IDC_REBASE_POST_BUTTON + 1)
444 CString cmd, out, err;
445 cmd.Format(_T("git.exe format-patch -o \"%s\" %s..%s"),
446 g_Git.m_CurrentDir,
447 g_Git.FixBranchName(dlg.m_Upstream),
448 g_Git.FixBranchName(dlg.m_Branch));
449 if (g_Git.Run(cmd, &out, &err, CP_UTF8))
451 CMessageBox::Show(NULL, out + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
452 return ;
455 CAppUtils::SendPatchMail(cmd,out);
460 void CSyncDlg::StashComplete()
462 EnableControlButton(true);
463 INT_PTR entry = m_ctrlStash.GetCurrentEntry();
464 if (entry != 1 && entry != 2)
465 return;
467 SwitchToInput();
468 if (m_GitCmdStatus)
470 CTGitPathList list;
471 if (g_Git.ListConflictFile(list))
473 m_ctrlCmdOut.SetSel(-1, -1);
474 m_ctrlCmdOut.ReplaceSel(_T("Get conflict files fail\n"));
476 ShowTab(IDC_CMD_LOG);
477 return;
480 if (!list.IsEmpty())
482 m_ConflictFileList.Clear();
483 CTGitPathList list;
484 CTGitPath path;
485 list.AddPath(path);
487 m_ConflictFileList.GetStatus(&list,true);
488 m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED, CTGitPath::LOGACTIONS_UNMERGED);
490 ShowTab(IDC_IN_CONFLICT);
492 else
493 ShowTab(IDC_CMD_LOG);
497 void CSyncDlg::OnBnClickedButtonPush()
499 this->UpdateData();
500 UpdateCombox();
501 m_ctrlCmdOut.SetWindowTextW(_T(""));
502 m_LogText = "";
504 if(this->m_strURL.IsEmpty())
506 CMessageBox::Show(NULL, IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
507 return;
510 this->m_regPushButton=(DWORD)this->m_ctrlPush.GetCurrentEntry();
511 this->SwitchToRun();
512 this->m_bAbort=false;
513 this->m_GitCmdList.clear();
515 ShowTab(IDC_CMD_LOG);
517 CString cmd;
518 CString arg;
520 CString error;
521 DWORD exitcode = 0xFFFFFFFF;
522 if (CHooks::Instance().PrePush(g_Git.m_CurrentDir, exitcode, error))
524 if (exitcode)
526 CString temp;
527 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
528 CMessageBox::Show(NULL,temp,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
529 return ;
533 CString refName = g_Git.FixBranchName(m_strLocalBranch);
534 switch (m_ctrlPush.GetCurrentEntry())
536 case 1:
537 arg += _T(" --tags ");
538 break;
539 case 2:
540 refName = _T("refs/notes/commits"); //default ref for notes
541 break;
544 if(this->m_bForce)
545 arg += _T(" --force ");
547 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
548 arg += _T("--progress ");
550 cmd.Format(_T("git.exe push -v %s \"%s\" %s"),
551 arg,
552 m_strURL,
553 refName);
555 if (!m_strRemoteBranch.IsEmpty() && m_ctrlPush.GetCurrentEntry() != 2)
557 cmd += _T(":") + m_strRemoteBranch;
560 m_GitCmdList.push_back(cmd);
562 m_CurrentCmd = GIT_COMMAND_PUSH;
564 if(this->m_bAutoLoadPuttyKey)
566 CAppUtils::LaunchPAgent(NULL,&this->m_strURL);
569 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
570 if (m_pThread==NULL)
572 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
574 else
576 m_pThread->m_bAutoDelete = TRUE;
577 m_pThread->ResumeThread();
581 void CSyncDlg::OnBnClickedButtonApply()
583 CGitHash oldhash;
584 if (g_Git.GetHash(oldhash, _T("HEAD")))
586 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR);
587 return;
590 CImportPatchDlg dlg;
591 CString cmd,output;
593 if(dlg.DoModal() == IDOK)
595 int err=0;
596 for (int i = 0; i < dlg.m_PathList.GetCount(); ++i)
598 cmd.Format(_T("git.exe am \"%s\""),dlg.m_PathList[i].GetGitPathString());
600 if (g_Git.Run(cmd, &output, CP_UTF8))
602 CMessageBox::Show(NULL,output,_T("TortoiseGit"),MB_OK);
604 err=1;
605 break;
607 this->m_ctrlCmdOut.SetSel(-1,-1);
608 this->m_ctrlCmdOut.ReplaceSel(cmd+_T("\n"));
609 this->m_ctrlCmdOut.SetSel(-1,-1);
610 this->m_ctrlCmdOut.ReplaceSel(output);
613 CGitHash newhash;
614 if (g_Git.GetHash(newhash, _T("HEAD")))
616 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash after applying patches.")), _T("TortoiseGit"), MB_ICONERROR);
617 return;
620 this->m_InLogList.Clear();
621 this->m_InChangeFileList.Clear();
623 if(newhash == oldhash)
625 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
626 this->m_InLogList.ShowText(_T("No commits get from patch"));
627 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
630 else
632 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,true);
633 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
635 CString range;
636 range.Format(_T("%s..%s"), m_oldHash.ToString(), newhash.ToString());
637 this->AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newhash.ToString(), oldhash.ToString());
638 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
640 this->FetchOutList(true);
643 this->m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,true);
645 if(err)
647 this->ShowTab(IDC_CMD_LOG);
649 else
651 this->ShowTab(IDC_IN_LOGLIST);
656 void CSyncDlg::OnBnClickedButtonEmail()
658 CString cmd, out, err;
660 this->m_strLocalBranch = this->m_ctrlLocalBranch.GetString();
661 this->m_ctrlRemoteBranch.GetWindowText(this->m_strRemoteBranch);
662 this->m_ctrlURL.GetWindowText(this->m_strURL);
663 m_strURL=m_strURL.Trim();
664 m_strRemoteBranch=m_strRemoteBranch.Trim();
666 cmd.Format(_T("git.exe format-patch -o \"%s\" %s..%s"),
667 g_Git.m_CurrentDir,
668 m_strURL+_T('/')+m_strRemoteBranch,g_Git.FixBranchName(m_strLocalBranch));
670 if (g_Git.Run(cmd, &out, &err, CP_UTF8))
672 CMessageBox::Show(NULL, out + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
673 return ;
676 CAppUtils::SendPatchMail(cmd,out);
679 void CSyncDlg::ShowProgressCtrl(bool bShow)
681 int b=bShow?SW_NORMAL:SW_HIDE;
682 this->m_ctrlAnimate.ShowWindow(b);
683 this->m_ctrlProgress.ShowWindow(b);
684 this->m_ctrlProgLabel.ShowWindow(b);
685 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
686 if(b == SW_NORMAL)
687 this->m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
688 else
689 this->m_ctrlAnimate.Stop();
691 void CSyncDlg::ShowInputCtrl(bool bShow)
693 int b=bShow?SW_NORMAL:SW_HIDE;
694 this->m_ctrlURL.ShowWindow(b);
695 this->m_ctrlLocalBranch.ShowWindow(b);
696 this->m_ctrlRemoteBranch.ShowWindow(b);
697 this->GetDlgItem(IDC_BUTTON_LOCAL_BRANCH)->ShowWindow(b);
698 this->GetDlgItem(IDC_BUTTON_REMOTE_BRANCH)->ShowWindow(b);
699 this->GetDlgItem(IDC_STATIC_LOCAL_BRANCH)->ShowWindow(b);
700 this->GetDlgItem(IDC_STATIC_REMOTE_BRANCH)->ShowWindow(b);
701 this->GetDlgItem(IDC_BUTTON_MANAGE)->ShowWindow(b);
702 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->ShowWindow(b);
703 this->GetDlgItem(IDC_CHECK_FORCE)->ShowWindow(b);
704 this->GetDlgItem(IDC_STATIC_REMOTE_URL)->ShowWindow(b);
706 BOOL CSyncDlg::OnInitDialog()
708 CResizableStandAloneDialog::OnInitDialog();
709 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
711 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
712 // do this, Explorer would be unable to send that message to our window if we
713 // were running elevated. It's OK to make the call all the time, since if we're
714 // not elevated, this is a no-op.
715 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
716 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
717 CAutoLibrary hUser = AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
718 if (hUser)
720 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
721 if (pfnChangeWindowMessageFilterEx)
723 pfnChangeWindowMessageFilterEx(m_hWnd, WM_TASKBARBTNCREATED, MSGFLT_ALLOW, &cfs);
726 m_pTaskbarList.Release();
727 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
728 m_pTaskbarList = nullptr;
730 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->EnableWindow(CAppUtils::IsSSHPutty());
733 this->m_ctrlAnimate.ShowWindow(SW_NORMAL);
734 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
735 this->m_ctrlAnimate.Play(0,-1,-1);
738 // ------------------ Create Tabctrl -----------
739 CWnd *pwnd=this->GetDlgItem(IDC_BUTTON_TABCTRL);
740 CRect rectDummy;
741 pwnd->GetWindowRect(&rectDummy);
742 this->ScreenToClient(rectDummy);
744 if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_SYNC_TAB))
746 TRACE0("Failed to create output tab window\n");
747 return FALSE; // fail to create
749 m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
751 // -------------Create Command Log Ctrl ---------
752 DWORD dwStyle;
753 dwStyle= ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL |WS_VSCROLL ;
755 if( !m_ctrlCmdOut.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_CMD_LOG))
757 TRACE0("Failed to create Log commits window\n");
758 return FALSE; // fail to create
761 // set the font to use in the log message view, configured in the settings dialog
762 CFont m_logFont;
763 CAppUtils::CreateFontForLogs(m_logFont);
764 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
765 m_ctrlCmdOut.SetFont(&m_logFont);
766 m_ctrlTabCtrl.InsertTab(&m_ctrlCmdOut, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
768 //m_ctrlCmdOut.ReplaceSel(_T("Hello"));
770 //---------- Create in coming list ctrl -----------
771 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
773 if( !m_InLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_LOGLIST))
775 TRACE0("Failed to create output commits window\n");
776 return FALSE; // fail to create
779 m_ctrlTabCtrl.InsertTab(&m_InLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCOMMITS)), -1);
781 m_InLogList.m_ColumnRegKey=_T("SyncIn");
782 m_InLogList.InsertGitColumn();
784 //----------- Create In Change file list -----------
785 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;
787 if( !m_InChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CHANGELIST))
789 TRACE0("Failed to create output change files window\n");
790 return FALSE; // fail to create
792 m_ctrlTabCtrl.InsertTab(&m_InChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCHANGELIST)), -1);
794 m_InChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL , _T("InSyncDlg"),
795 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
796 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, true, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD| GITSLC_COLDEL);
799 //---------- Create Conflict List Ctrl -----------------
800 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
802 if( !m_ConflictFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CONFLICT))
804 TRACE0("Failed to create output change files window\n");
805 return FALSE; // fail to create
807 m_ctrlTabCtrl.InsertTab(&m_ConflictFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CONFLICTS)), -1);
809 m_ConflictFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL , _T("ConflictSyncDlg"),
810 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
811 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS) |
812 GITSLC_POPCONFLICT|GITSLC_POPRESOLVE),false);
815 //---------- Create Commit Out List Ctrl---------------
817 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
819 if( !m_OutLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_LOGLIST))
821 TRACE0("Failed to create output commits window\n");
822 return FALSE; // fail to create
826 m_ctrlTabCtrl.InsertTab(&m_OutLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCOMMITS)), -1);
828 m_OutLogList.m_ColumnRegKey = _T("SyncOut");
829 m_OutLogList.InsertGitColumn();
831 //------------- Create Change File List Control ----------------
833 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;
835 if( !m_OutChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_CHANGELIST))
837 TRACE0("Failed to create output change files window\n");
838 return FALSE; // fail to create
840 m_ctrlTabCtrl.InsertTab(&m_OutChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCHANGELIST)), -1);
842 m_OutChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL, _T("OutSyncDlg"),
843 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
844 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, true, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL);
846 if (!m_GitProgressList.Create(dwStyle | LVS_OWNERDATA, rectDummy, &m_ctrlTabCtrl, IDC_CMD_GIT_PROG))
848 TRACE0("Failed to create Git Progress List Window\n");
849 return FALSE; // fail to create
851 m_ctrlTabCtrl.InsertTab(&m_GitProgressList, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
852 m_GitProgressList.m_pAnimate = &m_ctrlAnimate;
853 m_GitProgressList.m_pPostWnd = this;
854 m_GitProgressList.m_pProgressLabelCtrl = &m_ctrlProgLabel;
855 m_GitProgressList.m_pProgControl = &m_ctrlProgress;
856 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
858 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
859 DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_FULLROWSELECT;
860 m_refList.Create(dwStyle, rectDummy, &m_ctrlTabCtrl, IDC_REFLIST);
861 m_refList.SetExtendedStyle(exStyle);
862 m_refList.Init();
863 m_ctrlTabCtrl.InsertTab(&m_refList, CString(MAKEINTRESOURCE(IDS_REFLIST)), -1);
865 this->m_tooltips.Create(this);
867 AddAnchor(IDC_SYNC_TAB,TOP_LEFT,BOTTOM_RIGHT);
869 AddAnchor(IDC_GROUP_INFO,TOP_LEFT,TOP_RIGHT);
870 AddAnchor(IDC_COMBOBOXEX_URL,TOP_LEFT,TOP_RIGHT);
871 AddAnchor(IDC_BUTTON_MANAGE,TOP_RIGHT);
872 AddAnchor(IDC_BUTTON_PULL,BOTTOM_LEFT);
873 AddAnchor(IDC_BUTTON_PUSH,BOTTOM_LEFT);
874 AddAnchor(IDC_BUTTON_SUBMODULE,BOTTOM_LEFT);
875 AddAnchor(IDC_BUTTON_STASH,BOTTOM_LEFT);
876 AddAnchor(IDC_BUTTON_APPLY,BOTTOM_RIGHT);
877 AddAnchor(IDC_BUTTON_EMAIL,BOTTOM_RIGHT);
878 AddAnchor(IDC_PROGRESS_SYNC,TOP_LEFT,TOP_RIGHT);
879 AddAnchor(IDOK,BOTTOM_RIGHT);
880 AddAnchor(IDHELP,BOTTOM_RIGHT);
881 AddAnchor(IDC_STATIC_STATUS, BOTTOM_LEFT, BOTTOM_RIGHT);
882 AddAnchor(IDC_ANIMATE_SYNC,TOP_LEFT);
883 AddAnchor(IDC_BUTTON_COMMIT,BOTTOM_LEFT);
884 AddAnchor(IDC_LOG, BOTTOM_LEFT);
886 // do not use BRANCH_COMBOX_ADD_ANCHOR here, we want to have different stylings
887 AddAnchor(IDC_COMBOBOXEX_LOCAL_BRANCH, TOP_LEFT,TOP_CENTER);
888 AddAnchor(IDC_COMBOBOXEX_REMOTE_BRANCH, TOP_CENTER, TOP_RIGHT);
889 AddAnchor(IDC_BUTTON_LOCAL_BRANCH, TOP_CENTER);
890 AddAnchor(IDC_BUTTON_REMOTE_BRANCH, TOP_RIGHT);
891 AddAnchor(IDC_STATIC_REMOTE_BRANCH, TOP_CENTER);
892 AddAnchor(IDC_PROG_LABEL, TOP_LEFT);
894 AdjustControlSize(IDC_CHECK_PUTTY_KEY);
895 AdjustControlSize(IDC_CHECK_FORCE);
897 CString WorkingDir=g_Git.m_CurrentDir;
898 WorkingDir.Replace(_T(':'),_T('_'));
899 m_RegKeyRemoteBranch = CString(_T("Software\\TortoiseGit\\History\\SyncBranch\\"))+WorkingDir;
902 this->AddOthersToAnchor();
904 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSH)));
905 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHTAGS)));
906 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHNOTES)));
908 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULL)));
909 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCH)));
910 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHREBASE)));
911 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REMOTEUPDATE)));
912 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CLEANUPSTALEBRANCHES)));
914 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEUPDATE)));
915 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEINIT)));
916 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULESYNC)));
918 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHSAVE)));
919 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHPOP)));
920 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHAPPLY)));
922 WorkingDir.Replace(_T(':'),_T('_'));
924 CString regkey ;
925 regkey.Format(_T("Software\\TortoiseGit\\TortoiseProc\\Sync\\%s"),WorkingDir);
927 this->m_regPullButton = CRegDWORD(regkey+_T("\\Pull"),0);
928 this->m_regPushButton = CRegDWORD(regkey+_T("\\Push"),0);
929 this->m_regSubmoduleButton = CRegDWORD(regkey+_T("\\Submodule"));
930 this->m_regAutoLoadPutty = CRegDWORD(regkey + _T("\\AutoLoadPutty"), CAppUtils::IsSSHPutty());
932 this->UpdateData();
933 this->m_bAutoLoadPuttyKey = m_regAutoLoadPutty;
934 if(!CAppUtils::IsSSHPutty())
935 m_bAutoLoadPuttyKey = false;
936 this->UpdateData(FALSE);
938 this->m_ctrlPull.SetCurrentEntry(this->m_regPullButton);
939 this->m_ctrlPush.SetCurrentEntry(this->m_regPushButton);
940 this->m_ctrlSubmodule.SetCurrentEntry(this->m_regSubmoduleButton);
942 CString sWindowTitle;
943 GetWindowText(sWindowTitle);
944 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
946 EnableSaveRestore(_T("SyncDlg"));
948 m_ctrlURL.SetCaseSensitive(TRUE);
949 m_ctrlURL.SetURLHistory(true);
950 this->m_ctrlURL.LoadHistory(CString(_T("Software\\TortoiseGit\\History\\SyncURL\\"))+WorkingDir, _T("url"));
952 STRING_VECTOR list;
954 if(!g_Git.GetRemoteList(list))
956 for (unsigned int i = 0; i < list.size(); ++i)
958 m_ctrlURL.AddString(list[i]);
961 m_ctrlURL.SetCurSel(0);
962 m_ctrlRemoteBranch.SetCurSel(0);
964 this->LoadBranchInfo();
966 this->m_bInited=true;
967 FetchOutList();
969 m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,false);
970 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,false);
971 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
972 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT-1,false);
973 m_ctrlTabCtrl.ShowTab(IDC_CMD_GIT_PROG-1, false);
974 m_ctrlTabCtrl.ShowTab(IDC_REFLIST-1, false);
976 m_ctrlRemoteBranch.m_bWantReturn = TRUE;
977 m_ctrlURL.m_bWantReturn = TRUE;
979 this->m_Gitverion = CAppUtils::GetMsysgitVersion();
981 if (m_seq > 0 && (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\SyncDialogRandomPos")))
983 m_seq %= 5;
984 RECT rect;
985 GetWindowRect(&rect);
986 rect.top -= m_seq * 30;
987 rect.bottom -= m_seq * 30;
988 if (rect.top < 0)
990 rect.top += 150;
991 rect.bottom += 150;
993 MoveWindow(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
996 return TRUE; // return TRUE unless you set the focus to a control
997 // EXCEPTION: OCX Property Pages should return FALSE
1000 void CSyncDlg::OnBnClickedButtonManage()
1002 CAppUtils::LaunchRemoteSetting();
1003 Refresh();
1006 void CSyncDlg::Refresh()
1008 theApp.DoWaitCursor(1);
1010 int lastSelected = m_ctrlURL.GetCurSel();
1011 CString url;
1012 this->m_ctrlURL.GetWindowText(url);
1014 this->m_ctrlURL.Reset();
1015 CString workingDir = g_Git.m_CurrentDir;
1016 workingDir.Replace(_T(':'), _T('_'));
1017 this->m_ctrlURL.LoadHistory(_T("Software\\TortoiseGit\\History\\SyncURL\\") + workingDir, _T("url"));
1019 STRING_VECTOR list;
1020 bool found = false;
1021 if (!g_Git.GetRemoteList(list))
1023 for (size_t i = 0; i < list.size(); ++i)
1025 m_ctrlURL.AddString(list[i]);
1026 if (list[i] == url)
1027 found = true;
1030 if (lastSelected >= 0 && !found)
1032 m_ctrlURL.SetCurSel(0);
1033 m_ctrlURL.GetWindowText(url);
1036 CString local;
1037 CString remote;
1038 this->m_ctrlLocalBranch.GetWindowText(local);
1039 this->m_ctrlRemoteBranch.GetWindowText(remote);
1041 this->LoadBranchInfo();
1043 this->m_ctrlLocalBranch.AddString(local);
1044 this->m_ctrlRemoteBranch.AddString(remote);
1045 this->m_ctrlURL.AddString(url);
1047 m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REFRESHING)));
1048 this->FetchOutList(true);
1049 theApp.DoWaitCursor(-1);
1052 BOOL CSyncDlg::PreTranslateMessage(MSG* pMsg)
1054 if (pMsg->message == WM_KEYDOWN)
1056 switch (pMsg->wParam)
1059 case VK_F5:
1061 if (m_bBlock)
1062 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
1063 Refresh();
1065 break;
1067 /* Avoid TAB control destroy but dialog exist*/
1068 case VK_ESCAPE:
1069 case VK_CANCEL:
1071 TCHAR buff[128] = { 0 };
1072 ::GetClassName(pMsg->hwnd,buff,128);
1074 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
1075 if (_tcsnicmp(buff, MSFTEDIT_CLASS, 128) == 0 || //Unicode and MFC 2012 and later
1076 _tcsnicmp(buff, RICHEDIT_CLASS, 128) == 0 || //ANSI or MFC 2010
1077 _tcsnicmp(buff, _T("SysListView32"), 128) == 0)
1079 this->PostMessage(WM_KEYDOWN,VK_ESCAPE,0);
1080 return TRUE;
1085 m_tooltips.RelayEvent(pMsg);
1086 return __super::PreTranslateMessage(pMsg);
1088 void CSyncDlg::FetchOutList(bool force)
1090 if(!m_bInited)
1091 return;
1092 m_OutChangeFileList.Clear();
1093 this->m_OutLogList.Clear();
1095 CString remote;
1096 this->m_ctrlURL.GetWindowText(remote);
1097 CString remotebranch;
1098 this->m_ctrlRemoteBranch.GetWindowText(remotebranch);
1099 remotebranch=remote+_T("/")+remotebranch;
1100 CGitHash remotebranchHash;
1101 g_Git.GetHash(remotebranchHash, remotebranch);
1103 if(IsURL())
1105 CString str;
1106 str.LoadString(IDS_PROC_SYNC_PUSH_UNKNOWN);
1107 m_OutLogList.ShowText(str);
1108 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1109 m_OutLocalBranch.Empty();
1110 m_OutRemoteBranch.Empty();
1112 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1113 return ;
1116 else if(remotebranchHash.IsEmpty())
1118 CString str;
1119 str.Format(IDS_PROC_SYNC_PUSH_UNKNOWNBRANCH, remotebranch);
1120 m_OutLogList.ShowText(str);
1121 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1122 m_OutLocalBranch.Empty();
1123 m_OutRemoteBranch.Empty();
1125 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1126 return ;
1128 else
1130 CString localbranch;
1131 localbranch=this->m_ctrlLocalBranch.GetString();
1133 if(localbranch != m_OutLocalBranch || m_OutRemoteBranch != remotebranch || force)
1135 m_OutLogList.ClearText();
1137 CGitHash base, localBranchHash;
1138 bool isFastForward = g_Git.IsFastForward(remotebranch, localbranch, &base);
1140 if (g_Git.GetHash(localBranchHash, localbranch))
1142 MessageBox(g_Git.GetGitLastErr(_T("Could not get hash of \"") + localbranch + _T("\".")), _T("TortoiseGit"), MB_ICONERROR);
1143 return;
1145 if (remotebranchHash == localBranchHash)
1147 CString str;
1148 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, 0, remotebranch);
1149 m_OutLogList.ShowText(str);
1150 this->m_ctrlStatus.SetWindowText(str);
1151 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1152 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1154 else if (isFastForward || m_bForce)
1156 CString range;
1157 range.Format(_T("%s..%s"), g_Git.FixBranchName(remotebranch), g_Git.FixBranchName(localbranch));
1158 //fast forward
1159 m_OutLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT | CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
1160 CString str;
1161 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, m_OutLogList.GetItemCount(), remotebranch);
1162 this->m_ctrlStatus.SetWindowText(str);
1164 if (isFastForward)
1165 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, remotebranch);
1166 else
1168 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, base.ToString());
1171 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,TRUE);
1172 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(TRUE);
1174 else
1176 CString str;
1177 str.Format(IDS_PROC_SYNC_NOFASTFORWARD, localbranch, remotebranch);
1178 m_OutLogList.ShowText(str);
1179 this->m_ctrlStatus.SetWindowText(str);
1180 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID() - 1, FALSE);
1181 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1184 this->m_OutLocalBranch=localbranch;
1185 this->m_OutRemoteBranch=remotebranch;
1190 bool CSyncDlg::IsURL()
1192 CString str;
1193 this->m_ctrlURL.GetWindowText(str);
1194 if(str.Find(_T('\\'))>=0 || str.Find(_T('/'))>=0)
1195 return true;
1196 else
1197 return false;
1199 void CSyncDlg::OnCbnEditchangeComboboxex()
1201 SetTimer(IDT_INPUT, 1000, NULL);
1202 this->m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_WAINTINPUT)));
1204 //this->FetchOutList();
1207 UINT CSyncDlg::ProgressThread()
1209 m_startTick = GetTickCount();
1210 m_bDone = false;
1211 STRING_VECTOR list;
1212 CProgressDlg::RunCmdList(this, m_GitCmdList, list, true, nullptr, &this->m_bAbort, &this->m_Databuf);
1213 InterlockedExchange(&m_bBlock, FALSE);
1214 return 0;
1218 LRESULT CSyncDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
1220 if(wParam == MSG_PROGRESSDLG_START)
1222 m_BufStart = 0;
1223 m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
1224 this->m_ctrlProgress.SetPos(0);
1225 if (m_pTaskbarList)
1227 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
1228 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 100);
1232 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
1234 DWORD tickSpent = GetTickCount() - m_startTick;
1235 CString strEndTime = CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE, true, false);
1237 m_BufStart = 0;
1238 m_Databuf.m_critSec.Lock();
1239 m_Databuf.clear();
1240 m_Databuf.m_critSec.Unlock();
1242 m_bDone = true;
1243 m_ctrlAnimate.Stop();
1244 m_ctrlProgress.SetPos(100);
1245 //this->DialogEnableWindow(IDOK,TRUE);
1247 DWORD exitCode = (DWORD)lParam;
1248 if (exitCode)
1250 if (m_pTaskbarList)
1252 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
1253 m_pTaskbarList->SetProgressValue(m_hWnd, 100, 100);
1255 CString log;
1256 log.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT, exitCode);
1257 CString err;
1258 err.Format(_T("\r\n\r\n%s (%lu ms @ %s)\r\n"), log, tickSpent, strEndTime);
1259 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, err, RGB(255,0,0));
1260 CSoundUtils::PlayTGitError();
1262 else
1264 if (m_pTaskbarList)
1265 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
1266 CString temp;
1267 temp.LoadString(IDS_SUCCESS);
1268 CString log;
1269 log.Format(_T("\r\n%s (%lu ms @ %s)\r\n"), temp, tickSpent, strEndTime);
1270 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, log, RGB(0,0,255));
1272 m_GitCmdStatus = exitCode;
1274 //if(wParam == MSG_PROGRESSDLG_END)
1275 RunPostAction();
1278 if(lParam != 0)
1279 ParserCmdOutput((char)lParam);
1280 else
1282 m_Databuf.m_critSec.Lock();
1283 for (size_t i = m_BufStart; i < m_Databuf.size(); ++i)
1285 char c = m_Databuf[m_BufStart];
1286 ++m_BufStart;
1287 m_Databuf.m_critSec.Unlock();
1288 ParserCmdOutput(c);
1290 m_Databuf.m_critSec.Lock();
1293 if (m_BufStart > 1000)
1295 m_Databuf.erase(m_Databuf.begin(), m_Databuf.begin() + m_BufStart);
1296 m_BufStart = 0;
1298 m_Databuf.m_critSec.Unlock();
1301 return 0;
1304 static std::map<CString, CGitHash> * HashMapToRefMap(MAP_HASH_NAME &map)
1306 auto rmap = new std::map<CString, CGitHash>();
1307 for (auto mit = map.begin(); mit != map.end(); ++mit)
1309 for (auto rit = mit->second.begin(); rit != mit->second.end(); ++rit)
1311 rmap->insert(std::make_pair(*rit, mit->first));
1314 return rmap;
1317 void CSyncDlg::FillNewRefMap()
1319 m_refList.Clear();
1320 m_newHashMap.clear();
1321 CAutoRepository repo(g_Git.GetGitRepository());
1322 if (!repo)
1324 CMessageBox::Show(m_hWnd, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
1325 return;
1328 if (CGit::GetMapHashToFriendName(repo, m_newHashMap))
1330 MessageBox(CGit::GetLibGit2LastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
1331 return;
1334 auto oldRefMap = HashMapToRefMap(m_oldHashMap);
1335 auto newRefMap = HashMapToRefMap(m_newHashMap);
1336 for (auto oit = oldRefMap->begin(); oit != oldRefMap->end(); ++oit)
1338 bool found = false;
1339 for (auto nit = newRefMap->begin(); nit != newRefMap->end(); ++nit)
1341 // changed ref
1342 if (oit->first == nit->first)
1344 found = true;
1345 m_refList.AddEntry(repo, oit->first, &oit->second, &nit->second);
1346 break;
1349 // deleted ref
1350 if (!found)
1352 m_refList.AddEntry(repo, oit->first, &oit->second, nullptr);
1355 for (auto nit = newRefMap->begin(); nit != newRefMap->end(); ++nit)
1357 bool found = false;
1358 for (auto oit = oldRefMap->begin(); oit != oldRefMap->end(); ++oit)
1360 if (oit->first == nit->first)
1362 found = true;
1363 break;
1366 // new ref
1367 if (!found)
1369 m_refList.AddEntry(repo, nit->first, nullptr, &nit->second);
1372 delete oldRefMap;
1373 delete newRefMap;
1374 m_refList.Show();
1377 void CSyncDlg::RunPostAction()
1379 if (m_bWantToExit)
1380 return;
1382 FillNewRefMap();
1384 if (this->m_CurrentCmd == GIT_COMMAND_PUSH)
1386 DWORD exitcode = 0xFFFFFFFF;
1387 CString error;
1388 if (CHooks::Instance().PostPush(g_Git.m_CurrentDir, exitcode, error))
1390 if (exitcode)
1392 CString temp;
1393 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
1394 CMessageBox::Show(nullptr, temp,_T("TortoiseGit"), MB_OK | MB_ICONERROR);
1395 return;
1399 EnableControlButton(true);
1400 SwitchToInput();
1401 this->FetchOutList(true);
1403 else if (this->m_CurrentCmd == GIT_COMMAND_PULL)
1405 PullComplete();
1407 else if (this->m_CurrentCmd == GIT_COMMAND_FETCH || this->m_CurrentCmd == GIT_COMMAND_FETCHANDREBASE)
1409 FetchComplete();
1411 else if (this->m_CurrentCmd == GIT_COMMAND_SUBMODULE)
1413 //this->m_ctrlCmdOut.SetSel(-1,-1);
1414 //this->m_ctrlCmdOut.ReplaceSel(_T("Done\r\n"));
1415 //this->m_ctrlCmdOut.SetSel(-1,-1);
1416 EnableControlButton(true);
1417 SwitchToInput();
1419 else if (this->m_CurrentCmd == GIT_COMMAND_STASH)
1421 StashComplete();
1423 else if (this->m_CurrentCmd == GIT_COMMAND_REMOTE)
1425 this->FetchOutList(true);
1426 EnableControlButton(true);
1427 SwitchToInput();
1428 ShowTab(IDC_REFLIST);
1431 void CSyncDlg::ParserCmdOutput(char ch)
1433 CProgressDlg::ParserCmdOutput(m_ctrlCmdOut,m_ctrlProgress,m_hWnd,m_pTaskbarList,m_LogText,ch);
1435 void CSyncDlg::OnBnClickedButtonCommit()
1437 CString cmd = _T("/command:commit");
1438 cmd += _T(" /path:\"");
1439 cmd += g_Git.m_CurrentDir;
1440 cmd += _T("\"");
1442 CAppUtils::RunTortoiseGitProc(cmd);
1445 void CSyncDlg::OnOK()
1447 UpdateCombox();
1448 this->UpdateData();
1449 m_ctrlURL.SaveHistory();
1450 SaveHistory();
1451 m_regAutoLoadPutty = this->m_bAutoLoadPuttyKey;
1452 m_tooltips.Pop();
1453 __super::OnOK();
1456 void CSyncDlg::OnCancel()
1458 m_bAbort = true;
1459 if (m_bDone)
1461 CResizableStandAloneDialog::OnCancel();
1462 return;
1465 if (g_Git.m_CurrentGitPi.hProcess)
1467 DWORD dwConfirmKillProcess = CRegDWORD(_T("Software\\TortoiseGit\\ConfirmKillProcess"));
1468 if (dwConfirmKillProcess && CMessageBox::Show(m_hWnd, IDS_PROC_CONFIRMKILLPROCESS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION) != IDYES)
1469 return;
1470 if (::GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))
1472 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess, 10000);
1474 else
1476 GetLastError();
1479 CProgressDlg::KillProcessTree(g_Git.m_CurrentGitPi.dwProcessId);
1482 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
1483 m_tooltips.Pop();
1484 CResizableStandAloneDialog::OnCancel();
1487 void CSyncDlg::OnBnClickedButtonSubmodule()
1489 this->UpdateData();
1490 UpdateCombox();
1491 m_ctrlCmdOut.SetWindowTextW(_T(""));
1492 m_LogText = "";
1494 this->m_regSubmoduleButton = (DWORD)this->m_ctrlSubmodule.GetCurrentEntry();
1496 this->SwitchToRun();
1498 this->m_bAbort=false;
1499 this->m_GitCmdList.clear();
1501 ShowTab(IDC_CMD_LOG);
1503 CString cmd;
1505 switch (m_ctrlSubmodule.GetCurrentEntry())
1507 case 0:
1508 cmd=_T("git.exe submodule update --init");
1509 break;
1510 case 1:
1511 cmd=_T("git.exe submodule init");
1512 break;
1513 case 2:
1514 cmd=_T("git.exe submodule sync");
1515 break;
1518 m_GitCmdList.push_back(cmd);
1520 m_CurrentCmd = GIT_COMMAND_SUBMODULE;
1522 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
1523 if (m_pThread==NULL)
1525 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1527 else
1529 m_pThread->m_bAutoDelete = TRUE;
1530 m_pThread->ResumeThread();
1534 void CSyncDlg::OnBnClickedButtonStash()
1536 UpdateData();
1537 UpdateCombox();
1538 m_ctrlCmdOut.SetWindowTextW(_T(""));
1539 m_LogText = "";
1541 SwitchToRun();
1543 m_bAbort = false;
1544 m_GitCmdList.clear();
1546 ShowTab(IDC_CMD_LOG);
1548 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, false);
1549 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST -1, false);
1550 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT -1, false);
1552 CString cmd;
1553 switch (m_ctrlStash.GetCurrentEntry())
1555 case 0:
1556 cmd = _T("git.exe stash save");
1557 break;
1558 case 1:
1559 cmd = _T("git.exe stash pop");
1560 break;
1561 case 2:
1562 cmd = _T("git.exe stash apply");
1563 break;
1566 m_GitCmdList.push_back(cmd);
1567 m_CurrentCmd = GIT_COMMAND_STASH;
1569 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
1570 if (!m_pThread)
1572 //ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1574 else
1576 m_pThread->m_bAutoDelete = TRUE;
1577 m_pThread->ResumeThread();
1581 void CSyncDlg::OnTimer(UINT_PTR nIDEvent)
1583 if( nIDEvent == IDT_INPUT)
1585 KillTimer(IDT_INPUT);
1586 this->FetchOutList(true);
1591 void CSyncDlg::OnLvnInLogListColumnClick(NMHDR * /* pNMHDR */, LRESULT *pResult)
1593 *pResult = 0;
1596 LRESULT CSyncDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
1598 m_pTaskbarList.Release();
1599 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
1600 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
1601 SetUUIDOverlayIcon(m_hWnd);
1602 return 0;
1605 void CSyncDlg::OnBnClickedCheckForce()
1607 UpdateData();
1610 void CSyncDlg::OnBnClickedLog()
1612 CString cmd = _T("/command:log");
1613 cmd += _T(" /path:\"");
1614 cmd += g_Git.m_CurrentDir;
1615 cmd += _T("\"");
1617 CAppUtils::RunTortoiseGitProc(cmd);
1620 LRESULT CSyncDlg::OnProgCmdFinish(WPARAM /*wParam*/, LPARAM /*lParam*/)
1622 RunPostAction();
1623 return 0;
1626 void CSyncDlg::OnDestroy()
1628 m_bWantToExit = true;
1629 __super::OnDestroy();