Optical improvements
[TortoiseGit.git] / src / TortoiseProc / SyncDlg.cpp
blob032c23ae5ed0b76e834c3ccacd09976282694b1c
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"
34 #include "ProgressCommands/FetchProgressCommand.h"
36 // CSyncDlg dialog
38 IMPLEMENT_DYNAMIC(CSyncDlg, CResizableStandAloneDialog)
40 CSyncDlg::CSyncDlg(CWnd* pParent /*=NULL*/)
41 : CResizableStandAloneDialog(CSyncDlg::IDD, pParent)
43 m_CurrentCmd = 0;
44 m_pTooltip=&this->m_tooltips;
45 m_bInited=false;
46 m_CmdOutCurrentPos=0;
47 m_bAutoLoadPuttyKey = CAppUtils::IsSSHPutty();
48 m_bForce=false;
49 m_Gitverion = 0;
50 m_bBlock = false;
51 m_BufStart = 0;
52 m_pThread = NULL;
53 m_bAbort = false;
54 m_bDone = false;
55 m_bWantToExit = false;
56 m_GitCmdStatus = -1;
57 m_startTick = GetTickCount();
58 m_seq = 0;
61 CSyncDlg::~CSyncDlg()
65 void CSyncDlg::DoDataExchange(CDataExchange* pDX)
67 CDialog::DoDataExchange(pDX);
68 DDX_Check(pDX, IDC_CHECK_PUTTY_KEY, m_bAutoLoadPuttyKey);
69 DDX_Check(pDX, IDC_CHECK_FORCE,m_bForce);
70 DDX_Control(pDX, IDC_COMBOBOXEX_URL, m_ctrlURL);
71 DDX_Control(pDX, IDC_BUTTON_TABCTRL, m_ctrlDumyButton);
72 DDX_Control(pDX, IDC_BUTTON_PULL, m_ctrlPull);
73 DDX_Control(pDX, IDC_BUTTON_PUSH, m_ctrlPush);
74 DDX_Control(pDX, IDC_STATIC_STATUS, m_ctrlStatus);
75 DDX_Control(pDX, IDC_PROGRESS_SYNC, m_ctrlProgress);
76 DDX_Control(pDX, IDC_ANIMATE_SYNC, m_ctrlAnimate);
77 DDX_Control(pDX, IDC_BUTTON_SUBMODULE,m_ctrlSubmodule);
78 DDX_Control(pDX, IDC_BUTTON_STASH, m_ctrlStash);
79 DDX_Control(pDX, IDC_PROG_LABEL, m_ctrlProgLabel);
80 BRANCH_COMBOX_DDX;
84 BEGIN_MESSAGE_MAP(CSyncDlg, CResizableStandAloneDialog)
85 ON_BN_CLICKED(IDC_BUTTON_PULL, &CSyncDlg::OnBnClickedButtonPull)
86 ON_BN_CLICKED(IDC_BUTTON_PUSH, &CSyncDlg::OnBnClickedButtonPush)
87 ON_BN_CLICKED(IDC_BUTTON_APPLY, &CSyncDlg::OnBnClickedButtonApply)
88 ON_BN_CLICKED(IDC_BUTTON_EMAIL, &CSyncDlg::OnBnClickedButtonEmail)
89 ON_BN_CLICKED(IDC_BUTTON_MANAGE, &CSyncDlg::OnBnClickedButtonManage)
90 BRANCH_COMBOX_EVENT
91 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_URL, &CSyncDlg::OnCbnEditchangeComboboxex)
92 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_REMOTE_BRANCH, &CSyncDlg::OnCbnEditchangeComboboxex)
93 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
94 ON_MESSAGE(WM_PROG_CMD_FINISH, OnProgCmdFinish)
95 ON_NOTIFY(LVN_COLUMNCLICK, IDC_IN_LOGLIST, OnLvnInLogListColumnClick)
96 ON_BN_CLICKED(IDC_BUTTON_COMMIT, &CSyncDlg::OnBnClickedButtonCommit)
97 ON_BN_CLICKED(IDC_BUTTON_SUBMODULE, &CSyncDlg::OnBnClickedButtonSubmodule)
98 ON_BN_CLICKED(IDC_BUTTON_STASH, &CSyncDlg::OnBnClickedButtonStash)
99 ON_WM_TIMER()
100 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
101 ON_BN_CLICKED(IDC_CHECK_FORCE, &CSyncDlg::OnBnClickedCheckForce)
102 ON_BN_CLICKED(IDC_LOG, &CSyncDlg::OnBnClickedLog)
103 ON_WM_DESTROY()
104 END_MESSAGE_MAP()
107 void CSyncDlg::EnableControlButton(bool bEnabled)
109 GetDlgItem(IDC_BUTTON_PULL)->EnableWindow(bEnabled);
110 GetDlgItem(IDC_BUTTON_PUSH)->EnableWindow(bEnabled);
111 GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(bEnabled);
112 GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(bEnabled);
113 GetDlgItem(IDOK)->EnableWindow(bEnabled);
114 GetDlgItem(IDC_BUTTON_SUBMODULE)->EnableWindow(bEnabled);
115 GetDlgItem(IDC_BUTTON_STASH)->EnableWindow(bEnabled);
117 // CSyncDlg message handlers
119 void CSyncDlg::OnBnClickedButtonPull()
121 int CurrentEntry;
122 CurrentEntry = (int)this->m_ctrlPull.GetCurrentEntry();
123 this->m_regPullButton = CurrentEntry;
125 this->m_bAbort=false;
126 this->m_GitCmdList.clear();
127 m_ctrlCmdOut.SetWindowTextW(_T(""));
128 m_LogText = "";
130 this->UpdateData();
131 UpdateCombox();
133 if (g_Git.GetHash(m_oldHash, _T("HEAD")))
135 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR);
136 return;
139 m_refList.Clear();
140 m_newHashMap.clear();
141 m_oldHashMap.clear();
143 if( CurrentEntry == 0)
145 CGitHash localBranchHash;
146 if (g_Git.GetHash(localBranchHash, m_strLocalBranch))
148 MessageBox(g_Git.GetGitLastErr(_T("Could not get hash of \"") + m_strLocalBranch + _T("\".")), _T("TortoiseGit"), MB_ICONERROR);
149 return;
151 if (localBranchHash != m_oldHash)
153 CMessageBox::Show(NULL, IDS_PROC_SYNC_PULLWRONGBRANCH, IDS_APPNAME, MB_OK | MB_ICONERROR);
154 return;
158 if(this->m_strURL.IsEmpty())
160 CMessageBox::Show(NULL, IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
161 return;
164 if (m_bAutoLoadPuttyKey && CurrentEntry != 3) // CurrentEntry (Remote Update) handles this on its own)
166 CAppUtils::LaunchPAgent(NULL,&this->m_strURL);
169 this->SwitchToRun();
170 if (g_Git.GetMapHashToFriendName(m_oldHashMap))
171 MessageBox(g_Git.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
173 CString force;
174 if(this->m_bForce)
175 force = _T(" --force ");
177 CString cmd;
179 ShowTab(IDC_CMD_LOG);
181 this->m_ctrlTabCtrl.ShowTab(IDC_REFLIST-1,true);
182 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,false);
183 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
184 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT-1,false);
186 ///Pull
187 if(CurrentEntry == 0) //Pull
189 CString remotebranch;
190 remotebranch = m_strRemoteBranch;
192 if(!IsURL())
194 CString pullRemote, pullBranch;
195 g_Git.GetRemoteTrackedBranch(m_strLocalBranch, pullRemote, pullBranch);
196 if(pullBranch == remotebranch && pullRemote == this->m_strURL)
197 remotebranch.Empty();
200 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
201 force += _T("--progress ");
203 cmd.Format(_T("git.exe pull -v %s \"%s\" %s"),
204 force,
205 m_strURL,
206 remotebranch);
208 m_CurrentCmd = GIT_COMMAND_PULL;
209 m_GitCmdList.push_back(cmd);
211 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
212 if (m_pThread==NULL)
214 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
216 else
218 m_pThread->m_bAutoDelete = TRUE;
219 m_pThread->ResumeThread();
224 ///Fetch
225 if(CurrentEntry == 1 || CurrentEntry ==2 ) //Fetch
227 CString remotebranch;
228 if(this->IsURL() || m_strRemoteBranch.IsEmpty())
230 remotebranch=this->m_strRemoteBranch;
233 else
235 remotebranch.Format(_T("remotes/%s/%s"),
236 m_strURL,m_strRemoteBranch);
237 CGitHash remoteBranchHash;
238 g_Git.GetHash(remoteBranchHash, remotebranch);
239 if (remoteBranchHash.IsEmpty())
240 remotebranch=m_strRemoteBranch;
241 else
242 remotebranch=m_strRemoteBranch+_T(":")+remotebranch;
245 if(CurrentEntry == 1)
246 m_CurrentCmd = GIT_COMMAND_FETCH;
247 else
248 m_CurrentCmd = GIT_COMMAND_FETCHANDREBASE;
250 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
252 CString refspec;
253 // current libgit2 only supports well formated refspec
254 refspec.Format(_T("refs/heads/%s:refs/remotes/%s/%s"), m_strRemoteBranch, m_strURL, m_strRemoteBranch);
256 FetchProgressCommand fetchProgressCommand;
257 fetchProgressCommand.SetUrl(m_strURL);
258 fetchProgressCommand.SetRefSpec(refspec);
259 m_GitProgressList.SetCommand(&fetchProgressCommand);
260 m_GitProgressList.Init();
261 ShowTab(IDC_CMD_GIT_PROG);
263 else
265 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
266 force += _T("--progress ");
268 cmd.Format(_T("git.exe fetch -v %s \"%s\" %s"),
269 force,
270 m_strURL,
271 remotebranch);
273 m_GitCmdList.push_back(cmd);
275 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
276 if (m_pThread==NULL)
278 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
280 else
282 m_pThread->m_bAutoDelete = TRUE;
283 m_pThread->ResumeThread();
288 ///Remote Update
289 if(CurrentEntry == 3)
291 if (m_bAutoLoadPuttyKey)
293 STRING_VECTOR list;
294 if (!g_Git.GetRemoteList(list))
296 for (size_t i = 0; i < list.size(); ++i)
297 CAppUtils::LaunchPAgent(NULL, &list[i]);
301 m_CurrentCmd = GIT_COMMAND_REMOTE;
302 cmd=_T("git.exe remote update");
303 m_GitCmdList.push_back(cmd);
305 InterlockedExchange(&m_bBlock, TRUE);
307 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
308 if (m_pThread==NULL)
310 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
311 InterlockedExchange(&m_bBlock, FALSE);
313 else
315 m_pThread->m_bAutoDelete = TRUE;
316 m_pThread->ResumeThread();
320 ///Cleanup stale remote banches
321 if(CurrentEntry == 4)
323 m_CurrentCmd = GIT_COMMAND_REMOTE;
324 cmd.Format(_T("git.exe remote prune \"%s\""), m_strURL);
325 m_GitCmdList.push_back(cmd);
327 InterlockedExchange(&m_bBlock, TRUE);
329 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
330 if (m_pThread==NULL)
332 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
333 InterlockedExchange(&m_bBlock, FALSE);
335 else
337 m_pThread->m_bAutoDelete = TRUE;
338 m_pThread->ResumeThread();
343 void CSyncDlg::PullComplete()
345 EnableControlButton(true);
346 SwitchToInput();
347 this->FetchOutList(true);
349 CGitHash newhash;
350 if (g_Git.GetHash(newhash, _T("HEAD")))
351 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash after pulling.")), _T("TortoiseGit"), MB_ICONERROR);
353 if( this ->m_GitCmdStatus )
355 CTGitPathList list;
356 if(g_Git.ListConflictFile(list))
358 this->m_ctrlCmdOut.SetSel(-1,-1);
359 this->m_ctrlCmdOut.ReplaceSel(_T("Get conflict files fail\n"));
361 this->ShowTab(IDC_CMD_LOG);
362 return;
365 if (!list.IsEmpty())
367 this->m_ConflictFileList.Clear();
368 CTGitPathList list;
369 CTGitPath path;
370 list.AddPath(path);
372 this->m_ConflictFileList.GetStatus(&list,true);
373 this->m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED,
374 CTGitPath::LOGACTIONS_UNMERGED);
376 this->ShowTab(IDC_IN_CONFLICT);
378 else
379 this->ShowTab(IDC_CMD_LOG);
382 else
384 if(newhash == this->m_oldHash)
386 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
387 this->m_InLogList.ShowText(CString(MAKEINTRESOURCE(IDS_UPTODATE)));
388 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
389 this->ShowTab(IDC_REFLIST);
391 else
393 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,true);
394 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
396 this->AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newhash.ToString(), m_oldHash.ToString());
398 CString range;
399 range.Format(_T("%s..%s"), m_oldHash.ToString(), newhash.ToString());
400 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
401 this->ShowTab(IDC_IN_LOGLIST);
406 void CSyncDlg::FetchComplete()
408 EnableControlButton(true);
409 SwitchToInput();
410 this->FetchOutList(true);
412 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
413 ShowTab(IDC_CMD_GIT_PROG);
414 else
415 ShowTab(IDC_REFLIST);
416 if( (!this->m_GitCmdStatus) && this->m_CurrentCmd == GIT_COMMAND_FETCHANDREBASE)
418 CRebaseDlg dlg;
419 CString remote, remotebranch;
420 m_ctrlURL.GetWindowText(remote);
421 if (!remote.IsEmpty())
423 STRING_VECTOR remotes;
424 g_Git.GetRemoteList(remotes);
425 if (std::find(remotes.begin(), remotes.end(), remote) == remotes.end())
426 remote.Empty();
428 m_ctrlRemoteBranch.GetWindowText(remotebranch);
429 if (!remote.IsEmpty() && !remotebranch.IsEmpty())
430 dlg.m_Upstream = _T("remotes/") + remote + _T("/") + remotebranch;
431 dlg.m_PostButtonTexts.Add(CString(MAKEINTRESOURCE(IDS_MENULOG)));
432 dlg.m_PostButtonTexts.Add(_T("Email &Patch..."));
433 INT_PTR response = dlg.DoModal();
434 if(response == IDOK)
436 return ;
439 if (response == IDC_REBASE_POST_BUTTON)
441 CString cmd = _T("/command:log");
442 cmd += _T(" /path:\"") + g_Git.m_CurrentDir + _T("\"");
443 CAppUtils::RunTortoiseGitProc(cmd);
445 if(response == IDC_REBASE_POST_BUTTON + 1)
447 CString cmd, out, err;
448 cmd.Format(_T("git.exe format-patch -o \"%s\" %s..%s"),
449 g_Git.m_CurrentDir,
450 g_Git.FixBranchName(dlg.m_Upstream),
451 g_Git.FixBranchName(dlg.m_Branch));
452 if (g_Git.Run(cmd, &out, &err, CP_UTF8))
454 CMessageBox::Show(NULL, out + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
455 return ;
458 CAppUtils::SendPatchMail(cmd,out);
463 void CSyncDlg::StashComplete()
465 EnableControlButton(true);
466 INT_PTR entry = m_ctrlStash.GetCurrentEntry();
467 if (entry != 1 && entry != 2)
468 return;
470 SwitchToInput();
471 if (m_GitCmdStatus)
473 CTGitPathList list;
474 if (g_Git.ListConflictFile(list))
476 m_ctrlCmdOut.SetSel(-1, -1);
477 m_ctrlCmdOut.ReplaceSel(_T("Get conflict files fail\n"));
479 ShowTab(IDC_CMD_LOG);
480 return;
483 if (!list.IsEmpty())
485 m_ConflictFileList.Clear();
486 CTGitPathList list;
487 CTGitPath path;
488 list.AddPath(path);
490 m_ConflictFileList.GetStatus(&list,true);
491 m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED, CTGitPath::LOGACTIONS_UNMERGED);
493 ShowTab(IDC_IN_CONFLICT);
495 else
496 ShowTab(IDC_CMD_LOG);
500 void CSyncDlg::OnBnClickedButtonPush()
502 this->UpdateData();
503 UpdateCombox();
504 m_ctrlCmdOut.SetWindowTextW(_T(""));
505 m_LogText = "";
507 if(this->m_strURL.IsEmpty())
509 CMessageBox::Show(NULL, IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
510 return;
513 this->m_regPushButton=(DWORD)this->m_ctrlPush.GetCurrentEntry();
514 this->SwitchToRun();
515 this->m_bAbort=false;
516 this->m_GitCmdList.clear();
518 ShowTab(IDC_CMD_LOG);
520 CString cmd;
521 CString arg;
523 CString error;
524 DWORD exitcode = 0xFFFFFFFF;
525 if (CHooks::Instance().PrePush(g_Git.m_CurrentDir, exitcode, error))
527 if (exitcode)
529 CString temp;
530 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
531 CMessageBox::Show(NULL,temp,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
532 return ;
536 CString refName = g_Git.FixBranchName(m_strLocalBranch);
537 switch (m_ctrlPush.GetCurrentEntry())
539 case 1:
540 arg += _T(" --tags ");
541 break;
542 case 2:
543 refName = _T("refs/notes/commits"); //default ref for notes
544 break;
547 if(this->m_bForce)
548 arg += _T(" --force ");
550 if(m_Gitverion >= 0x01070203) //above 1.7.0.2
551 arg += _T("--progress ");
553 cmd.Format(_T("git.exe push -v %s \"%s\" %s"),
554 arg,
555 m_strURL,
556 refName);
558 if (!m_strRemoteBranch.IsEmpty() && m_ctrlPush.GetCurrentEntry() != 2)
560 cmd += _T(":") + m_strRemoteBranch;
563 m_GitCmdList.push_back(cmd);
565 m_CurrentCmd = GIT_COMMAND_PUSH;
567 if(this->m_bAutoLoadPuttyKey)
569 CAppUtils::LaunchPAgent(NULL,&this->m_strURL);
572 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
573 if (m_pThread==NULL)
575 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
577 else
579 m_pThread->m_bAutoDelete = TRUE;
580 m_pThread->ResumeThread();
584 void CSyncDlg::OnBnClickedButtonApply()
586 CGitHash oldhash;
587 if (g_Git.GetHash(oldhash, _T("HEAD")))
589 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR);
590 return;
593 CImportPatchDlg dlg;
594 CString cmd,output;
596 if(dlg.DoModal() == IDOK)
598 int err=0;
599 for (int i = 0; i < dlg.m_PathList.GetCount(); ++i)
601 cmd.Format(_T("git.exe am \"%s\""),dlg.m_PathList[i].GetGitPathString());
603 if (g_Git.Run(cmd, &output, CP_UTF8))
605 CMessageBox::Show(NULL,output,_T("TortoiseGit"),MB_OK);
607 err=1;
608 break;
610 this->m_ctrlCmdOut.SetSel(-1,-1);
611 this->m_ctrlCmdOut.ReplaceSel(cmd+_T("\n"));
612 this->m_ctrlCmdOut.SetSel(-1,-1);
613 this->m_ctrlCmdOut.ReplaceSel(output);
616 CGitHash newhash;
617 if (g_Git.GetHash(newhash, _T("HEAD")))
619 MessageBox(g_Git.GetGitLastErr(_T("Could not get HEAD hash after applying patches.")), _T("TortoiseGit"), MB_ICONERROR);
620 return;
623 this->m_InLogList.Clear();
624 this->m_InChangeFileList.Clear();
626 if(newhash == oldhash)
628 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
629 this->m_InLogList.ShowText(_T("No commits get from patch"));
630 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
633 else
635 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,true);
636 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
638 CString range;
639 range.Format(_T("%s..%s"), m_oldHash.ToString(), newhash.ToString());
640 this->AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newhash.ToString(), oldhash.ToString());
641 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
643 this->FetchOutList(true);
646 this->m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,true);
648 if(err)
650 this->ShowTab(IDC_CMD_LOG);
652 else
654 this->ShowTab(IDC_IN_LOGLIST);
659 void CSyncDlg::OnBnClickedButtonEmail()
661 CString cmd, out, err;
663 this->m_strLocalBranch = this->m_ctrlLocalBranch.GetString();
664 this->m_ctrlRemoteBranch.GetWindowText(this->m_strRemoteBranch);
665 this->m_ctrlURL.GetWindowText(this->m_strURL);
666 m_strURL=m_strURL.Trim();
667 m_strRemoteBranch=m_strRemoteBranch.Trim();
669 cmd.Format(_T("git.exe format-patch -o \"%s\" %s..%s"),
670 g_Git.m_CurrentDir,
671 m_strURL+_T('/')+m_strRemoteBranch,g_Git.FixBranchName(m_strLocalBranch));
673 if (g_Git.Run(cmd, &out, &err, CP_UTF8))
675 CMessageBox::Show(NULL, out + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
676 return ;
679 CAppUtils::SendPatchMail(cmd,out);
682 void CSyncDlg::ShowProgressCtrl(bool bShow)
684 int b=bShow?SW_NORMAL:SW_HIDE;
685 this->m_ctrlAnimate.ShowWindow(b);
686 this->m_ctrlProgress.ShowWindow(b);
687 this->m_ctrlProgLabel.ShowWindow(b);
688 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
689 if(b == SW_NORMAL)
690 this->m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
691 else
692 this->m_ctrlAnimate.Stop();
694 void CSyncDlg::ShowInputCtrl(bool bShow)
696 int b=bShow?SW_NORMAL:SW_HIDE;
697 this->m_ctrlURL.ShowWindow(b);
698 this->m_ctrlLocalBranch.ShowWindow(b);
699 this->m_ctrlRemoteBranch.ShowWindow(b);
700 this->GetDlgItem(IDC_BUTTON_LOCAL_BRANCH)->ShowWindow(b);
701 this->GetDlgItem(IDC_BUTTON_REMOTE_BRANCH)->ShowWindow(b);
702 this->GetDlgItem(IDC_STATIC_LOCAL_BRANCH)->ShowWindow(b);
703 this->GetDlgItem(IDC_STATIC_REMOTE_BRANCH)->ShowWindow(b);
704 this->GetDlgItem(IDC_BUTTON_MANAGE)->ShowWindow(b);
705 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->ShowWindow(b);
706 this->GetDlgItem(IDC_CHECK_FORCE)->ShowWindow(b);
707 this->GetDlgItem(IDC_STATIC_REMOTE_URL)->ShowWindow(b);
709 BOOL CSyncDlg::OnInitDialog()
711 CResizableStandAloneDialog::OnInitDialog();
712 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
714 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
715 // do this, Explorer would be unable to send that message to our window if we
716 // were running elevated. It's OK to make the call all the time, since if we're
717 // not elevated, this is a no-op.
718 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
719 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
720 CAutoLibrary hUser = AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
721 if (hUser)
723 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
724 if (pfnChangeWindowMessageFilterEx)
726 pfnChangeWindowMessageFilterEx(m_hWnd, WM_TASKBARBTNCREATED, MSGFLT_ALLOW, &cfs);
729 m_pTaskbarList.Release();
730 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
731 m_pTaskbarList = nullptr;
733 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->EnableWindow(CAppUtils::IsSSHPutty());
736 this->m_ctrlAnimate.ShowWindow(SW_NORMAL);
737 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
738 this->m_ctrlAnimate.Play(0,-1,-1);
741 // ------------------ Create Tabctrl -----------
742 CWnd *pwnd=this->GetDlgItem(IDC_BUTTON_TABCTRL);
743 CRect rectDummy;
744 pwnd->GetWindowRect(&rectDummy);
745 this->ScreenToClient(rectDummy);
747 if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_SYNC_TAB))
749 TRACE0("Failed to create output tab window\n");
750 return FALSE; // fail to create
752 m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
754 // -------------Create Command Log Ctrl ---------
755 DWORD dwStyle;
756 dwStyle= ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL |WS_VSCROLL ;
758 if( !m_ctrlCmdOut.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_CMD_LOG))
760 TRACE0("Failed to create Log commits window\n");
761 return FALSE; // fail to create
764 // set the font to use in the log message view, configured in the settings dialog
765 CFont m_logFont;
766 CAppUtils::CreateFontForLogs(m_logFont);
767 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
768 m_ctrlCmdOut.SetFont(&m_logFont);
769 m_ctrlTabCtrl.InsertTab(&m_ctrlCmdOut, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
771 //m_ctrlCmdOut.ReplaceSel(_T("Hello"));
773 //---------- Create in coming list ctrl -----------
774 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
776 if( !m_InLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_LOGLIST))
778 TRACE0("Failed to create output commits window\n");
779 return FALSE; // fail to create
782 m_ctrlTabCtrl.InsertTab(&m_InLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCOMMITS)), -1);
784 m_InLogList.m_ColumnRegKey=_T("SyncIn");
785 m_InLogList.InsertGitColumn();
787 //----------- Create In Change file list -----------
788 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;
790 if( !m_InChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CHANGELIST))
792 TRACE0("Failed to create output change files window\n");
793 return FALSE; // fail to create
795 m_ctrlTabCtrl.InsertTab(&m_InChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCHANGELIST)), -1);
797 m_InChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL , _T("InSyncDlg"),
798 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
799 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, true, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD| GITSLC_COLDEL);
802 //---------- Create Conflict List Ctrl -----------------
803 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
805 if( !m_ConflictFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CONFLICT))
807 TRACE0("Failed to create output change files window\n");
808 return FALSE; // fail to create
810 m_ctrlTabCtrl.InsertTab(&m_ConflictFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CONFLICTS)), -1);
812 m_ConflictFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL , _T("ConflictSyncDlg"),
813 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
814 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS) |
815 GITSLC_POPCONFLICT|GITSLC_POPRESOLVE),false);
818 //---------- Create Commit Out List Ctrl---------------
820 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
822 if( !m_OutLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_LOGLIST))
824 TRACE0("Failed to create output commits window\n");
825 return FALSE; // fail to create
829 m_ctrlTabCtrl.InsertTab(&m_OutLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCOMMITS)), -1);
831 m_OutLogList.m_ColumnRegKey = _T("SyncOut");
832 m_OutLogList.InsertGitColumn();
834 //------------- Create Change File List Control ----------------
836 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;
838 if( !m_OutChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_CHANGELIST))
840 TRACE0("Failed to create output change files window\n");
841 return FALSE; // fail to create
843 m_ctrlTabCtrl.InsertTab(&m_OutChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCHANGELIST)), -1);
845 m_OutChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL, _T("OutSyncDlg"),
846 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
847 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, true, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL);
849 if (!m_GitProgressList.Create(dwStyle | LVS_OWNERDATA, rectDummy, &m_ctrlTabCtrl, IDC_CMD_GIT_PROG))
851 TRACE0("Failed to create Git Progress List Window\n");
852 return FALSE; // fail to create
854 m_ctrlTabCtrl.InsertTab(&m_GitProgressList, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
855 m_GitProgressList.m_pAnimate = &m_ctrlAnimate;
856 m_GitProgressList.m_pPostWnd = this;
857 m_GitProgressList.m_pProgressLabelCtrl = &m_ctrlProgLabel;
858 m_GitProgressList.m_pProgControl = &m_ctrlProgress;
859 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
861 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
862 DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_FULLROWSELECT;
863 m_refList.Create(dwStyle, rectDummy, &m_ctrlTabCtrl, IDC_REFLIST);
864 m_refList.SetExtendedStyle(exStyle);
865 m_refList.Init();
866 m_ctrlTabCtrl.InsertTab(&m_refList, CString(MAKEINTRESOURCE(IDS_REFLIST)), -1);
868 this->m_tooltips.Create(this);
870 AddAnchor(IDC_SYNC_TAB,TOP_LEFT,BOTTOM_RIGHT);
872 AddAnchor(IDC_GROUP_INFO,TOP_LEFT,TOP_RIGHT);
873 AddAnchor(IDC_COMBOBOXEX_URL,TOP_LEFT,TOP_RIGHT);
874 AddAnchor(IDC_BUTTON_MANAGE,TOP_RIGHT);
875 AddAnchor(IDC_BUTTON_PULL,BOTTOM_LEFT);
876 AddAnchor(IDC_BUTTON_PUSH,BOTTOM_LEFT);
877 AddAnchor(IDC_BUTTON_SUBMODULE,BOTTOM_LEFT);
878 AddAnchor(IDC_BUTTON_STASH,BOTTOM_LEFT);
879 AddAnchor(IDC_BUTTON_APPLY,BOTTOM_RIGHT);
880 AddAnchor(IDC_BUTTON_EMAIL,BOTTOM_RIGHT);
881 AddAnchor(IDC_PROGRESS_SYNC,TOP_LEFT,TOP_RIGHT);
882 AddAnchor(IDOK,BOTTOM_RIGHT);
883 AddAnchor(IDHELP,BOTTOM_RIGHT);
884 AddAnchor(IDC_STATIC_STATUS, BOTTOM_LEFT, BOTTOM_RIGHT);
885 AddAnchor(IDC_ANIMATE_SYNC,TOP_LEFT);
886 AddAnchor(IDC_BUTTON_COMMIT,BOTTOM_LEFT);
887 AddAnchor(IDC_LOG, BOTTOM_LEFT);
889 // do not use BRANCH_COMBOX_ADD_ANCHOR here, we want to have different stylings
890 AddAnchor(IDC_COMBOBOXEX_LOCAL_BRANCH, TOP_LEFT,TOP_CENTER);
891 AddAnchor(IDC_COMBOBOXEX_REMOTE_BRANCH, TOP_CENTER, TOP_RIGHT);
892 AddAnchor(IDC_BUTTON_LOCAL_BRANCH, TOP_CENTER);
893 AddAnchor(IDC_BUTTON_REMOTE_BRANCH, TOP_RIGHT);
894 AddAnchor(IDC_STATIC_REMOTE_BRANCH, TOP_CENTER);
895 AddAnchor(IDC_PROG_LABEL, TOP_LEFT);
897 AdjustControlSize(IDC_CHECK_PUTTY_KEY);
898 AdjustControlSize(IDC_CHECK_FORCE);
900 CString WorkingDir=g_Git.m_CurrentDir;
901 WorkingDir.Replace(_T(':'),_T('_'));
902 m_RegKeyRemoteBranch = CString(_T("Software\\TortoiseGit\\History\\SyncBranch\\"))+WorkingDir;
905 this->AddOthersToAnchor();
907 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSH)));
908 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHTAGS)));
909 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHNOTES)));
911 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULL)));
912 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCH)));
913 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHREBASE)));
914 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REMOTEUPDATE)));
915 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CLEANUPSTALEBRANCHES)));
917 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEUPDATE)));
918 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEINIT)));
919 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULESYNC)));
921 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHSAVE)));
922 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHPOP)));
923 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHAPPLY)));
925 WorkingDir.Replace(_T(':'),_T('_'));
927 CString regkey ;
928 regkey.Format(_T("Software\\TortoiseGit\\TortoiseProc\\Sync\\%s"),WorkingDir);
930 this->m_regPullButton = CRegDWORD(regkey+_T("\\Pull"),0);
931 this->m_regPushButton = CRegDWORD(regkey+_T("\\Push"),0);
932 this->m_regSubmoduleButton = CRegDWORD(regkey+_T("\\Submodule"));
933 this->m_regAutoLoadPutty = CRegDWORD(regkey + _T("\\AutoLoadPutty"), CAppUtils::IsSSHPutty());
935 this->UpdateData();
936 this->m_bAutoLoadPuttyKey = m_regAutoLoadPutty;
937 if(!CAppUtils::IsSSHPutty())
938 m_bAutoLoadPuttyKey = false;
939 this->UpdateData(FALSE);
941 this->m_ctrlPull.SetCurrentEntry(this->m_regPullButton);
942 this->m_ctrlPush.SetCurrentEntry(this->m_regPushButton);
943 this->m_ctrlSubmodule.SetCurrentEntry(this->m_regSubmoduleButton);
945 CString sWindowTitle;
946 GetWindowText(sWindowTitle);
947 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
949 EnableSaveRestore(_T("SyncDlg"));
951 m_ctrlURL.SetCaseSensitive(TRUE);
952 m_ctrlURL.SetURLHistory(true);
953 this->m_ctrlURL.LoadHistory(CString(_T("Software\\TortoiseGit\\History\\SyncURL\\"))+WorkingDir, _T("url"));
955 STRING_VECTOR list;
957 if(!g_Git.GetRemoteList(list))
959 for (unsigned int i = 0; i < list.size(); ++i)
961 m_ctrlURL.AddString(list[i]);
964 m_ctrlURL.SetCurSel(0);
965 m_ctrlRemoteBranch.SetCurSel(0);
967 this->LoadBranchInfo();
969 this->m_bInited=true;
970 FetchOutList();
972 m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,false);
973 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,false);
974 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
975 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT-1,false);
976 m_ctrlTabCtrl.ShowTab(IDC_CMD_GIT_PROG-1, false);
977 m_ctrlTabCtrl.ShowTab(IDC_REFLIST-1, false);
979 m_ctrlRemoteBranch.m_bWantReturn = TRUE;
980 m_ctrlURL.m_bWantReturn = TRUE;
982 this->m_Gitverion = CAppUtils::GetMsysgitVersion();
984 if (m_seq > 0 && (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\SyncDialogRandomPos")))
986 m_seq %= 5;
987 RECT rect;
988 GetWindowRect(&rect);
989 rect.top -= m_seq * 30;
990 rect.bottom -= m_seq * 30;
991 if (rect.top < 0)
993 rect.top += 150;
994 rect.bottom += 150;
996 MoveWindow(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
999 return TRUE; // return TRUE unless you set the focus to a control
1000 // EXCEPTION: OCX Property Pages should return FALSE
1003 void CSyncDlg::OnBnClickedButtonManage()
1005 CAppUtils::LaunchRemoteSetting();
1006 Refresh();
1009 void CSyncDlg::Refresh()
1011 theApp.DoWaitCursor(1);
1013 int lastSelected = m_ctrlURL.GetCurSel();
1014 CString url;
1015 this->m_ctrlURL.GetWindowText(url);
1017 this->m_ctrlURL.Reset();
1018 CString workingDir = g_Git.m_CurrentDir;
1019 workingDir.Replace(_T(':'), _T('_'));
1020 this->m_ctrlURL.LoadHistory(_T("Software\\TortoiseGit\\History\\SyncURL\\") + workingDir, _T("url"));
1022 STRING_VECTOR list;
1023 bool found = false;
1024 if (!g_Git.GetRemoteList(list))
1026 for (size_t i = 0; i < list.size(); ++i)
1028 m_ctrlURL.AddString(list[i]);
1029 if (list[i] == url)
1030 found = true;
1033 if (lastSelected >= 0 && !found)
1035 m_ctrlURL.SetCurSel(0);
1036 m_ctrlURL.GetWindowText(url);
1039 CString local;
1040 CString remote;
1041 this->m_ctrlLocalBranch.GetWindowText(local);
1042 this->m_ctrlRemoteBranch.GetWindowText(remote);
1044 this->LoadBranchInfo();
1046 this->m_ctrlLocalBranch.AddString(local);
1047 this->m_ctrlRemoteBranch.AddString(remote);
1048 this->m_ctrlURL.AddString(url);
1050 m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REFRESHING)));
1051 this->FetchOutList(true);
1052 theApp.DoWaitCursor(-1);
1055 BOOL CSyncDlg::PreTranslateMessage(MSG* pMsg)
1057 if (pMsg->message == WM_KEYDOWN)
1059 switch (pMsg->wParam)
1062 case VK_F5:
1064 if (m_bBlock)
1065 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
1066 Refresh();
1068 break;
1070 /* Avoid TAB control destroy but dialog exist*/
1071 case VK_ESCAPE:
1072 case VK_CANCEL:
1074 TCHAR buff[128] = { 0 };
1075 ::GetClassName(pMsg->hwnd,buff,128);
1077 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
1078 if (_tcsnicmp(buff, MSFTEDIT_CLASS, 128) == 0 || //Unicode and MFC 2012 and later
1079 _tcsnicmp(buff, RICHEDIT_CLASS, 128) == 0 || //ANSI or MFC 2010
1080 _tcsnicmp(buff, _T("SysListView32"), 128) == 0)
1082 this->PostMessage(WM_KEYDOWN,VK_ESCAPE,0);
1083 return TRUE;
1088 m_tooltips.RelayEvent(pMsg);
1089 return __super::PreTranslateMessage(pMsg);
1091 void CSyncDlg::FetchOutList(bool force)
1093 if(!m_bInited)
1094 return;
1095 m_OutChangeFileList.Clear();
1096 this->m_OutLogList.Clear();
1098 CString remote;
1099 this->m_ctrlURL.GetWindowText(remote);
1100 CString remotebranch;
1101 this->m_ctrlRemoteBranch.GetWindowText(remotebranch);
1102 remotebranch=remote+_T("/")+remotebranch;
1103 CGitHash remotebranchHash;
1104 g_Git.GetHash(remotebranchHash, remotebranch);
1106 if(IsURL())
1108 CString str;
1109 str.LoadString(IDS_PROC_SYNC_PUSH_UNKNOWN);
1110 m_OutLogList.ShowText(str);
1111 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1112 m_OutLocalBranch.Empty();
1113 m_OutRemoteBranch.Empty();
1115 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1116 return ;
1119 else if(remotebranchHash.IsEmpty())
1121 CString str;
1122 str.Format(IDS_PROC_SYNC_PUSH_UNKNOWNBRANCH, remotebranch);
1123 m_OutLogList.ShowText(str);
1124 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1125 m_OutLocalBranch.Empty();
1126 m_OutRemoteBranch.Empty();
1128 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1129 return ;
1131 else
1133 CString localbranch;
1134 localbranch=this->m_ctrlLocalBranch.GetString();
1136 if(localbranch != m_OutLocalBranch || m_OutRemoteBranch != remotebranch || force)
1138 m_OutLogList.ClearText();
1140 CGitHash base, localBranchHash;
1141 bool isFastForward = g_Git.IsFastForward(remotebranch, localbranch, &base);
1143 if (g_Git.GetHash(localBranchHash, localbranch))
1145 MessageBox(g_Git.GetGitLastErr(_T("Could not get hash of \"") + localbranch + _T("\".")), _T("TortoiseGit"), MB_ICONERROR);
1146 return;
1148 if (remotebranchHash == localBranchHash)
1150 CString str;
1151 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, 0, remotebranch);
1152 m_OutLogList.ShowText(str);
1153 this->m_ctrlStatus.SetWindowText(str);
1154 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1155 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1157 else if (isFastForward || m_bForce)
1159 CString range;
1160 range.Format(_T("%s..%s"), g_Git.FixBranchName(remotebranch), g_Git.FixBranchName(localbranch));
1161 //fast forward
1162 m_OutLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT | CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
1163 CString str;
1164 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, m_OutLogList.GetItemCount(), remotebranch);
1165 this->m_ctrlStatus.SetWindowText(str);
1167 if (isFastForward)
1168 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, remotebranch);
1169 else
1171 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, base.ToString());
1174 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,TRUE);
1175 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(TRUE);
1177 else
1179 CString str;
1180 str.Format(IDS_PROC_SYNC_NOFASTFORWARD, localbranch, remotebranch);
1181 m_OutLogList.ShowText(str);
1182 this->m_ctrlStatus.SetWindowText(str);
1183 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID() - 1, FALSE);
1184 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1187 this->m_OutLocalBranch=localbranch;
1188 this->m_OutRemoteBranch=remotebranch;
1193 bool CSyncDlg::IsURL()
1195 CString str;
1196 this->m_ctrlURL.GetWindowText(str);
1197 if(str.Find(_T('\\'))>=0 || str.Find(_T('/'))>=0)
1198 return true;
1199 else
1200 return false;
1202 void CSyncDlg::OnCbnEditchangeComboboxex()
1204 SetTimer(IDT_INPUT, 1000, NULL);
1205 this->m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_WAINTINPUT)));
1207 //this->FetchOutList();
1210 UINT CSyncDlg::ProgressThread()
1212 m_startTick = GetTickCount();
1213 m_bDone = false;
1214 STRING_VECTOR list;
1215 CProgressDlg::RunCmdList(this, m_GitCmdList, list, true, nullptr, &this->m_bAbort, &this->m_Databuf);
1216 InterlockedExchange(&m_bBlock, FALSE);
1217 return 0;
1221 LRESULT CSyncDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
1223 if(wParam == MSG_PROGRESSDLG_START)
1225 m_BufStart = 0;
1226 m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
1227 this->m_ctrlProgress.SetPos(0);
1228 if (m_pTaskbarList)
1230 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
1231 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 100);
1235 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
1237 DWORD tickSpent = GetTickCount() - m_startTick;
1238 CString strEndTime = CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE, true, false);
1240 m_BufStart = 0;
1241 m_Databuf.m_critSec.Lock();
1242 m_Databuf.clear();
1243 m_Databuf.m_critSec.Unlock();
1245 m_bDone = true;
1246 m_ctrlAnimate.Stop();
1247 m_ctrlProgress.SetPos(100);
1248 //this->DialogEnableWindow(IDOK,TRUE);
1250 DWORD exitCode = (DWORD)lParam;
1251 if (exitCode)
1253 if (m_pTaskbarList)
1255 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
1256 m_pTaskbarList->SetProgressValue(m_hWnd, 100, 100);
1258 CString log;
1259 log.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT, exitCode);
1260 CString err;
1261 err.Format(_T("\r\n\r\n%s (%lu ms @ %s)\r\n"), log, tickSpent, strEndTime);
1262 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, err, RGB(255,0,0));
1263 CSoundUtils::PlayTGitError();
1265 else
1267 if (m_pTaskbarList)
1268 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
1269 CString temp;
1270 temp.LoadString(IDS_SUCCESS);
1271 CString log;
1272 log.Format(_T("\r\n%s (%lu ms @ %s)\r\n"), temp, tickSpent, strEndTime);
1273 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, log, RGB(0,0,255));
1275 m_GitCmdStatus = exitCode;
1277 //if(wParam == MSG_PROGRESSDLG_END)
1278 RunPostAction();
1281 if(lParam != 0)
1282 ParserCmdOutput((char)lParam);
1283 else
1285 m_Databuf.m_critSec.Lock();
1286 for (size_t i = m_BufStart; i < m_Databuf.size(); ++i)
1288 char c = m_Databuf[m_BufStart];
1289 ++m_BufStart;
1290 m_Databuf.m_critSec.Unlock();
1291 ParserCmdOutput(c);
1293 m_Databuf.m_critSec.Lock();
1296 if (m_BufStart > 1000)
1298 m_Databuf.erase(m_Databuf.begin(), m_Databuf.begin() + m_BufStart);
1299 m_BufStart = 0;
1301 m_Databuf.m_critSec.Unlock();
1304 return 0;
1307 static std::map<CString, CGitHash> * HashMapToRefMap(MAP_HASH_NAME &map)
1309 auto rmap = new std::map<CString, CGitHash>();
1310 for (auto mit = map.begin(); mit != map.end(); ++mit)
1312 for (auto rit = mit->second.begin(); rit != mit->second.end(); ++rit)
1314 rmap->insert(std::make_pair(*rit, mit->first));
1317 return rmap;
1320 void CSyncDlg::FillNewRefMap()
1322 m_refList.Clear();
1323 m_newHashMap.clear();
1324 CAutoRepository repo(g_Git.GetGitRepository());
1325 if (!repo)
1327 CMessageBox::Show(m_hWnd, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
1328 return;
1331 if (CGit::GetMapHashToFriendName(repo, m_newHashMap))
1333 MessageBox(CGit::GetLibGit2LastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR);
1334 return;
1337 auto oldRefMap = HashMapToRefMap(m_oldHashMap);
1338 auto newRefMap = HashMapToRefMap(m_newHashMap);
1339 for (auto oit = oldRefMap->begin(); oit != oldRefMap->end(); ++oit)
1341 bool found = false;
1342 for (auto nit = newRefMap->begin(); nit != newRefMap->end(); ++nit)
1344 // changed ref
1345 if (oit->first == nit->first)
1347 found = true;
1348 m_refList.AddEntry(repo, oit->first, &oit->second, &nit->second);
1349 break;
1352 // deleted ref
1353 if (!found)
1355 m_refList.AddEntry(repo, oit->first, &oit->second, nullptr);
1358 for (auto nit = newRefMap->begin(); nit != newRefMap->end(); ++nit)
1360 bool found = false;
1361 for (auto oit = oldRefMap->begin(); oit != oldRefMap->end(); ++oit)
1363 if (oit->first == nit->first)
1365 found = true;
1366 break;
1369 // new ref
1370 if (!found)
1372 m_refList.AddEntry(repo, nit->first, nullptr, &nit->second);
1375 delete oldRefMap;
1376 delete newRefMap;
1377 m_refList.Show();
1380 void CSyncDlg::RunPostAction()
1382 if (m_bWantToExit)
1383 return;
1385 FillNewRefMap();
1387 if (this->m_CurrentCmd == GIT_COMMAND_PUSH)
1389 DWORD exitcode = 0xFFFFFFFF;
1390 CString error;
1391 if (CHooks::Instance().PostPush(g_Git.m_CurrentDir, exitcode, error))
1393 if (exitcode)
1395 CString temp;
1396 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
1397 CMessageBox::Show(nullptr, temp,_T("TortoiseGit"), MB_OK | MB_ICONERROR);
1398 return;
1402 EnableControlButton(true);
1403 SwitchToInput();
1404 this->FetchOutList(true);
1406 else if (this->m_CurrentCmd == GIT_COMMAND_PULL)
1408 PullComplete();
1410 else if (this->m_CurrentCmd == GIT_COMMAND_FETCH || this->m_CurrentCmd == GIT_COMMAND_FETCHANDREBASE)
1412 FetchComplete();
1414 else if (this->m_CurrentCmd == GIT_COMMAND_SUBMODULE)
1416 //this->m_ctrlCmdOut.SetSel(-1,-1);
1417 //this->m_ctrlCmdOut.ReplaceSel(_T("Done\r\n"));
1418 //this->m_ctrlCmdOut.SetSel(-1,-1);
1419 EnableControlButton(true);
1420 SwitchToInput();
1422 else if (this->m_CurrentCmd == GIT_COMMAND_STASH)
1424 StashComplete();
1426 else if (this->m_CurrentCmd == GIT_COMMAND_REMOTE)
1428 this->FetchOutList(true);
1429 EnableControlButton(true);
1430 SwitchToInput();
1431 ShowTab(IDC_REFLIST);
1434 void CSyncDlg::ParserCmdOutput(char ch)
1436 CProgressDlg::ParserCmdOutput(m_ctrlCmdOut,m_ctrlProgress,m_hWnd,m_pTaskbarList,m_LogText,ch);
1438 void CSyncDlg::OnBnClickedButtonCommit()
1440 CString cmd = _T("/command:commit");
1441 cmd += _T(" /path:\"");
1442 cmd += g_Git.m_CurrentDir;
1443 cmd += _T("\"");
1445 CAppUtils::RunTortoiseGitProc(cmd);
1448 void CSyncDlg::OnOK()
1450 UpdateCombox();
1451 this->UpdateData();
1452 m_ctrlURL.SaveHistory();
1453 SaveHistory();
1454 m_regAutoLoadPutty = this->m_bAutoLoadPuttyKey;
1455 m_tooltips.Pop();
1456 __super::OnOK();
1459 void CSyncDlg::OnCancel()
1461 m_bAbort = true;
1462 if (m_bDone)
1464 CResizableStandAloneDialog::OnCancel();
1465 return;
1468 if (g_Git.m_CurrentGitPi.hProcess)
1470 DWORD dwConfirmKillProcess = CRegDWORD(_T("Software\\TortoiseGit\\ConfirmKillProcess"));
1471 if (dwConfirmKillProcess && CMessageBox::Show(m_hWnd, IDS_PROC_CONFIRMKILLPROCESS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION) != IDYES)
1472 return;
1473 if (::GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))
1475 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess, 10000);
1477 else
1479 GetLastError();
1482 CProgressDlg::KillProcessTree(g_Git.m_CurrentGitPi.dwProcessId);
1485 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
1486 m_tooltips.Pop();
1487 CResizableStandAloneDialog::OnCancel();
1490 void CSyncDlg::OnBnClickedButtonSubmodule()
1492 this->UpdateData();
1493 UpdateCombox();
1494 m_ctrlCmdOut.SetWindowTextW(_T(""));
1495 m_LogText = "";
1497 this->m_regSubmoduleButton = (DWORD)this->m_ctrlSubmodule.GetCurrentEntry();
1499 this->SwitchToRun();
1501 this->m_bAbort=false;
1502 this->m_GitCmdList.clear();
1504 ShowTab(IDC_CMD_LOG);
1506 CString cmd;
1508 switch (m_ctrlSubmodule.GetCurrentEntry())
1510 case 0:
1511 cmd=_T("git.exe submodule update --init");
1512 break;
1513 case 1:
1514 cmd=_T("git.exe submodule init");
1515 break;
1516 case 2:
1517 cmd=_T("git.exe submodule sync");
1518 break;
1521 m_GitCmdList.push_back(cmd);
1523 m_CurrentCmd = GIT_COMMAND_SUBMODULE;
1525 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
1526 if (m_pThread==NULL)
1528 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1530 else
1532 m_pThread->m_bAutoDelete = TRUE;
1533 m_pThread->ResumeThread();
1537 void CSyncDlg::OnBnClickedButtonStash()
1539 UpdateData();
1540 UpdateCombox();
1541 m_ctrlCmdOut.SetWindowTextW(_T(""));
1542 m_LogText = "";
1544 SwitchToRun();
1546 m_bAbort = false;
1547 m_GitCmdList.clear();
1549 ShowTab(IDC_CMD_LOG);
1551 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, false);
1552 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST -1, false);
1553 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT -1, false);
1555 CString cmd;
1556 switch (m_ctrlStash.GetCurrentEntry())
1558 case 0:
1559 cmd = _T("git.exe stash save");
1560 break;
1561 case 1:
1562 cmd = _T("git.exe stash pop");
1563 break;
1564 case 2:
1565 cmd = _T("git.exe stash apply");
1566 break;
1569 m_GitCmdList.push_back(cmd);
1570 m_CurrentCmd = GIT_COMMAND_STASH;
1572 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
1573 if (!m_pThread)
1575 //ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1577 else
1579 m_pThread->m_bAutoDelete = TRUE;
1580 m_pThread->ResumeThread();
1584 void CSyncDlg::OnTimer(UINT_PTR nIDEvent)
1586 if( nIDEvent == IDT_INPUT)
1588 KillTimer(IDT_INPUT);
1589 this->FetchOutList(true);
1594 void CSyncDlg::OnLvnInLogListColumnClick(NMHDR * /* pNMHDR */, LRESULT *pResult)
1596 *pResult = 0;
1599 LRESULT CSyncDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
1601 m_pTaskbarList.Release();
1602 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
1603 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
1604 SetUUIDOverlayIcon(m_hWnd);
1605 return 0;
1608 void CSyncDlg::OnBnClickedCheckForce()
1610 UpdateData();
1613 void CSyncDlg::OnBnClickedLog()
1615 CString cmd = _T("/command:log");
1616 cmd += _T(" /path:\"");
1617 cmd += g_Git.m_CurrentDir;
1618 cmd += _T("\"");
1620 CAppUtils::RunTortoiseGitProc(cmd);
1623 LRESULT CSyncDlg::OnProgCmdFinish(WPARAM /*wParam*/, LPARAM /*lParam*/)
1625 RefreshCursor();
1626 RunPostAction();
1627 return 0;
1630 void CSyncDlg::OnDestroy()
1632 m_bWantToExit = true;
1633 __super::OnDestroy();