1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2021 - 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
24 #include "TortoiseProc.h"
27 #include "ProgressDlg.h"
28 #include "MessageBox.h"
29 #include "ImportPatchDlg.h"
30 #include "RebaseDlg.h"
32 #include "SmartHandle.h"
33 #include "ProgressCommands/FetchProgressCommand.h"
34 #include "SyncTabCtrl.h"
35 #include "SysProgressDlg.h"
36 #include "ThemeMFCVisualManager.h"
40 IMPLEMENT_DYNAMIC(CSyncDlg
, CResizableStandAloneDialog
)
42 CSyncDlg::CSyncDlg(CWnd
* pParent
/*=nullptr*/)
43 : CResizableStandAloneDialog(CSyncDlg::IDD
, pParent
)
47 , m_CmdOutCurrentPos(0)
48 , m_bAutoLoadPuttyKey(CAppUtils::IsSSHPutty())
49 , m_bForce(BST_UNCHECKED
)
55 , m_bWantToExit(false)
57 , m_startTick(GetTickCount64())
60 m_pTooltip
= &m_tooltips
;
67 void CSyncDlg::DoDataExchange(CDataExchange
* pDX
)
69 CDialog::DoDataExchange(pDX
);
70 DDX_Check(pDX
, IDC_CHECK_PUTTY_KEY
, m_bAutoLoadPuttyKey
);
71 DDX_Check(pDX
, IDC_CHECK_FORCE
,m_bForce
);
72 DDX_Control(pDX
, IDC_COMBOBOXEX_URL
, m_ctrlURL
);
73 DDX_Control(pDX
, IDC_BUTTON_TABCTRL
, m_ctrlDumyButton
);
74 DDX_Control(pDX
, IDC_BUTTON_PULL
, m_ctrlPull
);
75 DDX_Control(pDX
, IDC_BUTTON_PUSH
, m_ctrlPush
);
76 DDX_Control(pDX
, IDC_STATIC_STATUS
, m_ctrlStatus
);
77 DDX_Control(pDX
, IDC_PROGRESS_SYNC
, m_ctrlProgress
);
78 DDX_Control(pDX
, IDC_ANIMATE_SYNC
, m_ctrlAnimate
);
79 DDX_Control(pDX
, IDC_BUTTON_SUBMODULE
,m_ctrlSubmodule
);
80 DDX_Control(pDX
, IDC_BUTTON_STASH
, m_ctrlStash
);
81 DDX_Control(pDX
, IDC_PROG_LABEL
, m_ctrlProgLabel
);
85 BEGIN_MESSAGE_MAP(CSyncDlg
, CResizableStandAloneDialog
)
86 ON_BN_CLICKED(IDC_BUTTON_PULL
, &CSyncDlg::OnBnClickedButtonPull
)
87 ON_BN_CLICKED(IDC_BUTTON_PUSH
, &CSyncDlg::OnBnClickedButtonPush
)
88 ON_BN_CLICKED(IDC_BUTTON_APPLY
, &CSyncDlg::OnBnClickedButtonApply
)
89 ON_BN_CLICKED(IDC_BUTTON_EMAIL
, &CSyncDlg::OnBnClickedButtonEmail
)
90 ON_BN_CLICKED(IDC_BUTTON_MANAGE
, &CSyncDlg::OnBnClickedButtonManage
)
92 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_URL
, &CSyncDlg::OnCbnEditchangeComboboxex
)
93 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_REMOTE_BRANCH
, &CSyncDlg::OnCbnEditchangeComboboxex
)
94 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI
, OnProgressUpdateUI
)
95 ON_MESSAGE(WM_PROG_CMD_FINISH
, OnProgCmdFinish
)
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
)
100 ON_REGISTERED_MESSAGE(TaskBarButtonCreated
, OnTaskbarBtnCreated
)
101 ON_BN_CLICKED(IDC_CHECK_FORCE
, &CSyncDlg::OnBnClickedCheckForce
)
102 ON_BN_CLICKED(IDC_LOG
, &CSyncDlg::OnBnClickedLog
)
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 bool CSyncDlg::AskSetTrackedBranch()
120 CString remote
, remoteBranch
;
121 g_Git
.GetRemoteTrackedBranch(m_strLocalBranch
, remote
, remoteBranch
);
122 if (remoteBranch
.IsEmpty())
124 remoteBranch
= m_strRemoteBranch
;
125 if (remoteBranch
.IsEmpty())
126 remoteBranch
= m_strLocalBranch
;
128 temp
.FormatMessage(IDS_NOTYET_SETTRACKEDBRANCH
, static_cast<LPCWSTR
>(m_strLocalBranch
), static_cast<LPCWSTR
>(remoteBranch
));
129 BOOL dontShowAgain
= FALSE
;
130 auto ret
= CMessageBox::ShowCheck(GetSafeHwnd(), temp
, L
"TortoiseGit", MB_ICONQUESTION
| MB_YESNOCANCEL
, nullptr, CString(MAKEINTRESOURCE(IDS_MSGBOX_DONOTSHOW
)), &dontShowAgain
);
132 CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch") = FALSE
;
138 key
.Format(L
"branch.%s.remote", static_cast<LPCWSTR
>(m_strLocalBranch
));
139 g_Git
.SetConfigValue(key
, m_strURL
);
140 key
.Format(L
"branch.%s.merge", static_cast<LPCWSTR
>(m_strLocalBranch
));
141 g_Git
.SetConfigValue(key
, L
"refs/heads/" + g_Git
.StripRefName(remoteBranch
));
147 void CSyncDlg::OnBnClickedButtonPull()
149 bool bShift
= (GetAsyncKeyState(VK_SHIFT
) & 0x8000) != 0;
151 int CurrentEntry
= static_cast<int>(this->m_ctrlPull
.GetCurrentEntry());
152 this->m_regPullButton
= CurrentEntry
;
154 if (bShift
&& CurrentEntry
> 1)
157 this->m_bAbort
=false;
158 this->m_GitCmdList
.clear();
159 m_ctrlCmdOut
.SetWindowText(L
"");
165 if (g_Git
.GetHash(m_oldHash
, L
"HEAD"))
167 MessageBox(g_Git
.GetGitLastErr(L
"Could not get HEAD hash."), L
"TortoiseGit", MB_ICONERROR
);
172 m_newHashMap
.clear();
173 m_oldHashMap
.clear();
175 if( CurrentEntry
== 0)
177 CGitHash localBranchHash
;
178 if (g_Git
.GetHash(localBranchHash
, m_strLocalBranch
))
180 MessageBox(g_Git
.GetGitLastErr(L
"Could not get hash of \"" + m_strLocalBranch
+ L
"\"."), L
"TortoiseGit", MB_ICONERROR
);
183 if (localBranchHash
!= m_oldHash
|| m_strLocalBranch
!= g_Git
.GetCurrentBranch())
186 tmp
.Format(IDS_PROC_SYNC_SWITCHTO
, static_cast<LPCWSTR
>(m_strLocalBranch
));
187 if (CMessageBox::Show(GetSafeHwnd(), CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULLWRONGBRANCH
)), L
"TortoiseGit", 2, IDI_QUESTION
, tmp
, CString(MAKEINTRESOURCE(IDS_ABORTBUTTON
))) == 2)
191 cmd
.Format(L
"git.exe checkout %s --", static_cast<LPCWSTR
>(m_strLocalBranch
));
193 CProgressDlg
progress(this);
194 progress
.m_AutoClose
= AUTOCLOSE_IF_NO_ERRORS
;
195 progress
.m_GitCmd
= cmd
;
196 if (progress
.DoModal() != IDOK
|| progress
.m_GitStatus
!= 0)
201 if(this->m_strURL
.IsEmpty())
203 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
207 if (CurrentEntry
== 6)
210 m_ctrlTabCtrl
.ShowTab(IDC_LOG
- 1, false);
211 m_ctrlTabCtrl
.ShowTab(IDC_REFLIST
- 1, false);
212 m_ctrlTabCtrl
.ShowTab(IDC_OUT_LOGLIST
- 1, false);
213 m_ctrlTabCtrl
.ShowTab(IDC_OUT_CHANGELIST
- 1, false);
214 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, false);
215 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, false);
216 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
- 1, false);
217 m_ctrlTabCtrl
.ShowTab(IDC_TAGCOMPARELIST
- 1, true);
219 CSysProgressDlg sysProgressDlg
;
220 sysProgressDlg
.SetTitle(CString(MAKEINTRESOURCE(IDS_APPNAME
)));
221 sysProgressDlg
.SetLine(1, CString(MAKEINTRESOURCE(IDS_LOADING
)));
222 sysProgressDlg
.SetLine(2, CString(MAKEINTRESOURCE(IDS_PROGRESSWAIT
)));
223 sysProgressDlg
.SetShowProgressBar(false);
224 sysProgressDlg
.ShowModal(this, true);
226 auto ret
= m_tagCompareList
.Fill(m_strURL
, err
);
227 sysProgressDlg
.Stop();
229 MessageBox(err
, L
"TortoiseGit", MB_ICONERROR
);
233 EnableControlButton();
237 if (!IsURL() && !m_strRemoteBranch
.IsEmpty() && CurrentEntry
== 0 && CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE
) == TRUE
)
239 if (!AskSetTrackedBranch())
243 if (m_bAutoLoadPuttyKey
&& CurrentEntry
!= 4) // CurrentEntry (Remote Update) handles this on its own)
245 CAppUtils::LaunchPAgent(this->GetSafeHwnd(), nullptr, &m_strURL
);
248 if (g_Git
.GetMapHashToFriendName(m_oldHashMap
))
249 MessageBox(g_Git
.GetGitLastErr(L
"Could not get all refs."), L
"TortoiseGit", MB_ICONERROR
);
251 if (bShift
&& (CurrentEntry
== 0 || CurrentEntry
== 1))
253 if (CurrentEntry
== 1 || CurrentEntry
== 2 || CurrentEntry
== 3)
254 CAppUtils::Fetch(GetSafeHwnd(), !IsURL() ? m_strURL
: L
"");
256 CAppUtils::Pull(GetSafeHwnd());
261 int hasConflicts
= g_Git
.HasWorkingTreeConflicts();
262 if (hasConflicts
< 0)
264 this->m_ctrlCmdOut
.SetSel(-1, -1);
265 this->m_ctrlCmdOut
.ReplaceSel(g_Git
.GetGitLastErr(L
"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS
));
267 this->ShowTab(IDC_CMD_LOG
);
273 this->m_ConflictFileList
.Clear();
274 this->m_ConflictFileList
.GetStatus(nullptr, true);
275 this->m_ConflictFileList
.Show(CTGitPath::LOGACTIONS_UNMERGED
,
276 CTGitPath::LOGACTIONS_UNMERGED
);
278 this->ShowTab(IDC_IN_CONFLICT
);
279 CMessageBox::ShowCheck(GetSafeHwnd(), IDS_NEED_TO_RESOLVE_CONFLICTS_HINT
, IDS_APPNAME
, MB_ICONINFORMATION
, L
"MergeConflictsNeedsCommit", IDS_MSGBOX_DONOTSHOWAGAIN
);
282 ShowInCommits(L
"HEAD");
294 if (CurrentEntry
== 0) // check whether we need to override Pull if pull.rebase is set
296 CAutoRepository
repo(g_Git
.GetGitRepository());
298 MessageBox(CGit::GetLibGit2LastErr(L
"Could not open repository."), L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
300 // Check config branch.<name>.rebase and pull.reabse
306 if (git_repository_head_detached(repo
) == 1)
309 CAutoConfig
config(true);
310 if (git_repository_config(config
.GetPointer(), repo
))
313 // branch.<name>.rebase overrides pull.rebase
314 if (config
.GetBOOL(L
"branch." + g_Git
.GetCurrentBranch() + L
".rebase", m_iPullRebase
) == GIT_ENOTFOUND
)
316 if (config
.GetBOOL(L
"pull.rebase", m_iPullRebase
) == GIT_ENOTFOUND
)
321 config
.GetString(L
"pull.rebase", value
);
322 if (value
== L
"preserve")
332 config
.GetString(L
"branch." + g_Git
.GetCurrentBranch() + L
".rebase", value
);
333 if (value
== L
"preserve")
340 if (m_iPullRebase
> 0)
343 if (m_strRemoteBranch
.IsEmpty())
345 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_PULL_EMPTYBRANCH
, IDS_APPNAME
, MB_ICONEXCLAMATION
);
353 ShowTab(IDC_CMD_LOG
);
355 m_ctrlTabCtrl
.ShowTab(IDC_REFLIST
- 1, true);
356 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, false);
357 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, false);
358 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
- 1, false);
359 m_ctrlTabCtrl
.ShowTab(IDC_TAGCOMPARELIST
- 1, false);
362 if(CurrentEntry
== 0) //Pull
364 CString remotebranch
;
365 remotebranch
= m_strRemoteBranch
;
369 CString pullRemote
, pullBranch
;
370 g_Git
.GetRemoteTrackedBranch(m_strLocalBranch
, pullRemote
, pullBranch
);
371 if(pullBranch
== remotebranch
&& pullRemote
== this->m_strURL
)
372 remotebranch
.Empty();
375 cmd
.Format(L
"git.exe pull -v --progress%s \"%s\" %s",
376 static_cast<LPCWSTR
>(force
),
377 static_cast<LPCWSTR
>(m_strURL
),
378 static_cast<LPCWSTR
>(remotebranch
));
380 m_CurrentCmd
= GIT_COMMAND_PULL
;
381 m_GitCmdList
.push_back(cmd
);
387 if (CurrentEntry
== 1 || CurrentEntry
== 2 || CurrentEntry
== 3)
389 m_oldRemoteHash
.Empty();
390 CString remotebranch
;
391 if (CurrentEntry
== 3)
392 m_strRemoteBranch
.Empty();
393 else if (IsURL() || m_strRemoteBranch
.IsEmpty())
395 remotebranch
=this->m_strRemoteBranch
;
400 remotebranch
.Format(L
"remotes/%s/%s", static_cast<LPCWSTR
>(m_strURL
), static_cast<LPCWSTR
>(m_strRemoteBranch
));
401 g_Git
.GetHash(m_oldRemoteHash
, remotebranch
);
402 if (m_oldRemoteHash
.IsEmpty())
403 remotebranch
=m_strRemoteBranch
;
405 remotebranch
= m_strRemoteBranch
+ L
':' + remotebranch
;
408 if (CurrentEntry
== 1 || CurrentEntry
== 3)
409 m_CurrentCmd
= GIT_COMMAND_FETCH
;
411 m_CurrentCmd
= GIT_COMMAND_FETCHANDREBASE
;
413 if (g_Git
.UsingLibGit2(CGit::GIT_CMD_FETCH
))
416 if (!remotebranch
.IsEmpty())
417 refspec
.Format(L
"refs/heads/%s:refs/remotes/%s/%s", static_cast<LPCWSTR
>(m_strRemoteBranch
), static_cast<LPCWSTR
>(m_strURL
), static_cast<LPCWSTR
>(m_strRemoteBranch
));
419 progressCommand
= std::make_unique
<FetchProgressCommand
>();
420 FetchProgressCommand
* fetchProgressCommand
= static_cast<FetchProgressCommand
*>(progressCommand
.get());
421 fetchProgressCommand
->SetUrl(m_strURL
);
422 fetchProgressCommand
->SetRefSpec(refspec
);
423 m_GitProgressList
.SetCommand(progressCommand
.get());
424 m_GitProgressList
.Init();
425 ShowTab(IDC_CMD_GIT_PROG
);
429 cmd
.Format(L
"git.exe fetch --progress -v%s \"%s\" %s",
430 static_cast<LPCWSTR
>(force
),
431 static_cast<LPCWSTR
>(m_strURL
),
432 static_cast<LPCWSTR
>(remotebranch
));
434 m_GitCmdList
.push_back(cmd
);
441 if (CurrentEntry
== 4)
443 if (m_bAutoLoadPuttyKey
)
445 for (size_t i
= 0; i
< m_remotelist
.size(); ++i
)
446 CAppUtils::LaunchPAgent(this->GetSafeHwnd(), nullptr, &m_remotelist
[i
]);
449 m_CurrentCmd
= GIT_COMMAND_REMOTE
;
450 cmd
= L
"git.exe remote update";
451 m_GitCmdList
.push_back(cmd
);
456 ///Cleanup stale remote banches
457 if (CurrentEntry
== 5)
459 m_CurrentCmd
= GIT_COMMAND_REMOTE
;
460 cmd
.Format(L
"git.exe remote prune \"%s\"", static_cast<LPCWSTR
>(m_strURL
));
461 m_GitCmdList
.push_back(cmd
);
467 void CSyncDlg::ShowInCommits(const CString
& friendname
)
471 if (g_Git
.GetHash(newHash
, friendname
))
473 MessageBox(g_Git
.GetGitLastErr(L
"Could not get " + friendname
+ L
" hash."), L
"TortoiseGit", MB_ICONERROR
);
477 if (newHash
== m_oldHash
)
479 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, false);
480 m_InLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_UPTODATE
)));
481 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, true);
482 ShowTab(IDC_REFLIST
);
486 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, true);
487 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, true);
489 AddDiffFileList(&m_InChangeFileList
, &m_arInChangeList
, newHash
, m_oldHash
);
492 range
.Format(L
"%s..%s", static_cast<LPCWSTR
>(m_oldHash
.ToString()), static_cast<LPCWSTR
>(newHash
.ToString()));
493 m_InLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
494 ShowTab(IDC_IN_LOGLIST
);
498 void CSyncDlg::PullComplete()
500 EnableControlButton(true);
502 this->FetchOutList(true);
504 if( this ->m_GitCmdStatus
)
506 int hasConflicts
= g_Git
.HasWorkingTreeConflicts();
507 if (hasConflicts
< 0)
509 this->m_ctrlCmdOut
.SetSel(-1,-1);
510 this->m_ctrlCmdOut
.ReplaceSel(g_Git
.GetGitLastErr(L
"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS
));
512 this->ShowTab(IDC_CMD_LOG
);
518 this->m_ConflictFileList
.Clear();
519 this->m_ConflictFileList
.GetStatus(nullptr, true);
520 this->m_ConflictFileList
.Show(CTGitPath::LOGACTIONS_UNMERGED
,
521 CTGitPath::LOGACTIONS_UNMERGED
);
523 this->ShowTab(IDC_IN_CONFLICT
);
524 CMessageBox::ShowCheck(GetSafeHwnd(), IDS_NEED_TO_RESOLVE_CONFLICTS_HINT
, IDS_APPNAME
, MB_ICONINFORMATION
, L
"MergeConflictsNeedsCommit", IDS_MSGBOX_DONOTSHOWAGAIN
);
527 this->ShowTab(IDC_CMD_LOG
);
531 ShowInCommits(L
"HEAD");
534 void CSyncDlg::FetchComplete()
536 EnableControlButton(true);
539 if (g_Git
.UsingLibGit2(CGit::GIT_CMD_FETCH
))
540 ShowTab(IDC_CMD_GIT_PROG
);
542 ShowTab(IDC_REFLIST
);
544 if (m_GitCmdStatus
|| (m_CurrentCmd
!= GIT_COMMAND_FETCHANDREBASE
&& m_iPullRebase
== 0))
551 CString remotebranch
;
552 CString upstream
= L
"FETCH_HEAD";
553 m_ctrlURL
.GetWindowText(remote
);
554 if (!remote
.IsEmpty())
556 if (std::find(m_remotelist
.cbegin(), m_remotelist
.cend(), remote
) == m_remotelist
.cend())
559 m_ctrlRemoteBranch
.GetWindowText(remotebranch
);
560 if (!remote
.IsEmpty() && !remotebranch
.IsEmpty())
561 upstream
= L
"remotes/" + remote
+ L
'/' + remotebranch
;
563 if (m_iPullRebase
> 0)
565 CAppUtils::RebaseAfterFetch(GetSafeHwnd(), upstream
, m_iPullRebase
? 2 : 0, m_iPullRebase
== 2);
569 ShowInCommits(L
"HEAD");
574 CGitHash remoteBranchHash
;
575 g_Git
.GetHash(remoteBranchHash
, upstream
);
576 if (remoteBranchHash
== m_oldRemoteHash
&& !m_oldRemoteHash
.IsEmpty() && CMessageBox::ShowCheck(this->GetSafeHwnd(), IDS_REBASE_BRANCH_UNCHANGED
, IDS_APPNAME
, MB_ICONQUESTION
| MB_YESNO
| MB_DEFBUTTON2
, L
"OpenRebaseRemoteBranchUnchanged", IDS_MSGBOX_DONOTSHOWAGAIN
) == IDNO
)
578 ShowInCommits(upstream
);
582 if (g_Git
.IsFastForward(L
"HEAD", upstream
))
584 UINT ret
= CMessageBox::ShowCheck(GetSafeHwnd(), IDS_REBASE_BRANCH_FF
, IDS_APPNAME
, 2, IDI_QUESTION
, IDS_MERGEBUTTON
, IDS_REBASEBUTTON
, IDS_ABORTBUTTON
, L
"OpenRebaseRemoteBranchFastForwards", IDS_MSGBOX_DONOTSHOWAGAIN
);
589 CProgressDlg mergeProgress
;
590 mergeProgress
.m_GitCmd
= L
"git.exe merge --ff-only " + upstream
;
591 mergeProgress
.m_AutoClose
= AUTOCLOSE_IF_NO_ERRORS
;
592 mergeProgress
.m_PostCmdCallback
= [](DWORD status
, PostCmdList
& postCmdList
)
594 if (status
&& g_Git
.HasWorkingTreeConflicts())
596 // there are conflict files
597 postCmdList
.emplace_back(IDI_RESOLVE
, IDS_PROGRS_CMD_RESOLVE
, []
600 sCmd
.Format(L
"/command:commit /path:\"%s\"", static_cast<LPCWSTR
>(g_Git
.m_CurrentDir
));
601 CAppUtils::RunTortoiseGitProc(sCmd
);
605 mergeProgress
.DoModal();
609 ShowInCommits(L
"HEAD");
615 CAppUtils::RebaseAfterFetch(GetSafeHwnd(), upstream
);
619 ShowInCommits(L
"HEAD");
622 void CSyncDlg::StashComplete()
624 EnableControlButton(true);
625 INT_PTR entry
= m_ctrlStash
.GetCurrentEntry();
626 if (entry
!= 1 && entry
!= 2)
632 int hasConflicts
= g_Git
.HasWorkingTreeConflicts();
633 if (hasConflicts
< 0)
635 m_ctrlCmdOut
.SetSel(-1, -1);
636 m_ctrlCmdOut
.ReplaceSel(g_Git
.GetGitLastErr(L
"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS
));
638 ShowTab(IDC_CMD_LOG
);
644 m_ConflictFileList
.Clear();
645 m_ConflictFileList
.GetStatus(nullptr, true);
646 m_ConflictFileList
.Show(CTGitPath::LOGACTIONS_UNMERGED
, CTGitPath::LOGACTIONS_UNMERGED
);
648 ShowTab(IDC_IN_CONFLICT
);
651 ShowTab(IDC_CMD_LOG
);
655 void CSyncDlg::OnBnClickedButtonPush()
657 bool bShift
= (GetAsyncKeyState(VK_SHIFT
) & 0x8000) != 0;
663 if (m_ctrlPush
.GetCurrentEntry() == 0)
665 CAppUtils::Push(GetSafeHwnd(), g_Git
.FixBranchName(m_strLocalBranch
));
672 m_ctrlCmdOut
.SetWindowText(L
"");
675 if(this->m_strURL
.IsEmpty())
677 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
681 if (!IsURL() && m_ctrlPush
.GetCurrentEntry() == 0 && CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE
) == TRUE
)
683 if (!AskSetTrackedBranch())
687 this->m_regPushButton
= static_cast<DWORD
>(this->m_ctrlPush
.GetCurrentEntry());
689 this->m_bAbort
=false;
690 this->m_GitCmdList
.clear();
692 ShowTab(IDC_CMD_LOG
);
698 DWORD exitcode
= 0xFFFFFFFF;
699 CHooks::Instance().SetProjectProperties(g_Git
.m_CurrentDir
, m_ProjectProperties
);
700 if (CHooks::Instance().PrePush(GetSafeHwnd(), g_Git
.m_CurrentDir
, exitcode
, error
))
705 sErrorMsg
.Format(IDS_HOOK_ERRORMSG
, static_cast<LPCWSTR
>(error
));
706 CTaskDialog
taskdlg(sErrorMsg
, CString(MAKEINTRESOURCE(IDS_HOOKFAILED_TASK2
)), L
"TortoiseGit", 0, TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
| TDF_SIZE_TO_CONTENT
);
707 taskdlg
.AddCommandControl(101, CString(MAKEINTRESOURCE(IDS_HOOKFAILED_TASK3
)));
708 taskdlg
.AddCommandControl(102, CString(MAKEINTRESOURCE(IDS_HOOKFAILED_TASK4
)));
709 taskdlg
.SetDefaultCommandControl(101);
710 taskdlg
.SetMainIcon(TD_ERROR_ICON
);
711 if (taskdlg
.DoModal(GetSafeHwnd()) != 102)
716 CString refName
= g_Git
.FixBranchName(m_strLocalBranch
);
717 switch (m_ctrlPush
.GetCurrentEntry())
723 refName
= L
"refs/notes/commits"; //default ref for notes
730 cmd
.Format(L
"git.exe push -v --progress%s \"%s\" %s",
731 static_cast<LPCWSTR
>(arg
),
732 static_cast<LPCWSTR
>(m_strURL
),
733 static_cast<LPCWSTR
>(refName
));
735 if (!m_strRemoteBranch
.IsEmpty() && m_ctrlPush
.GetCurrentEntry() != 2)
737 cmd
+= L
':' + m_strRemoteBranch
;
740 m_GitCmdList
.push_back(cmd
);
742 m_CurrentCmd
= GIT_COMMAND_PUSH
;
744 if(this->m_bAutoLoadPuttyKey
)
746 CAppUtils::LaunchPAgent(this->GetSafeHwnd(), nullptr, &m_strURL
);
752 void CSyncDlg::OnBnClickedButtonApply()
755 if (g_Git
.GetHash(oldhash
, L
"HEAD"))
757 MessageBox(g_Git
.GetGitLastErr(L
"Could not get HEAD hash."), L
"TortoiseGit", MB_ICONERROR
);
764 if(dlg
.DoModal() == IDOK
)
767 for (int i
= 0; i
< dlg
.m_PathList
.GetCount(); ++i
)
769 cmd
.Format(L
"git.exe am \"%s\"", static_cast<LPCWSTR
>(dlg
.m_PathList
[i
].GetGitPathString()));
771 if (g_Git
.Run(cmd
, &output
, CP_UTF8
))
773 CMessageBox::Show(GetSafeHwnd(), output
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
778 this->m_ctrlCmdOut
.SetSel(-1,-1);
779 this->m_ctrlCmdOut
.ReplaceSel(cmd
+ L
'\n');
780 this->m_ctrlCmdOut
.SetSel(-1,-1);
781 this->m_ctrlCmdOut
.ReplaceSel(output
);
785 if (g_Git
.GetHash(newhash
, L
"HEAD"))
787 MessageBox(g_Git
.GetGitLastErr(L
"Could not get HEAD hash after applying patches."), L
"TortoiseGit", MB_ICONERROR
);
791 this->m_InLogList
.Clear();
792 this->m_InChangeFileList
.Clear();
794 if(newhash
== oldhash
)
796 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,false);
797 this->m_InLogList
.ShowText(L
"No commits get from patch");
798 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,true);
803 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,true);
804 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,true);
807 range
.Format(L
"%s..%s", static_cast<LPCWSTR
>(m_oldHash
.ToString()), static_cast<LPCWSTR
>(newhash
.ToString()));
808 this->AddDiffFileList(&m_InChangeFileList
, &m_arInChangeList
, newhash
, oldhash
);
809 m_InLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
811 this->FetchOutList(true);
814 this->m_ctrlTabCtrl
.ShowTab(IDC_CMD_LOG
-1,true);
818 this->ShowTab(IDC_CMD_LOG
);
822 this->ShowTab(IDC_IN_LOGLIST
);
827 void CSyncDlg::OnBnClickedButtonEmail()
829 CString cmd
, out
, err
;
831 this->m_strLocalBranch
= this->m_ctrlLocalBranch
.GetString();
832 this->m_ctrlRemoteBranch
.GetWindowText(this->m_strRemoteBranch
);
833 this->m_ctrlURL
.GetWindowText(this->m_strURL
);
834 m_strURL
=m_strURL
.Trim();
835 m_strRemoteBranch
=m_strRemoteBranch
.Trim();
837 cmd
.Format(L
"git.exe format-patch -o \"%s\" %s/%s..%s",
838 static_cast<LPCWSTR
>(g_Git
.m_CurrentDir
),
839 static_cast<LPCWSTR
>(m_strURL
), static_cast<LPCWSTR
>(m_strRemoteBranch
), static_cast<LPCWSTR
>(g_Git
.FixBranchName(m_strLocalBranch
)));
841 if (g_Git
.Run(cmd
, &out
, &err
, CP_UTF8
))
843 CMessageBox::Show(GetSafeHwnd(), out
+ L
'\n' + err
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
847 CAppUtils::SendPatchMail(GetSafeHwnd(), cmd
, out
);
849 void CSyncDlg::ShowProgressCtrl(bool bShow
)
851 int b
=bShow
?SW_NORMAL
:SW_HIDE
;
852 this->m_ctrlAnimate
.ShowWindow(b
);
853 this->m_ctrlProgress
.ShowWindow(b
);
854 this->m_ctrlProgLabel
.ShowWindow(b
);
855 this->m_ctrlAnimate
.Open(IDR_DOWNLOAD
);
856 if (b
== SW_NORMAL
&& CRegDWORD(L
"Software\\TortoiseGit\\DownloadAnimation", TRUE
) == TRUE
)
857 this->m_ctrlAnimate
.Play(0, UINT_MAX
, UINT_MAX
);
859 this->m_ctrlAnimate
.Stop();
861 void CSyncDlg::ShowInputCtrl(bool bShow
)
863 int b
=bShow
?SW_NORMAL
:SW_HIDE
;
864 this->m_ctrlURL
.ShowWindow(b
);
865 this->m_ctrlLocalBranch
.ShowWindow(b
);
866 this->m_ctrlRemoteBranch
.ShowWindow(b
);
867 this->GetDlgItem(IDC_BUTTON_LOCAL_BRANCH
)->ShowWindow(b
);
868 this->GetDlgItem(IDC_BUTTON_REMOTE_BRANCH
)->ShowWindow(b
);
869 this->GetDlgItem(IDC_STATIC_LOCAL_BRANCH
)->ShowWindow(b
);
870 this->GetDlgItem(IDC_STATIC_REMOTE_BRANCH
)->ShowWindow(b
);
871 this->GetDlgItem(IDC_BUTTON_MANAGE
)->ShowWindow(b
);
872 this->GetDlgItem(IDC_CHECK_PUTTY_KEY
)->ShowWindow(b
);
873 this->GetDlgItem(IDC_CHECK_FORCE
)->ShowWindow(b
);
874 this->GetDlgItem(IDC_STATIC_REMOTE_URL
)->ShowWindow(b
);
876 BOOL
CSyncDlg::OnInitDialog()
878 CResizableStandAloneDialog::OnInitDialog();
879 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
881 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
882 // do this, Explorer would be unable to send that message to our window if we
883 // were running elevated. It's OK to make the call all the time, since if we're
884 // not elevated, this is a no-op.
885 CHANGEFILTERSTRUCT cfs
= { sizeof(CHANGEFILTERSTRUCT
) };
886 typedef BOOL STDAPICALLTYPE
ChangeWindowMessageFilterExDFN(HWND hWnd
, UINT message
, DWORD action
, PCHANGEFILTERSTRUCT pChangeFilterStruct
);
887 CAutoLibrary hUser
= AtlLoadSystemLibraryUsingFullPath(L
"user32.dll");
890 auto pfnChangeWindowMessageFilterEx
= reinterpret_cast<ChangeWindowMessageFilterExDFN
*>(GetProcAddress(hUser
, "ChangeWindowMessageFilterEx"));
891 if (pfnChangeWindowMessageFilterEx
)
892 pfnChangeWindowMessageFilterEx(m_hWnd
, TaskBarButtonCreated
, MSGFLT_ALLOW
, &cfs
);
894 m_pTaskbarList
.Release();
895 if (FAILED(m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
896 m_pTaskbarList
= nullptr;
898 this->GetDlgItem(IDC_CHECK_PUTTY_KEY
)->EnableWindow(CAppUtils::IsSSHPutty());
901 this->m_ctrlAnimate.ShowWindow(SW_NORMAL);
902 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
903 this->m_ctrlAnimate.Play(0,-1,-1);
906 // ------------------ Create Tabctrl -----------
907 CWnd
*pwnd
=this->GetDlgItem(IDC_BUTTON_TABCTRL
);
909 pwnd
->GetWindowRect(&rectDummy
);
910 this->ScreenToClient(rectDummy
);
912 if (CTheme::Instance().IsDarkTheme())
913 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CThemeMFCVisualManager
));
914 if (!m_ctrlTabCtrl
.Create(CTheme::Instance().IsDarkTheme() ? CMFCTabCtrl::STYLE_3D
: CMFCTabCtrl::STYLE_FLAT
, rectDummy
, this, IDC_SYNC_TAB
))
916 TRACE0("Failed to create output tab window\n");
917 return FALSE
; // fail to create
919 m_ctrlTabCtrl
.SetResizeMode(CMFCTabCtrl::RESIZE_NO
);
921 // -------------Create Command Log Ctrl ---------
922 DWORD dwStyle
= ES_MULTILINE
| ES_READONLY
| WS_CHILD
| WS_VISIBLE
| ES_AUTOHSCROLL
| ES_AUTOVSCROLL
|WS_VSCROLL
;
924 if( !m_ctrlCmdOut
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_CMD_LOG
))
926 TRACE0("Failed to create Log commits window\n");
927 return FALSE
; // fail to create
930 // set the font to use in the log message view, configured in the settings dialog
932 CAppUtils::CreateFontForLogs(m_logFont
);
933 m_ctrlCmdOut
.SetFont(&m_logFont
);
934 m_ctrlTabCtrl
.InsertTab(&m_ctrlCmdOut
, CString(MAKEINTRESOURCE(IDS_LOG
)), -1);
935 // make the log message rich edit control send a message when the mouse pointer is over a link
936 m_ctrlCmdOut
.SendMessage(EM_SETEVENTMASK
, NULL
, ENM_LINK
| ENM_SCROLL
);
938 //---------- Create in coming list ctrl -----------
939 dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| LVS_OWNERDATA
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;;
941 if( !m_InLogList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_LOGLIST
))
943 TRACE0("Failed to create output commits window\n");
944 return FALSE
; // fail to create
946 // for some unknown reason, the SetExtendedStyle in OnCreate/PreSubclassWindow is not working here
947 m_InLogList
.SetStyle();
949 m_ctrlTabCtrl
.InsertTab(&m_InLogList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCOMMITS
)), -1);
951 m_InLogList
.m_ColumnRegKey
= L
"SyncIn";
952 m_InLogList
.InsertGitColumn();
954 //----------- Create In Change file list -----------
955 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
957 if( !m_InChangeFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_CHANGELIST
))
959 TRACE0("Failed to create output change files window\n");
960 return FALSE
; // fail to create
962 m_ctrlTabCtrl
.InsertTab(&m_InChangeFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCHANGELIST
)), -1);
964 m_InChangeFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
|GITSLC_COLADD
|GITSLC_COLDEL
, L
"InSyncDlg",
965 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS
) |
966 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS
)), false, false, GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
);
969 //---------- Create Conflict List Ctrl -----------------
970 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
972 if( !m_ConflictFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_CONFLICT
))
974 TRACE0("Failed to create output change files window\n");
975 return FALSE
; // fail to create
977 m_ctrlTabCtrl
.InsertTab(&m_ConflictFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CONFLICTS
)), -1);
979 m_ConflictFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
|GITSLC_COLADD
|GITSLC_COLDEL
, L
"ConflictSyncDlg",
980 (GITSLC_POPEXPLORE
| GITSLC_POPOPEN
| GITSLC_POPSHOWLOG
|
981 GITSLC_POPCONFLICT
|GITSLC_POPRESOLVE
),false);
984 //---------- Create Commit Out List Ctrl---------------
986 dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| LVS_OWNERDATA
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;;
988 if( !m_OutLogList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_OUT_LOGLIST
))
990 TRACE0("Failed to create output commits window\n");
991 return FALSE
; // fail to create
994 // for some unknown reason, the SetExtendedStyle in OnCreate/PreSubclassWindow is not working here
995 m_OutLogList
.SetStyle();
997 m_ctrlTabCtrl
.InsertTab(&m_OutLogList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCOMMITS
)), -1);
999 m_OutLogList
.m_ColumnRegKey
= L
"SyncOut";
1000 m_OutLogList
.InsertGitColumn();
1002 //------------- Create Change File List Control ----------------
1004 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
1006 if( !m_OutChangeFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_OUT_CHANGELIST
))
1008 TRACE0("Failed to create output change files window\n");
1009 return FALSE
; // fail to create
1011 m_ctrlTabCtrl
.InsertTab(&m_OutChangeFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCHANGELIST
)), -1);
1013 m_OutChangeFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
, L
"OutSyncDlg",
1014 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS
) |
1015 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS
)), false, false, GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
);
1017 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| LVS_SINGLESEL
| WS_CHILD
| WS_VISIBLE
;
1018 if (!m_GitProgressList
.Create(dwStyle
| LVS_OWNERDATA
, rectDummy
, &m_ctrlTabCtrl
, IDC_CMD_GIT_PROG
))
1020 TRACE0("Failed to create Git Progress List Window\n");
1021 return FALSE
; // fail to create
1023 m_ctrlTabCtrl
.InsertTab(&m_GitProgressList
, CString(MAKEINTRESOURCE(IDS_LOG
)), -1);
1024 m_GitProgressList
.m_pAnimate
= &m_ctrlAnimate
;
1025 m_GitProgressList
.m_pPostWnd
= this;
1026 m_GitProgressList
.m_pProgressLabelCtrl
= &m_ctrlProgLabel
;
1027 m_GitProgressList
.m_pProgControl
= &m_ctrlProgress
;
1028 m_GitProgressList
.m_pTaskbarList
= m_pTaskbarList
;
1030 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
| LVS_SINGLESEL
;
1031 DWORD exStyle
= LVS_EX_HEADERDRAGDROP
| LVS_EX_DOUBLEBUFFER
| LVS_EX_INFOTIP
;
1032 if (CRegDWORD(L
"Software\\TortoiseGit\\FullRowSelect", TRUE
))
1033 exStyle
|= LVS_EX_FULLROWSELECT
;
1034 if (g_Git
.m_IsUseLibGit2
)
1036 m_refList
.Create(dwStyle
, rectDummy
, &m_ctrlTabCtrl
, IDC_REFLIST
);
1037 m_refList
.SetExtendedStyle(exStyle
);
1039 m_ctrlTabCtrl
.InsertTab(&m_refList
, CString(MAKEINTRESOURCE(IDS_REFLIST
)), -1);
1041 m_tagCompareList
.Create(dwStyle
, rectDummy
, &m_ctrlTabCtrl
, IDC_TAGCOMPARELIST
);
1042 m_tagCompareList
.SetExtendedStyle(exStyle
);
1043 m_tagCompareList
.Init();
1044 m_ctrlTabCtrl
.InsertTab(&m_tagCompareList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_COMPARETAGS
)), -1);
1046 m_ProjectProperties
.ReadProps();
1048 AdjustControlSize(IDC_CHECK_PUTTY_KEY
);
1049 AdjustControlSize(IDC_CHECK_FORCE
);
1051 AddAnchor(IDC_SYNC_TAB
,TOP_LEFT
,BOTTOM_RIGHT
);
1053 AddAnchor(IDC_GROUP_INFO
,TOP_LEFT
,TOP_RIGHT
);
1054 AddAnchor(IDC_COMBOBOXEX_URL
,TOP_LEFT
,TOP_RIGHT
);
1055 AddAnchor(IDC_BUTTON_MANAGE
,TOP_RIGHT
);
1056 AddAnchor(IDC_BUTTON_PULL
,BOTTOM_LEFT
);
1057 AddAnchor(IDC_BUTTON_PUSH
,BOTTOM_LEFT
);
1058 AddAnchor(IDC_BUTTON_SUBMODULE
,BOTTOM_LEFT
);
1059 AddAnchor(IDC_BUTTON_STASH
,BOTTOM_LEFT
);
1060 AddAnchor(IDC_BUTTON_APPLY
,BOTTOM_RIGHT
);
1061 AddAnchor(IDC_BUTTON_EMAIL
,BOTTOM_RIGHT
);
1062 AddAnchor(IDC_PROGRESS_SYNC
,TOP_LEFT
,TOP_RIGHT
);
1063 AddAnchor(IDOK
,BOTTOM_RIGHT
);
1064 AddAnchor(IDHELP
,BOTTOM_RIGHT
);
1065 AddAnchor(IDC_STATIC_STATUS
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
1066 AddAnchor(IDC_ANIMATE_SYNC
,TOP_LEFT
);
1067 AddAnchor(IDC_BUTTON_COMMIT
,BOTTOM_LEFT
);
1068 AddAnchor(IDC_LOG
, BOTTOM_LEFT
);
1070 // do not use BRANCH_COMBOX_ADD_ANCHOR here, we want to have different stylings
1071 AddAnchor(IDC_COMBOBOXEX_LOCAL_BRANCH
, TOP_LEFT
,TOP_CENTER
);
1072 AddAnchor(IDC_COMBOBOXEX_REMOTE_BRANCH
, TOP_CENTER
, TOP_RIGHT
);
1073 AddAnchor(IDC_BUTTON_LOCAL_BRANCH
, TOP_CENTER
);
1074 AddAnchor(IDC_BUTTON_REMOTE_BRANCH
, TOP_RIGHT
);
1075 AddAnchor(IDC_STATIC_REMOTE_BRANCH
, TOP_CENTER
);
1076 AddAnchor(IDC_PROG_LABEL
, TOP_LEFT
);
1078 CString WorkingDir
=g_Git
.m_CurrentDir
;
1079 WorkingDir
.Replace(L
':', L
'_');
1080 m_RegKeyRemoteBranch
= L
"Software\\TortoiseGit\\History\\SyncBranch\\" + WorkingDir
;
1083 this->AddOthersToAnchor();
1085 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSH
)));
1086 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHTAGS
)));
1087 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHNOTES
)));
1089 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULL
)));
1090 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCH
)));
1091 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHREBASE
)));
1092 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHALL
)));
1093 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REMOTEUPDATE
)));
1094 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CLEANUPSTALEBRANCHES
)));
1095 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_COMPARETAGS
)));
1097 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEUPDATE
)));
1098 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEINIT
)));
1099 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULESYNC
)));
1101 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHSAVE
)));
1102 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHPOP
)));
1103 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHAPPLY
)));
1105 WorkingDir
.Replace(L
':', L
'_');
1108 regkey
.Format(L
"Software\\TortoiseGit\\TortoiseProc\\Sync\\%s", static_cast<LPCWSTR
>(WorkingDir
));
1110 this->m_regPullButton
= CRegDWORD(regkey
+ L
"\\Pull", 0);
1111 this->m_regPushButton
= CRegDWORD(regkey
+ L
"\\Push", 0);
1112 this->m_regSubmoduleButton
= CRegDWORD(regkey
+ L
"\\Submodule");
1113 this->m_regAutoLoadPutty
= CRegDWORD(regkey
+ L
"\\AutoLoadPutty", CAppUtils::IsSSHPutty());
1116 this->m_bAutoLoadPuttyKey
= m_regAutoLoadPutty
;
1117 if(!CAppUtils::IsSSHPutty())
1118 m_bAutoLoadPuttyKey
= false;
1119 this->UpdateData(FALSE
);
1121 this->m_ctrlPull
.SetCurrentEntry(this->m_regPullButton
);
1122 this->m_ctrlPush
.SetCurrentEntry(this->m_regPushButton
);
1123 this->m_ctrlSubmodule
.SetCurrentEntry(this->m_regSubmoduleButton
);
1125 CString sWindowTitle
;
1126 GetWindowText(sWindowTitle
);
1127 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
1129 EnableSaveRestore(L
"SyncDlg");
1131 m_ctrlURL
.SetCaseSensitive(TRUE
);
1133 m_ctrlURL
.SetCustomAutoSuggest(true, true, true);
1134 m_ctrlURL
.SetMaxHistoryItems(0x7FFFFFFF);
1135 this->m_ctrlURL
.LoadHistory(L
"Software\\TortoiseGit\\History\\SyncURL\\" + WorkingDir
, L
"url");
1137 m_remotelist
.clear();
1138 if(!g_Git
.GetRemoteList(m_remotelist
))
1140 for (unsigned int i
= 0; i
< m_remotelist
.size(); ++i
)
1142 m_ctrlURL
.AddString(m_remotelist
[i
]);
1145 m_ctrlURL
.SetCurSel(0);
1146 m_ctrlRemoteBranch
.SetCurSel(0);
1148 this->LoadBranchInfo();
1150 this->m_bInited
=true;
1153 m_ctrlTabCtrl
.ShowTab(IDC_CMD_LOG
-1,false);
1154 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,false);
1155 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,false);
1156 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
-1,false);
1157 m_ctrlTabCtrl
.ShowTab(IDC_CMD_GIT_PROG
-1, false);
1158 m_ctrlTabCtrl
.ShowTab(IDC_REFLIST
-1, false);
1159 m_ctrlTabCtrl
.ShowTab(IDC_TAGCOMPARELIST
- 1, false);
1161 m_ctrlRemoteBranch
.m_bWantReturn
= TRUE
;
1162 m_ctrlURL
.m_bWantReturn
= TRUE
;
1164 if (m_seq
> 0 && static_cast<DWORD
>(CRegDWORD(L
"Software\\TortoiseGit\\SyncDialogRandomPos")))
1168 GetWindowRect(&rect
);
1169 rect
.top
-= m_seq
* 30;
1170 rect
.bottom
-= m_seq
* 30;
1173 rect
.top
+= CDPIAware::Instance().ScaleY(150);
1174 rect
.bottom
+= CDPIAware::Instance().ScaleY(150);
1176 MoveWindow(rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
1179 SetTheme(CTheme::Instance().IsDarkTheme());
1181 return TRUE
; // return TRUE unless you set the focus to a control
1182 // EXCEPTION: OCX Property Pages should return FALSE
1185 void CSyncDlg::OnBnClickedButtonManage()
1187 CAppUtils::LaunchRemoteSetting();
1191 void CSyncDlg::Refresh()
1193 theApp
.DoWaitCursor(1);
1195 int lastSelected
= m_ctrlURL
.GetCurSel();
1197 this->m_ctrlURL
.GetWindowText(url
);
1199 this->m_ctrlURL
.Reset();
1200 CString workingDir
= g_Git
.m_CurrentDir
;
1201 workingDir
.Replace(L
':', L
'_');
1202 this->m_ctrlURL
.LoadHistory(L
"Software\\TortoiseGit\\History\\SyncURL\\" + workingDir
, L
"url");
1205 m_remotelist
.clear();
1206 if (!g_Git
.GetRemoteList(m_remotelist
))
1208 for (size_t i
= 0; i
< m_remotelist
.size(); ++i
)
1210 m_ctrlURL
.AddString(m_remotelist
[i
]);
1211 if (m_remotelist
[i
] == url
)
1215 if (lastSelected
>= 0 && !found
)
1217 m_ctrlURL
.SetCurSel(0);
1218 m_ctrlURL
.GetWindowText(url
);
1223 this->m_ctrlLocalBranch
.GetWindowText(local
);
1224 this->m_ctrlRemoteBranch
.GetWindowText(remote
);
1226 this->LoadBranchInfo();
1228 this->m_ctrlLocalBranch
.AddString(local
);
1229 this->m_ctrlRemoteBranch
.AddString(remote
);
1230 this->m_ctrlURL
.AddString(url
);
1232 m_OutLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REFRESHING
)));
1233 this->FetchOutList(true);
1234 theApp
.DoWaitCursor(-1);
1237 BOOL
CSyncDlg::PreTranslateMessage(MSG
* pMsg
)
1239 if (pMsg
->message
== WM_KEYDOWN
)
1241 switch (pMsg
->wParam
)
1246 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
1251 /* Avoid TAB control destroy but dialog exist*/
1256 ::GetClassName(pMsg
->hwnd
, buff
, _countof(buff
) - 1);
1258 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
1259 if (_wcsnicmp(buff
, MSFTEDIT_CLASS
, _countof(buff
) - 1) == 0 || //Unicode and MFC 2012 and later
1260 _wcsnicmp(buff
, RICHEDIT_CLASS
, _countof(buff
) - 1) == 0 || //ANSI or MFC 2010
1261 _wcsnicmp(buff
, L
"SysListView32", _countof(buff
) - 1) == 0)
1263 this->PostMessage(WM_KEYDOWN
,VK_ESCAPE
,0);
1269 return __super::PreTranslateMessage(pMsg
);
1271 void CSyncDlg::FetchOutList(bool force
)
1273 if (!m_bInited
|| m_bWantToExit
)
1275 m_OutChangeFileList
.Clear();
1276 this->m_OutLogList
.Clear();
1278 m_ctrlTabCtrl
.ShowTab(IDC_OUT_LOGLIST
- 1, true);
1279 m_ctrlTabCtrl
.ShowTab(IDC_OUT_CHANGELIST
- 1, true);
1282 this->m_ctrlURL
.GetWindowText(remote
);
1283 CString remotebranch
;
1284 this->m_ctrlRemoteBranch
.GetWindowText(remotebranch
);
1285 remotebranch
= remote
+ L
'/' + remotebranch
;
1286 CGitHash remotebranchHash
;
1287 g_Git
.GetHash(remotebranchHash
, remotebranch
);
1292 str
.LoadString(IDS_PROC_SYNC_PUSH_UNKNOWN
);
1293 m_OutLogList
.ShowText(str
);
1294 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1295 m_OutLocalBranch
.Empty();
1296 m_OutRemoteBranch
.Empty();
1298 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1302 else if(remotebranchHash
.IsEmpty())
1305 str
.Format(IDS_PROC_SYNC_PUSH_UNKNOWNBRANCH
, static_cast<LPCWSTR
>(remotebranch
));
1306 m_OutLogList
.ShowText(str
);
1307 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1308 m_OutLocalBranch
.Empty();
1309 m_OutRemoteBranch
.Empty();
1311 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1316 CString localbranch
;
1317 localbranch
=this->m_ctrlLocalBranch
.GetString();
1319 if(localbranch
!= m_OutLocalBranch
|| m_OutRemoteBranch
!= remotebranch
|| force
)
1321 m_OutLogList
.ClearText();
1323 CGitHash base
, localBranchHash
;
1324 bool isFastForward
= g_Git
.IsFastForward(remotebranch
, localbranch
, &base
);
1326 if (g_Git
.GetHash(localBranchHash
, localbranch
))
1328 MessageBox(g_Git
.GetGitLastErr(L
"Could not get hash of \"" + localbranch
+ L
"\"."), L
"TortoiseGit", MB_ICONERROR
);
1331 if (remotebranchHash
== localBranchHash
)
1334 str
.FormatMessage(IDS_PROC_SYNC_COMMITSAHEAD
, 0, static_cast<LPCWSTR
>(remotebranch
));
1335 m_OutLogList
.ShowText(str
);
1336 this->m_ctrlStatus
.SetWindowText(str
);
1337 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1338 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1340 else if (isFastForward
|| m_bForce
)
1343 range
.Format(L
"%s..%s", static_cast<LPCWSTR
>(g_Git
.FixBranchName(remotebranch
)), static_cast<LPCWSTR
>(g_Git
.FixBranchName(localbranch
)));
1345 m_OutLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
1347 str
.FormatMessage(IDS_PROC_SYNC_COMMITSAHEAD
, m_OutLogList
.GetItemCount(), static_cast<LPCWSTR
>(remotebranch
));
1348 this->m_ctrlStatus
.SetWindowText(str
);
1351 AddDiffFileList(&m_OutChangeFileList
, &m_arOutChangeList
, localBranchHash
, remotebranchHash
);
1354 AddDiffFileList(&m_OutChangeFileList
, &m_arOutChangeList
, localBranchHash
, base
);
1357 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,TRUE
);
1358 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(TRUE
);
1363 str
.FormatMessage(IDS_PROC_SYNC_NOFASTFORWARD
, static_cast<LPCWSTR
>(localbranch
), static_cast<LPCWSTR
>(remotebranch
));
1364 m_OutLogList
.ShowText(str
);
1365 this->m_ctrlStatus
.SetWindowText(str
);
1366 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID() - 1, FALSE
);
1367 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1370 this->m_OutLocalBranch
=localbranch
;
1371 this->m_OutRemoteBranch
=remotebranch
;
1375 bool CSyncDlg::IsURL()
1378 this->m_ctrlURL
.GetWindowText(str
);
1379 return str
.Find(L
'\\') >= 0 || str
.Find(L
'/') >= 0;
1382 void CSyncDlg::OnCbnEditchangeComboboxex()
1384 SetTimer(IDT_INPUT
, 1000, nullptr);
1385 this->m_OutLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_WAINTINPUT
)));
1387 //this->FetchOutList();
1390 UINT
CSyncDlg::ProgressThread()
1392 m_startTick
= GetTickCount64();
1395 CProgressDlg::RunCmdList(this, m_GitCmdList
, list
, true, nullptr, &this->m_bAbort
, &this->m_Databuf
);
1396 InterlockedExchange(&m_bBlock
, FALSE
);
1400 LRESULT
CSyncDlg::OnProgressUpdateUI(WPARAM wParam
,LPARAM lParam
)
1404 if(wParam
== MSG_PROGRESSDLG_START
)
1407 if (CRegDWORD(L
"Software\\TortoiseGit\\DownloadAnimation", TRUE
) == TRUE
)
1408 m_ctrlAnimate
.Play(0, UINT_MAX
, UINT_MAX
);
1409 this->m_ctrlProgress
.SetPos(0);
1412 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
1413 m_pTaskbarList
->SetProgressValue(m_hWnd
, 0, 100);
1417 if(wParam
== MSG_PROGRESSDLG_END
|| wParam
== MSG_PROGRESSDLG_FAILED
)
1419 ULONGLONG tickSpent
= GetTickCount64() - m_startTick
;
1420 CString strEndTime
= CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE
, true, false);
1423 m_Databuf
.m_critSec
.Lock();
1425 m_Databuf
.m_critSec
.Unlock();
1428 m_ctrlAnimate
.Stop();
1429 m_ctrlProgress
.SetPos(100);
1430 //this->DialogEnableWindow(IDOK,TRUE);
1434 m_ctrlCmdOut
.GetWindowText(text
);
1436 CAppUtils::StyleURLs(text
, &m_ctrlCmdOut
);
1439 auto exitCode
= static_cast<DWORD
>(lParam
);
1444 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
1445 m_pTaskbarList
->SetProgressValue(m_hWnd
, 100, 100);
1448 log
.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT
, exitCode
);
1450 err
.Format(L
"\r\n\r\n%s (%I64u ms @ %s)\r\n", static_cast<LPCWSTR
>(log
), tickSpent
, static_cast<LPCWSTR
>(strEndTime
));
1451 CProgressDlg::InsertColorText(this->m_ctrlCmdOut
, err
, RGB(255,0,0));
1452 if (CRegDWORD(L
"Software\\TortoiseGit\\NoSounds", FALSE
) == FALSE
)
1453 PlaySound(reinterpret_cast<LPCWSTR
>(SND_ALIAS_SYSTEMEXCLAMATION
), nullptr, SND_ALIAS_ID
| SND_ASYNC
);
1458 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
);
1460 temp
.LoadString(IDS_SUCCESS
);
1462 log
.Format(L
"\r\n%s (%I64u ms @ %s)\r\n", static_cast<LPCWSTR
>(temp
), tickSpent
, static_cast<LPCWSTR
>(strEndTime
));
1463 CProgressDlg::InsertColorText(this->m_ctrlCmdOut
, log
, RGB(0,0,255));
1465 m_GitCmdStatus
= exitCode
;
1467 //if(wParam == MSG_PROGRESSDLG_END)
1472 ParserCmdOutput(static_cast<char>(lParam
));
1475 m_Databuf
.m_critSec
.Lock();
1476 for (size_t i
= m_BufStart
; i
< m_Databuf
.size(); ++i
)
1478 char c
= m_Databuf
[m_BufStart
];
1480 m_Databuf
.m_critSec
.Unlock();
1483 m_Databuf
.m_critSec
.Lock();
1486 if (m_BufStart
> 1000)
1488 m_Databuf
.erase(m_Databuf
.cbegin(), m_Databuf
.cbegin() + m_BufStart
);
1491 m_Databuf
.m_critSec
.Unlock();
1497 static REF_VECTOR
HashMapToRefMap(MAP_HASH_NAME
& map
)
1499 auto rmap
= REF_VECTOR();
1500 for (auto mit
= map
.cbegin(); mit
!= map
.cend(); ++mit
)
1502 for (auto rit
= mit
->second
.cbegin(); rit
!= mit
->second
.cend(); ++rit
)
1504 rmap
.emplace_back(TGitRef
{ *rit
, mit
->first
});
1510 void CSyncDlg::FillNewRefMap()
1513 m_newHashMap
.clear();
1515 if (!g_Git
.m_IsUseLibGit2
)
1518 CAutoRepository
repo(g_Git
.GetGitRepository());
1521 CMessageBox::Show(m_hWnd
, CGit::GetLibGit2LastErr(L
"Could not open repository."), L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
1525 if (CGit::GetMapHashToFriendName(repo
, m_newHashMap
))
1527 MessageBox(CGit::GetLibGit2LastErr(L
"Could not get all refs."), L
"TortoiseGit", MB_ICONERROR
);
1531 auto oldRefMap
= HashMapToRefMap(m_oldHashMap
);
1532 auto newRefMap
= HashMapToRefMap(m_newHashMap
);
1533 for (auto oit
= oldRefMap
.cbegin(); oit
!= oldRefMap
.cend(); ++oit
)
1536 for (auto nit
= newRefMap
.cbegin(); nit
!= newRefMap
.cend(); ++nit
)
1539 if (oit
->name
== nit
->name
)
1542 m_refList
.AddEntry(repo
, oit
->name
, &oit
->hash
, &nit
->hash
);
1548 m_refList
.AddEntry(repo
, oit
->name
, &oit
->hash
, nullptr);
1550 for (auto nit
= newRefMap
.cbegin(); nit
!= newRefMap
.cend(); ++nit
)
1553 for (auto oit
= oldRefMap
.cbegin(); oit
!= oldRefMap
.cend(); ++oit
)
1555 if (oit
->name
== nit
->name
)
1563 m_refList
.AddEntry(repo
, nit
->name
, nullptr, &nit
->hash
);
1568 void CSyncDlg::RunPostAction()
1575 if (this->m_CurrentCmd
== GIT_COMMAND_PUSH
)
1577 DWORD exitcode
= 0xFFFFFFFF;
1579 CHooks::Instance().SetProjectProperties(g_Git
.m_CurrentDir
, m_ProjectProperties
);
1580 if (CHooks::Instance().PostPush(GetSafeHwnd(), g_Git
.m_CurrentDir
, exitcode
, error
))
1585 temp
.Format(IDS_ERR_HOOKFAILED
, static_cast<LPCWSTR
>(error
));
1586 CMessageBox::Show(GetSafeHwnd(), temp
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
1591 EnableControlButton(true);
1593 this->FetchOutList(true);
1595 else if (this->m_CurrentCmd
== GIT_COMMAND_PULL
)
1597 else if (this->m_CurrentCmd
== GIT_COMMAND_FETCH
|| this->m_CurrentCmd
== GIT_COMMAND_FETCHANDREBASE
)
1599 else if (this->m_CurrentCmd
== GIT_COMMAND_SUBMODULE
)
1601 //this->m_ctrlCmdOut.SetSel(-1,-1);
1602 //this->m_ctrlCmdOut.ReplaceSel(L"Done\r\n");
1603 //this->m_ctrlCmdOut.SetSel(-1,-1);
1604 EnableControlButton(true);
1607 else if (this->m_CurrentCmd
== GIT_COMMAND_STASH
)
1609 else if (this->m_CurrentCmd
== GIT_COMMAND_REMOTE
)
1611 this->FetchOutList(true);
1612 EnableControlButton(true);
1614 ShowTab(IDC_REFLIST
);
1617 void CSyncDlg::ParserCmdOutput(char ch
)
1621 CProgressDlg::ParserCmdOutput(m_ctrlCmdOut
,m_ctrlProgress
,m_hWnd
,m_pTaskbarList
,m_LogText
,ch
);
1623 void CSyncDlg::OnBnClickedButtonCommit()
1625 CString cmd
= L
"/command:commit";
1626 cmd
+= L
" /path:\"";
1627 cmd
+= g_Git
.m_CurrentDir
;
1630 CAppUtils::RunTortoiseGitProc(cmd
);
1633 void CSyncDlg::OnOK()
1637 m_ctrlURL
.SaveHistory();
1639 m_regAutoLoadPutty
= this->m_bAutoLoadPuttyKey
;
1644 void CSyncDlg::OnCancel()
1647 m_GitProgressList
.Cancel();
1648 if (m_bDone
&& !m_GitProgressList
.IsRunning())
1650 CResizableStandAloneDialog::OnCancel();
1653 if (m_GitProgressList
.IsRunning())
1654 WaitForSingleObject(m_GitProgressList
.m_pThread
->m_hThread
, 10000);
1656 if (g_Git
.m_CurrentGitPi
.hProcess
)
1658 DWORD dwConfirmKillProcess
= CRegDWORD(L
"Software\\TortoiseGit\\ConfirmKillProcess");
1659 if (dwConfirmKillProcess
&& CMessageBox::Show(m_hWnd
, IDS_PROC_CONFIRMKILLPROCESS
, IDS_APPNAME
, MB_YESNO
| MB_ICONQUESTION
) != IDYES
)
1661 if (::GenerateConsoleCtrlEvent(CTRL_C_EVENT
, 0))
1662 ::WaitForSingleObject(g_Git
.m_CurrentGitPi
.hProcess
, 10000);
1664 CProgressDlg::KillProcessTree(g_Git
.m_CurrentGitPi
.dwProcessId
);
1667 ::WaitForSingleObject(g_Git
.m_CurrentGitPi
.hProcess
,10000);
1670 if (::WaitForSingleObject(m_pThread
->m_hThread
, 5000) == WAIT_TIMEOUT
)
1671 g_Git
.KillRelatedThreads(m_pThread
);
1674 CResizableStandAloneDialog::OnCancel();
1677 void CSyncDlg::OnBnClickedButtonSubmodule()
1679 bool bShift
= (GetAsyncKeyState(VK_SHIFT
) & 0x8000) != 0;
1685 switch (m_ctrlSubmodule
.GetCurrentEntry())
1690 CAppUtils::RunTortoiseGitProc(L
"/command:subupdate /bkpath:\"" + g_Git
.m_CurrentDir
+ L
"\"");
1693 CAppUtils::RunTortoiseGitProc(L
"/command:subsync /bkpath:\"" + g_Git
.m_CurrentDir
+ L
"\"");
1699 m_ctrlCmdOut
.SetWindowText(L
"");
1702 this->m_regSubmoduleButton
= static_cast<DWORD
>(this->m_ctrlSubmodule
.GetCurrentEntry());
1704 this->SwitchToRun();
1706 this->m_bAbort
=false;
1707 this->m_GitCmdList
.clear();
1709 ShowTab(IDC_CMD_LOG
);
1713 switch (m_ctrlSubmodule
.GetCurrentEntry())
1716 cmd
= L
"git.exe submodule update --init";
1719 cmd
= L
"git.exe submodule init";
1722 cmd
= L
"git.exe submodule sync";
1726 m_GitCmdList
.push_back(cmd
);
1728 m_CurrentCmd
= GIT_COMMAND_SUBMODULE
;
1730 StartWorkerThread();
1733 void CSyncDlg::OnBnClickedButtonStash()
1735 bool bShift
= (GetAsyncKeyState(VK_SHIFT
) & 0x8000) != 0;
1741 if (m_ctrlStash
.GetCurrentEntry() == 0)
1742 CAppUtils::RunTortoiseGitProc(L
"/command:stashsave");
1746 m_ctrlCmdOut
.SetWindowText(L
"");
1752 m_GitCmdList
.clear();
1754 ShowTab(IDC_CMD_LOG
);
1756 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, false);
1757 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1, false);
1758 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
-1, false);
1761 switch (m_ctrlStash
.GetCurrentEntry())
1764 cmd
= L
"git.exe stash save";
1767 cmd
= L
"git.exe stash pop";
1770 cmd
= L
"git.exe stash apply";
1774 m_GitCmdList
.push_back(cmd
);
1775 m_CurrentCmd
= GIT_COMMAND_STASH
;
1777 StartWorkerThread();
1780 void CSyncDlg::OnTimer(UINT_PTR nIDEvent
)
1782 if( nIDEvent
== IDT_INPUT
)
1784 KillTimer(IDT_INPUT
);
1785 this->FetchOutList(true);
1786 m_ctrlTabCtrl
.ShowTab(IDC_TAGCOMPARELIST
- 1, false);
1790 LRESULT
CSyncDlg::OnTaskbarBtnCreated(WPARAM wParam
, LPARAM lParam
)
1792 m_pTaskbarList
.Release();
1793 m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
);
1794 m_GitProgressList
.m_pTaskbarList
= m_pTaskbarList
;
1795 return __super::OnTaskbarButtonCreated(wParam
, lParam
);
1798 void CSyncDlg::OnBnClickedCheckForce()
1803 void CSyncDlg::OnBnClickedLog()
1805 CString cmd
= L
"/command:log";
1806 cmd
+= L
" /path:\"";
1807 cmd
+= g_Git
.m_CurrentDir
;
1810 CAppUtils::RunTortoiseGitProc(cmd
);
1813 LRESULT
CSyncDlg::OnProgCmdFinish(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1820 void CSyncDlg::OnDestroy()
1822 m_bWantToExit
= true;
1823 __super::OnDestroy();
1826 void CSyncDlg::SetTheme(bool bDark
)
1828 __super::SetTheme(bDark
);
1829 CMFCVisualManager::GetInstance()->DestroyInstance();
1832 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CThemeMFCVisualManager
));
1833 m_ctrlTabCtrl
.ModifyTabStyle(CMFCTabCtrl::STYLE_3D
);
1837 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
1838 m_ctrlTabCtrl
.ModifyTabStyle(CMFCTabCtrl::STYLE_FLAT
);
1840 CMFCVisualManager::RedrawAll();
1843 void CSyncDlg::OnEnLinkLog(NMHDR
*pNMHDR
, LRESULT
*pResult
)
1845 // similar code in ProgressDlg.cpp and LogDlg.cpp
1846 ENLINK
*pEnLink
= reinterpret_cast<ENLINK
*>(pNMHDR
);
1847 if ((pEnLink
->msg
== WM_LBUTTONUP
) || (pEnLink
->msg
== WM_SETCURSOR
))
1850 m_ctrlCmdOut
.GetWindowText(msg
);
1851 msg
.Replace(L
"\r\n", L
"\n");
1852 CString url
= msg
.Mid(pEnLink
->chrg
.cpMin
, pEnLink
->chrg
.cpMax
- pEnLink
->chrg
.cpMin
);
1853 // check if it's an email address
1854 auto atpos
= url
.Find(L
'@');
1855 if ((atpos
> 0) && (url
.ReverseFind(L
'.') > atpos
) && !::PathIsURL(url
))
1856 url
= L
"mailto:" + url
;
1857 if (::PathIsURL(url
))
1859 if (pEnLink
->msg
== WM_LBUTTONUP
)
1860 ShellExecute(GetSafeHwnd(), L
"open", url
, nullptr, nullptr, SW_SHOWDEFAULT
);
1863 static RECT prevRect
= { 0 };
1864 CWnd
* pMsgView
= &m_ctrlCmdOut
;
1869 pMsgView
->SendMessage(EM_POSFROMCHAR
, reinterpret_cast<WPARAM
>(&pt
), pEnLink
->chrg
.cpMin
);
1872 pMsgView
->SendMessage(EM_POSFROMCHAR
, reinterpret_cast<WPARAM
>(&pt
), pEnLink
->chrg
.cpMax
);
1874 rc
.bottom
= pt
.y
+ 12;
1875 if ((prevRect
.left
!= rc
.left
) || (prevRect
.top
!= rc
.top
))
1877 m_tooltips
.DelTool(pMsgView
, 1);
1878 m_tooltips
.AddTool(pMsgView
, url
, &rc
, 1);
1888 void CSyncDlg::OnEnscrollLog()
1890 m_tooltips
.DelTool(&m_ctrlCmdOut
, 1);
1893 void CSyncDlg::StartWorkerThread()
1895 if (InterlockedExchange(&m_bBlock
, TRUE
))
1898 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
);
1901 InterlockedExchange(&m_bBlock
, FALSE
);
1902 CMessageBox::Show(this->m_hWnd
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1904 EnableControlButton(true);