Fixed issue #4118: When dark mode is enabled, dialogs momentarily flicker with "light...
[TortoiseGit.git] / src / TortoiseProc / ChangedDlg.cpp
blobb2e3d57d5e2bb324148840e3899e09fc13d7932f
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2024 - 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"
29 #include "AutoCloakWindow.h"
31 IMPLEMENT_DYNAMIC(CChangedDlg, CResizableStandAloneDialog)
32 CChangedDlg::CChangedDlg(CWnd* pParent /*=nullptr*/)
33 : CResizableStandAloneDialog(CChangedDlg::IDD, pParent)
34 , m_bShowUnversioned(FALSE)
35 , m_iShowUnmodified(0)
36 , m_bShowIgnored(FALSE)
37 , m_bShowLocalChangesIgnored(FALSE)
38 , m_bWholeProject(FALSE)
39 , m_bRemote(FALSE)
40 , m_bShowStaged(TRUE)
44 CChangedDlg::~CChangedDlg()
48 void CChangedDlg::DoDataExchange(CDataExchange* pDX)
50 CResizableStandAloneDialog::DoDataExchange(pDX);
51 DDX_Control(pDX, IDC_BRANCH, m_BranchLink);
52 DDX_Control(pDX, IDC_CHANGEDLIST, m_FileListCtrl);
53 DDX_Control(pDX, IDC_BUTTON_STASH, m_ctrlStash);
54 DDX_Check(pDX, IDC_SHOWUNVERSIONED, m_bShowUnversioned);
55 DDX_Check(pDX, IDC_SHOWUNMODIFIED, m_iShowUnmodified);
56 DDX_Check(pDX, IDC_SHOWIGNORED, m_bShowIgnored);
57 DDX_Check(pDX, IDC_SHOWLOCALCHANGESIGNORED, m_bShowLocalChangesIgnored);
58 DDX_Check(pDX, IDC_WHOLE_PROJECT, m_bWholeProject);
59 DDX_Check(pDX, IDC_SHOWSTAGED, m_bShowStaged);
63 BEGIN_MESSAGE_MAP(CChangedDlg, CResizableStandAloneDialog)
64 ON_BN_CLICKED(IDC_SHOWUNVERSIONED, OnBnClickedShowunversioned)
65 ON_BN_CLICKED(IDC_SHOWUNMODIFIED, OnBnClickedShowUnmodified)
66 ON_REGISTERED_MESSAGE(CGitStatusListCtrl::GITSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)
67 ON_REGISTERED_MESSAGE(CGitStatusListCtrl::GITSLNM_ITEMCOUNTCHANGED, OnSVNStatusListCtrlItemCountChanged)
68 ON_BN_CLICKED(IDC_SHOWIGNORED, &CChangedDlg::OnBnClickedShowignored)
69 ON_BN_CLICKED(IDC_REFRESH, &CChangedDlg::OnBnClickedRefresh)
70 ON_BN_CLICKED(IDC_COMMIT, &CChangedDlg::OnBnClickedCommit)
71 ON_BN_CLICKED(IDC_BUTTON_STASH, &CChangedDlg::OnBnClickedStash)
72 ON_BN_CLICKED(IDC_BUTTON_UNIFIEDDIFF, &CChangedDlg::OnBnClickedButtonUnifieddiff)
73 ON_BN_CLICKED(IDC_SHOWLOCALCHANGESIGNORED, &CChangedDlg::OnBnClickedShowlocalchangesignored)
74 ON_BN_CLICKED(IDC_WHOLE_PROJECT, OnBnClickedWholeProject)
75 ON_BN_CLICKED(IDC_SHOWSTAGED, OnBnClickedShowStaged)
76 ON_NOTIFY(NM_CLICK, IDC_BRANCH, &CChangedDlg::OnNMClickBranchLink)
77 END_MESSAGE_MAP()
79 BOOL CChangedDlg::OnInitDialog()
81 CAutoCloakWindow window_cloaker{ GetSafeHwnd() };
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");
134 SetTheme(CTheme::Instance().IsDarkTheme());
136 m_ctrlStash.m_bAlwaysShowArrow = true;
138 m_bRemote = !!static_cast<DWORD>(CRegDWORD(L"Software\\TortoiseGit\\CheckRepo", FALSE));
140 // first start a thread to obtain the status without
141 // blocking the dialog
142 OnBnClickedRefresh();
144 return TRUE;
147 UINT CChangedDlg::ChangedStatusThreadEntry(LPVOID pVoid)
149 return static_cast<CChangedDlg*>(pVoid)->ChangedStatusThread();
152 UINT CChangedDlg::ChangedStatusThread()
154 m_bCanceled = false;
155 SetDlgItemText(IDOK, CString(MAKEINTRESOURCE(IDS_MSGBOX_CANCEL)));
156 DialogEnableWindow(IDC_REFRESH, FALSE);
157 DialogEnableWindow(IDC_SHOWUNVERSIONED, FALSE);
158 DialogEnableWindow(IDC_SHOWUNMODIFIED, FALSE);
159 DialogEnableWindow(IDC_SHOWIGNORED, FALSE);
160 DialogEnableWindow(IDC_SHOWLOCALCHANGESIGNORED, FALSE);
161 DialogEnableWindow(IDC_SHOWSTAGED, FALSE);
163 m_BranchLink.SetWindowText(L"");
165 g_Git.RefreshGitIndex();
167 m_FileListCtrl.StoreScrollPos();
168 m_FileListCtrl.Clear();
169 m_FileListCtrl.m_bIncludedStaged = (m_bShowStaged == TRUE);
170 if (!m_FileListCtrl.GetStatus(m_bWholeProject ? nullptr : &m_pathList, m_bRemote, m_bShowIgnored != FALSE, m_bShowUnversioned != FALSE, m_bShowLocalChangesIgnored != FALSE))
172 if (!m_FileListCtrl.GetLastErrorMessage().IsEmpty())
173 m_FileListCtrl.SetEmptyString(m_FileListCtrl.GetLastErrorMessage());
175 unsigned int dwShow = GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS | GITSLC_SHOWSWITCHED | GITSLC_SHOWINCHANGELIST;
176 dwShow |= m_bShowUnversioned ? GITSLC_SHOWUNVERSIONED : 0;
177 dwShow |= m_iShowUnmodified ? GITSLC_SHOWNORMAL : 0;
178 dwShow |= m_bShowIgnored ? GITSLC_SHOWIGNORED : 0;
179 dwShow |= m_bShowLocalChangesIgnored ? GITSLC_SHOWASSUMEVALID | GITSLC_SHOWSKIPWORKTREE : 0;
180 m_FileListCtrl.Show(dwShow);
181 UpdateStatistics();
183 SetDlgTitle();
184 bool bIsDirectory = false;
185 if (m_pathList.GetCount() == 1)
186 bIsDirectory = m_pathList[0].IsDirectory() || m_pathList[0].IsEmpty(); // if it is empty it is g_Git.m_CurrentDir which is a directory
188 m_BranchLink.SetWindowText(L"<a>" + g_Git.GetCurrentBranch() + L"</a>");
189 SetDlgItemText(IDOK, CString(MAKEINTRESOURCE(IDS_MSGBOX_OK)));
190 DialogEnableWindow(IDC_REFRESH, TRUE);
191 DialogEnableWindow(IDC_SHOWUNVERSIONED, bIsDirectory);
192 //DialogEnableWindow(IDC_SHOWUNMODIFIED, bIsDirectory);
193 DialogEnableWindow(IDC_SHOWIGNORED, bIsDirectory);
194 DialogEnableWindow(IDC_SHOWLOCALCHANGESIGNORED, TRUE);
195 DialogEnableWindow(IDC_SHOWSTAGED, TRUE);
196 InterlockedExchange(&m_bBlock, FALSE);
197 // revert the remote flag back to the default
198 m_bRemote = !!static_cast<DWORD>(CRegDWORD(L"Software\\TortoiseGit\\CheckRepo", FALSE));
199 RefreshCursor();
200 return 0;
203 void CChangedDlg::OnOK()
205 if (m_bBlock)
207 m_bCanceled = true;
208 return;
210 __super::OnOK();
213 void CChangedDlg::OnCancel()
215 if (m_bBlock)
217 m_bCanceled = true;
218 return;
220 __super::OnCancel();
223 DWORD CChangedDlg::UpdateShowFlags()
225 DWORD dwShow = m_FileListCtrl.GetShowFlags();
226 if (m_bShowUnversioned)
227 dwShow |= GITSLC_SHOWUNVERSIONED;
228 else
229 dwShow &= ~GITSLC_SHOWUNVERSIONED;
230 if (m_iShowUnmodified)
231 dwShow |= GITSLC_SHOWNORMAL;
232 else
233 dwShow &= ~GITSLC_SHOWNORMAL;
234 if (m_bShowIgnored)
235 dwShow |= GITSLC_SHOWIGNORED;
236 else
237 dwShow &= ~GITSLC_SHOWIGNORED;
238 if (m_bShowLocalChangesIgnored)
239 dwShow |= GITSLC_SHOWASSUMEVALID|GITSLC_SHOWSKIPWORKTREE;
240 else
241 dwShow &= ~(GITSLC_SHOWASSUMEVALID|GITSLC_SHOWSKIPWORKTREE);
243 // old bShowExternals:
244 dwShow &= ~(GITSLC_SHOWEXTERNAL | GITSLC_SHOWINEXTERNALS | GITSLC_SHOWEXTERNALFROMDIFFERENTREPO);
246 return dwShow;
249 void CChangedDlg::SetDlgTitle()
251 if (m_sTitle.IsEmpty())
252 GetWindowText(m_sTitle);
254 if (m_bWholeProject)
255 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, m_sTitle);
256 else
258 if (m_pathList.GetCount() == 1)
259 CAppUtils::SetWindowTitle(m_hWnd, g_Git.CombinePath(m_pathList[0].GetUIPathString()), m_sTitle);
260 else
261 CAppUtils::SetWindowTitle(m_hWnd, g_Git.CombinePath(m_FileListCtrl.GetCommonDirectory(false)), m_sTitle);
265 void CChangedDlg::OnBnClickedShowunversioned()
267 UpdateData();
268 m_regAddBeforeCommit = m_bShowUnversioned;
269 if(m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_UNVER)
271 m_FileListCtrl.StoreScrollPos();
272 m_FileListCtrl.Show(UpdateShowFlags());
274 else
276 if(m_bShowUnversioned)
277 OnBnClickedRefresh();
279 UpdateStatistics();
282 void CChangedDlg::OnBnClickedShowUnmodified()
284 UpdateData();
285 m_FileListCtrl.StoreScrollPos();
286 m_FileListCtrl.Show(UpdateShowFlags());
287 m_regAddBeforeCommit = m_bShowUnversioned;
288 UpdateStatistics();
291 void CChangedDlg::OnBnClickedShowignored()
293 UpdateData();
294 m_FileListCtrl.StoreScrollPos();
295 if (m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_IGNORE)
296 m_FileListCtrl.Show(UpdateShowFlags());
297 else if (m_bShowIgnored)
298 OnBnClickedRefresh();
299 UpdateStatistics();
302 void CChangedDlg::OnBnClickedShowlocalchangesignored()
304 UpdateData();
305 m_FileListCtrl.StoreScrollPos();
306 if (m_FileListCtrl.m_FileLoaded & CGitStatusListCtrl::FILELIST_LOCALCHANGESIGNORED)
307 m_FileListCtrl.Show(UpdateShowFlags());
308 else if (m_bShowLocalChangesIgnored)
309 OnBnClickedRefresh();
310 UpdateStatistics();
313 LRESULT CChangedDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)
315 OnBnClickedRefresh();
316 return 0;
319 LRESULT CChangedDlg::OnSVNStatusListCtrlItemCountChanged(WPARAM, LPARAM)
321 UpdateStatistics();
322 return 0;
325 void CChangedDlg::OnNMClickBranchLink(NMHDR* /*pNMHDR*/, LRESULT* pResult)
327 if (CAppUtils::Switch(GetSafeHwnd()))
328 OnBnClickedRefresh();
329 *pResult = 0;
332 BOOL CChangedDlg::PreTranslateMessage(MSG* pMsg)
334 if (pMsg->message == WM_KEYDOWN)
336 switch (pMsg->wParam)
338 case VK_F5:
339 OnBnClickedRefresh();
340 break;
344 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
347 void CChangedDlg::OnBnClickedRefresh()
349 if (InterlockedExchange(&m_bBlock, TRUE))
350 return;
352 if (!AfxBeginThread(ChangedStatusThreadEntry, this))
354 InterlockedExchange(&m_bBlock, FALSE);
355 CMessageBox::Show(GetSafeHwnd(), IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
359 void CChangedDlg::UpdateStatistics()
361 CString temp = m_FileListCtrl.GetStatisticsString();
362 temp.Replace(L" = ", L"=");
363 temp.Replace(L"\n", L", ");
364 SetDlgItemText(IDC_INFOLABEL, temp);
367 void CChangedDlg::OnBnClickedCommit()
369 CTGitPathList pathList;
370 bool bSingleFile = (m_pathList.GetCount() >= 1 && !m_pathList[0].IsEmpty() && !m_pathList[0].IsDirectory());
371 if (bSingleFile)
372 pathList.AddPath(m_pathList[0]);
373 else
374 pathList.AddPath(m_pathList.GetCommonRoot().GetDirectory());
376 bool bSelectFilesForCommit = !!DWORD(CRegStdDWORD(L"Software\\TortoiseGit\\SelectFilesForCommit", TRUE));
378 CString logmsg;
379 CAppUtils::Commit(GetSafeHwnd(),
380 L"",
381 m_bWholeProject,
382 logmsg,
383 pathList,
384 bSelectFilesForCommit);
386 OnBnClickedRefresh();
389 void CChangedDlg::OnBnClickedStash()
391 CIconMenu popup;
393 if (popup.CreatePopupMenu())
395 popup.AppendMenuIcon(ID_STASH_SAVE, IDS_MENUSTASHSAVE, IDI_SHELVE);
397 CTGitPath root = g_Git.m_CurrentDir;
398 if (root.HasStashDir())
400 popup.AppendMenuIcon(ID_STASH_POP, IDS_MENUSTASHPOP, IDI_UNSHELVE);
401 popup.AppendMenuIcon(ID_STASH_APPLY, IDS_MENUSTASHAPPLY, IDI_UNSHELVE);
402 popup.AppendMenuIcon(ID_STASH_LIST, IDS_MENUSTASHLIST, IDI_LOG);
405 RECT rect;
406 GetDlgItem(IDC_BUTTON_STASH)->GetWindowRect(&rect);
407 TPMPARAMS params;
408 params.cbSize = sizeof(TPMPARAMS);
409 params.rcExclude = rect;
410 int cmd = popup.TrackPopupMenuEx(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY | TPM_VERTICAL, rect.left, rect.top, this, &params);
412 switch (cmd & 0xFFFF)
414 case ID_STASH_SAVE:
415 CAppUtils::StashSave(GetSafeHwnd());
416 break;
417 case ID_STASH_POP:
418 CAppUtils::StashPop(GetSafeHwnd(), 2);
419 break;
420 case ID_STASH_APPLY:
421 CAppUtils::StashApply(GetSafeHwnd(), L"", false);
422 break;
423 case ID_STASH_LIST:
425 CRefLogDlg dlg;
426 dlg.m_CurrentBranch = L"refs/stash";
427 dlg.DoModal();
429 break;
430 default:
431 return;
433 OnBnClickedRefresh();
437 void CChangedDlg::OnBnClickedButtonUnifieddiff()
439 CTGitPath commonDirectory;
440 if (!m_bWholeProject)
441 commonDirectory = m_pathList.GetCommonRoot().GetDirectory();
442 bool bSingleFile = ((m_pathList.GetCount()==1)&&(!m_pathList[0].IsEmpty())&&(!m_pathList[0].IsDirectory()));
443 if (bSingleFile)
444 commonDirectory = m_pathList[0];
445 CString sCmd;
446 sCmd.Format(L"/command:showcompare /unified /path:\"%s\" /revision1:HEAD /revision2:%s", static_cast<LPCWSTR>(g_Git.CombinePath(commonDirectory)), static_cast<LPCWSTR>(GitRev::GetWorkingCopy()));
447 if (!!(GetAsyncKeyState(VK_SHIFT) & 0x8000))
448 sCmd += L" /alternative";
449 CAppUtils::RunTortoiseGitProc(sCmd);
452 void CChangedDlg::OnBnClickedWholeProject()
454 UpdateData();
455 m_regShowWholeProject = m_bWholeProject;
456 OnBnClickedRefresh();
459 void CChangedDlg::OnBnClickedShowStaged()
461 UpdateData();
462 m_regShowStaged = m_bShowStaged;
463 OnBnClickedRefresh();