Add support for Ctrl+A in BrowseRefsDlg and RepositoryBrowser
[TortoiseGit.git] / src / TortoiseProc / ChangedDlg.cpp
blobeaec07a2eaf6608cad10afebe9b1e3a4d2839515
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2021 - TortoiseGit
4 // Copyright (C) 2003-2008 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "ChangedDlg.h"
23 #include "MessageBox.h"
24 #include "cursor.h"
25 #include "AppUtils.h"
26 #include "ChangedDlg.h"
27 #include "IconMenu.h"
28 #include "RefLogDlg.h"
30 IMPLEMENT_DYNAMIC(CChangedDlg, CResizableStandAloneDialog)
31 CChangedDlg::CChangedDlg(CWnd* pParent /*=nullptr*/)
32 : CResizableStandAloneDialog(CChangedDlg::IDD, pParent)
33 , m_bShowUnversioned(FALSE)
34 , m_iShowUnmodified(0)
35 , m_bBlock(FALSE)
36 , m_bCanceled(false)
37 , m_bShowIgnored(FALSE)
38 , m_bShowLocalChangesIgnored(FALSE)
39 , m_bWholeProject(FALSE)
40 , m_bRemote(FALSE)
41 , m_bShowStaged(TRUE)
45 CChangedDlg::~CChangedDlg()
49 void CChangedDlg::DoDataExchange(CDataExchange* pDX)
51 CResizableStandAloneDialog::DoDataExchange(pDX);
52 DDX_Control(pDX, IDC_BRANCH, m_BranchLink);
53 DDX_Control(pDX, IDC_CHANGEDLIST, m_FileListCtrl);
54 DDX_Control(pDX, IDC_BUTTON_STASH, m_ctrlStash);
55 DDX_Check(pDX, IDC_SHOWUNVERSIONED, m_bShowUnversioned);
56 DDX_Check(pDX, IDC_SHOWUNMODIFIED, m_iShowUnmodified);
57 DDX_Check(pDX, IDC_SHOWIGNORED, m_bShowIgnored);
58 DDX_Check(pDX, IDC_SHOWLOCALCHANGESIGNORED, m_bShowLocalChangesIgnored);
59 DDX_Check(pDX, IDC_WHOLE_PROJECT, m_bWholeProject);
60 DDX_Check(pDX, IDC_SHOWSTAGED, m_bShowStaged);
64 BEGIN_MESSAGE_MAP(CChangedDlg, CResizableStandAloneDialog)
65 ON_BN_CLICKED(IDC_SHOWUNVERSIONED, OnBnClickedShowunversioned)
66 ON_BN_CLICKED(IDC_SHOWUNMODIFIED, OnBnClickedShowUnmodified)
67 ON_REGISTERED_MESSAGE(CGitStatusListCtrl::GITSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)
68 ON_REGISTERED_MESSAGE(CGitStatusListCtrl::GITSLNM_ITEMCOUNTCHANGED, OnSVNStatusListCtrlItemCountChanged)
69 ON_BN_CLICKED(IDC_SHOWIGNORED, &CChangedDlg::OnBnClickedShowignored)
70 ON_BN_CLICKED(IDC_REFRESH, &CChangedDlg::OnBnClickedRefresh)
71 ON_BN_CLICKED(IDC_COMMIT, &CChangedDlg::OnBnClickedCommit)
72 ON_BN_CLICKED(IDC_BUTTON_STASH, &CChangedDlg::OnBnClickedStash)
73 ON_BN_CLICKED(IDC_BUTTON_UNIFIEDDIFF, &CChangedDlg::OnBnClickedButtonUnifieddiff)
74 ON_BN_CLICKED(IDC_SHOWLOCALCHANGESIGNORED, &CChangedDlg::OnBnClickedShowlocalchangesignored)
75 ON_BN_CLICKED(IDC_WHOLE_PROJECT, OnBnClickedWholeProject)
76 ON_BN_CLICKED(IDC_SHOWSTAGED, OnBnClickedShowStaged)
77 ON_NOTIFY(NM_CLICK, IDC_BRANCH, &CChangedDlg::OnNMClickBranchLink)
78 END_MESSAGE_MAP()
80 BOOL CChangedDlg::OnInitDialog()
82 CResizableStandAloneDialog::OnInitDialog();
84 m_regAddBeforeCommit = CRegDWORD(L"Software\\TortoiseGit\\AddBeforeCommit", TRUE);
85 m_bShowUnversioned = m_regAddBeforeCommit;
87 CString regPath(g_Git.m_CurrentDir);
88 regPath.Replace(L':', L'_');
89 m_regShowWholeProject = CRegDWORD(L"Software\\TortoiseGit\\TortoiseProc\\ShowWholeProject\\" + regPath, FALSE);
90 m_bWholeProject = m_regShowWholeProject;
91 m_regShowStaged = CRegDWORD(L"Software\\TortoiseGit\\TortoiseProc\\ChangedFilesIncludeStaged", TRUE);
92 m_bShowStaged = m_regShowStaged;
93 SetDlgTitle();
95 if (m_pathList.GetCount() == 1 && m_pathList[0].GetWinPathString().IsEmpty())
97 m_bWholeProject = BST_CHECKED;
98 DialogEnableWindow(IDC_WHOLE_PROJECT, FALSE);
101 UpdateData(FALSE);
103 m_FileListCtrl.Init(GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL | GITSLC_COLMODIFICATIONDATE, L"ChangedDlg", (GITSLC_POPALL ^ (GITSLC_POPSAVEAS | GITSLC_POPRESTORE | GITSLC_POPPREPAREDIFF)), false);
104 m_FileListCtrl.SetCancelBool(&m_bCanceled);
105 m_FileListCtrl.SetBackgroundImage(IDI_CFM_BKG);
106 m_FileListCtrl.SetEmptyString(IDS_REPOSTATUS_EMPTYFILELIST);
108 AdjustControlSize(IDC_SHOWUNVERSIONED);
109 AdjustControlSize(IDC_SHOWUNMODIFIED);
110 AdjustControlSize(IDC_SHOWLOCALCHANGESIGNORED);
111 AdjustControlSize(IDC_SHOWIGNORED);
112 AdjustControlSize(IDC_WHOLE_PROJECT);
113 AdjustControlSize(IDC_SHOWSTAGED);
115 AddAnchor(IDC_BRANCH, TOP_LEFT, TOP_RIGHT);
116 AddAnchor(IDC_CHANGEDLIST, TOP_LEFT, BOTTOM_RIGHT);
117 AddAnchor(IDC_SUMMARYTEXT, BOTTOM_LEFT, BOTTOM_RIGHT);
118 AddAnchor(IDC_SHOWUNVERSIONED, BOTTOM_LEFT);
119 AddAnchor(IDC_SHOWUNMODIFIED, BOTTOM_LEFT);
120 AddAnchor(IDC_SHOWLOCALCHANGESIGNORED, BOTTOM_LEFT);
121 AddAnchor(IDC_SHOWIGNORED, BOTTOM_LEFT);
122 AddAnchor(IDC_WHOLE_PROJECT, BOTTOM_LEFT);
123 AddAnchor(IDC_SHOWSTAGED, BOTTOM_LEFT);
124 AddAnchor(IDC_INFOLABEL, BOTTOM_RIGHT);
125 AddAnchor(IDC_BUTTON_STASH, BOTTOM_RIGHT);
126 AddAnchor(IDC_BUTTON_UNIFIEDDIFF, BOTTOM_RIGHT);
127 AddAnchor(IDC_COMMIT, BOTTOM_RIGHT);
128 AddAnchor(IDC_REFRESH, BOTTOM_RIGHT);
129 AddAnchor(IDOK, BOTTOM_RIGHT);
130 // SetPromptParentWindow(m_hWnd);
131 if (GetExplorerHWND())
132 CenterWindow(CWnd::FromHandle(GetExplorerHWND()));
133 EnableSaveRestore(L"ChangedDlg");
135 m_ctrlStash.m_bAlwaysShowArrow = true;
137 m_bRemote = !!static_cast<DWORD>(CRegDWORD(L"Software\\TortoiseGit\\CheckRepo", FALSE));
139 // first start a thread to obtain the status without
140 // blocking the dialog
141 OnBnClickedRefresh();
143 return TRUE;
146 UINT CChangedDlg::ChangedStatusThreadEntry(LPVOID pVoid)
148 return static_cast<CChangedDlg*>(pVoid)->ChangedStatusThread();
151 UINT CChangedDlg::ChangedStatusThread()
153 m_bCanceled = false;
154 SetDlgItemText(IDOK, CString(MAKEINTRESOURCE(IDS_MSGBOX_CANCEL)));
155 DialogEnableWindow(IDC_REFRESH, FALSE);
156 DialogEnableWindow(IDC_SHOWUNVERSIONED, FALSE);
157 DialogEnableWindow(IDC_SHOWUNMODIFIED, FALSE);
158 DialogEnableWindow(IDC_SHOWIGNORED, FALSE);
159 DialogEnableWindow(IDC_SHOWLOCALCHANGESIGNORED, FALSE);
160 DialogEnableWindow(IDC_SHOWSTAGED, FALSE);
162 m_BranchLink.SetWindowText(L"");
164 g_Git.RefreshGitIndex();
166 m_FileListCtrl.StoreScrollPos();
167 m_FileListCtrl.Clear();
168 m_FileListCtrl.m_bIncludedStaged = (m_bShowStaged == TRUE);
169 if (!m_FileListCtrl.GetStatus(m_bWholeProject ? nullptr : &m_pathList, m_bRemote, m_bShowIgnored != FALSE, m_bShowUnversioned != FALSE, m_bShowLocalChangesIgnored != FALSE))
171 if (!m_FileListCtrl.GetLastErrorMessage().IsEmpty())
172 m_FileListCtrl.SetEmptyString(m_FileListCtrl.GetLastErrorMessage());
174 unsigned int dwShow = GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS | GITSLC_SHOWSWITCHED | GITSLC_SHOWINCHANGELIST;
175 dwShow |= m_bShowUnversioned ? GITSLC_SHOWUNVERSIONED : 0;
176 dwShow |= m_iShowUnmodified ? GITSLC_SHOWNORMAL : 0;
177 dwShow |= m_bShowIgnored ? GITSLC_SHOWIGNORED : 0;
178 dwShow |= m_bShowLocalChangesIgnored ? GITSLC_SHOWASSUMEVALID | GITSLC_SHOWSKIPWORKTREE : 0;
179 m_FileListCtrl.Show(dwShow);
180 UpdateStatistics();
182 SetDlgTitle();
183 bool bIsDirectory = false;
184 if (m_pathList.GetCount() == 1)
185 bIsDirectory = m_pathList[0].IsDirectory() || m_pathList[0].IsEmpty(); // if it is empty it is g_Git.m_CurrentDir which is a directory
187 m_BranchLink.SetWindowText(L"<a>" + g_Git.GetCurrentBranch() + L"</a>");
188 SetDlgItemText(IDOK, CString(MAKEINTRESOURCE(IDS_MSGBOX_OK)));
189 DialogEnableWindow(IDC_REFRESH, TRUE);
190 DialogEnableWindow(IDC_SHOWUNVERSIONED, bIsDirectory);
191 //DialogEnableWindow(IDC_SHOWUNMODIFIED, bIsDirectory);
192 DialogEnableWindow(IDC_SHOWIGNORED, bIsDirectory);
193 DialogEnableWindow(IDC_SHOWLOCALCHANGESIGNORED, TRUE);
194 DialogEnableWindow(IDC_SHOWSTAGED, TRUE);
195 InterlockedExchange(&m_bBlock, FALSE);
196 // revert the remote flag back to the default
197 m_bRemote = !!static_cast<DWORD>(CRegDWORD(L"Software\\TortoiseGit\\CheckRepo", FALSE));
198 RefreshCursor();
199 return 0;
202 void CChangedDlg::OnOK()
204 if (m_bBlock)
206 m_bCanceled = true;
207 return;
209 __super::OnOK();
212 void CChangedDlg::OnCancel()
214 if (m_bBlock)
216 m_bCanceled = true;
217 return;
219 __super::OnCancel();
222 DWORD CChangedDlg::UpdateShowFlags()
224 DWORD dwShow = m_FileListCtrl.GetShowFlags();
225 if (m_bShowUnversioned)
226 dwShow |= GITSLC_SHOWUNVERSIONED;
227 else
228 dwShow &= ~GITSLC_SHOWUNVERSIONED;
229 if (m_iShowUnmodified)
230 dwShow |= GITSLC_SHOWNORMAL;
231 else
232 dwShow &= ~GITSLC_SHOWNORMAL;
233 if (m_bShowIgnored)
234 dwShow |= GITSLC_SHOWIGNORED;
235 else
236 dwShow &= ~GITSLC_SHOWIGNORED;
237 if (m_bShowLocalChangesIgnored)
238 dwShow |= GITSLC_SHOWASSUMEVALID|GITSLC_SHOWSKIPWORKTREE;
239 else
240 dwShow &= ~(GITSLC_SHOWASSUMEVALID|GITSLC_SHOWSKIPWORKTREE);
242 // old bShowExternals:
243 dwShow &= ~(GITSLC_SHOWEXTERNAL | GITSLC_SHOWINEXTERNALS | GITSLC_SHOWEXTERNALFROMDIFFERENTREPO);
245 return dwShow;
248 void CChangedDlg::SetDlgTitle()
250 if (m_sTitle.IsEmpty())
251 GetWindowText(m_sTitle);
253 if (m_bWholeProject)
254 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, m_sTitle);
255 else
257 if (m_pathList.GetCount() == 1)
258 CAppUtils::SetWindowTitle(m_hWnd, g_Git.CombinePath(m_pathList[0].GetUIPathString()), m_sTitle);
259 else
260 CAppUtils::SetWindowTitle(m_hWnd, g_Git.CombinePath(m_FileListCtrl.GetCommonDirectory(false)), m_sTitle);
264 void CChangedDlg::OnBnClickedShowunversioned()
266 UpdateData();
267 m_regAddBeforeCommit = m_bShowUnversioned;
268 if(m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_UNVER)
270 m_FileListCtrl.StoreScrollPos();
271 m_FileListCtrl.Show(UpdateShowFlags());
273 else
275 if(m_bShowUnversioned)
276 OnBnClickedRefresh();
278 UpdateStatistics();
281 void CChangedDlg::OnBnClickedShowUnmodified()
283 UpdateData();
284 m_FileListCtrl.StoreScrollPos();
285 m_FileListCtrl.Show(UpdateShowFlags());
286 m_regAddBeforeCommit = m_bShowUnversioned;
287 UpdateStatistics();
290 void CChangedDlg::OnBnClickedShowignored()
292 UpdateData();
293 m_FileListCtrl.StoreScrollPos();
294 if (m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_IGNORE)
295 m_FileListCtrl.Show(UpdateShowFlags());
296 else if (m_bShowIgnored)
297 OnBnClickedRefresh();
298 UpdateStatistics();
301 void CChangedDlg::OnBnClickedShowlocalchangesignored()
303 UpdateData();
304 m_FileListCtrl.StoreScrollPos();
305 if (m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_LOCALCHANGESIGNORED)
306 m_FileListCtrl.Show(UpdateShowFlags());
307 else if (m_bShowLocalChangesIgnored)
308 OnBnClickedRefresh();
309 UpdateStatistics();
312 LRESULT CChangedDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)
314 OnBnClickedRefresh();
315 return 0;
318 LRESULT CChangedDlg::OnSVNStatusListCtrlItemCountChanged(WPARAM, LPARAM)
320 UpdateStatistics();
321 return 0;
324 void CChangedDlg::OnNMClickBranchLink(NMHDR* /*pNMHDR*/, LRESULT* pResult)
326 if (CAppUtils::Switch(GetSafeHwnd()))
327 OnBnClickedRefresh();
328 *pResult = 0;
331 BOOL CChangedDlg::PreTranslateMessage(MSG* pMsg)
333 if (pMsg->message == WM_KEYDOWN)
335 switch (pMsg->wParam)
337 case VK_F5:
338 OnBnClickedRefresh();
339 break;
343 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
346 void CChangedDlg::OnBnClickedRefresh()
348 if (InterlockedExchange(&m_bBlock, TRUE))
349 return;
351 if (!AfxBeginThread(ChangedStatusThreadEntry, this))
353 InterlockedExchange(&m_bBlock, FALSE);
354 CMessageBox::Show(GetSafeHwnd(), IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
358 void CChangedDlg::UpdateStatistics()
360 CString temp = m_FileListCtrl.GetStatisticsString();
361 temp.Replace(L" = ", L"=");
362 temp.Replace(L"\n", L", ");
363 SetDlgItemText(IDC_INFOLABEL, temp);
366 void CChangedDlg::OnBnClickedCommit()
368 CTGitPathList pathList;
369 bool bSingleFile = (m_pathList.GetCount() >= 1 && !m_pathList[0].IsEmpty() && !m_pathList[0].IsDirectory());
370 if (bSingleFile)
371 pathList.AddPath(m_pathList[0]);
372 else
373 pathList.AddPath(m_pathList.GetCommonRoot().GetDirectory());
375 bool bSelectFilesForCommit = !!DWORD(CRegStdDWORD(L"Software\\TortoiseGit\\SelectFilesForCommit", TRUE));
377 CString logmsg;
378 CAppUtils::Commit(GetSafeHwnd(),
379 L"",
380 m_bWholeProject,
381 logmsg,
382 pathList,
383 bSelectFilesForCommit);
385 OnBnClickedRefresh();
388 void CChangedDlg::OnBnClickedStash()
390 CIconMenu popup;
392 if (popup.CreatePopupMenu())
394 popup.AppendMenuIcon(ID_STASH_SAVE, IDS_MENUSTASHSAVE, IDI_SHELVE);
396 CTGitPath root = g_Git.m_CurrentDir;
397 if (root.HasStashDir())
399 popup.AppendMenuIcon(ID_STASH_POP, IDS_MENUSTASHPOP, IDI_UNSHELVE);
400 popup.AppendMenuIcon(ID_STASH_APPLY, IDS_MENUSTASHAPPLY, IDI_UNSHELVE);
401 popup.AppendMenuIcon(ID_STASH_LIST, IDS_MENUSTASHLIST, IDI_LOG);
404 RECT rect;
405 GetDlgItem(IDC_BUTTON_STASH)->GetWindowRect(&rect);
406 TPMPARAMS params;
407 params.cbSize = sizeof(TPMPARAMS);
408 params.rcExclude = rect;
409 int cmd = popup.TrackPopupMenuEx(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY | TPM_VERTICAL, rect.left, rect.top, this, &params);
411 switch (cmd & 0xFFFF)
413 case ID_STASH_SAVE:
414 CAppUtils::StashSave(GetSafeHwnd());
415 break;
416 case ID_STASH_POP:
417 CAppUtils::StashPop(GetSafeHwnd(), 2);
418 break;
419 case ID_STASH_APPLY:
420 CAppUtils::StashApply(GetSafeHwnd(), L"", false);
421 break;
422 case ID_STASH_LIST:
424 CRefLogDlg dlg;
425 dlg.m_CurrentBranch = L"refs/stash";
426 dlg.DoModal();
428 break;
429 default:
430 return;
432 OnBnClickedRefresh();
436 void CChangedDlg::OnBnClickedButtonUnifieddiff()
438 CTGitPath commonDirectory;
439 if (!m_bWholeProject)
440 commonDirectory = m_pathList.GetCommonRoot().GetDirectory();
441 bool bSingleFile = ((m_pathList.GetCount()==1)&&(!m_pathList[0].IsEmpty())&&(!m_pathList[0].IsDirectory()));
442 if (bSingleFile)
443 commonDirectory = m_pathList[0];
444 CString sCmd;
445 sCmd.Format(L"/command:showcompare /unified /path:\"%s\" /revision1:HEAD /revision2:%s", static_cast<LPCWSTR>(g_Git.CombinePath(commonDirectory)), static_cast<LPCWSTR>(GitRev::GetWorkingCopy()));
446 if (!!(GetAsyncKeyState(VK_SHIFT) & 0x8000))
447 sCmd += L" /alternative";
448 CAppUtils::RunTortoiseGitProc(sCmd);
451 void CChangedDlg::OnBnClickedWholeProject()
453 UpdateData();
454 m_regShowWholeProject = m_bWholeProject;
455 OnBnClickedRefresh();
458 void CChangedDlg::OnBnClickedShowStaged()
460 UpdateData();
461 m_regShowStaged = m_bShowStaged;
462 OnBnClickedRefresh();