Prepare release and bump version numbers to 2.17.0.2
[TortoiseGit.git] / src / TortoiseProc / RefLogDlg.cpp
blob3ab72eb095aed30ca95a81a56a04eb096bf4da3b
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2009-2021, 2023-2024 - 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.
19 // RefLogDlg.cpp : implementation file
22 #include "stdafx.h"
23 #include "resource.h"
24 #include "RefLogDlg.h"
25 #include "Git.h"
26 #include "AppUtils.h"
27 #include "MessageBox.h"
28 #include "UnicodeUtils.h"
30 // CRefLogDlg dialog
32 IMPLEMENT_DYNAMIC(CRefLogDlg, CResizableStandAloneDialog)
34 UINT CRefLogDlg::m_FindDialogMessage = ::RegisterWindowMessage(FINDMSGSTRING);
36 CRefLogDlg::CRefLogDlg(CWnd* pParent /*=nullptr*/)
37 : CResizableStandAloneDialog(CRefLogDlg::IDD, pParent)
41 CRefLogDlg::~CRefLogDlg()
45 void CRefLogDlg::DoDataExchange(CDataExchange* pDX)
47 CDialog::DoDataExchange(pDX);
48 DDX_Control(pDX, IDC_COMBOBOXEX_REF, m_ChooseRef);
49 DDX_Control(pDX, IDC_REFLOG_LIST, m_RefList);
53 BEGIN_MESSAGE_MAP(CRefLogDlg, CResizableStandAloneDialog)
54 ON_BN_CLICKED(IDOK, &CRefLogDlg::OnBnClickedOk)
55 ON_BN_CLICKED(IDC_REFLOG_BUTTONCLEARSTASH, &CRefLogDlg::OnBnClickedClearStash)
56 ON_CBN_SELCHANGE(IDC_COMBOBOXEX_REF, &CRefLogDlg::OnCbnSelchangeRef)
57 ON_NOTIFY(LVN_ITEMCHANGED, IDC_REFLOG_LIST, OnLvnItemchangedRefLoglist)
58 ON_MESSAGE(MSG_REFLOG_CHANGED,OnRefLogChanged)
59 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
60 ON_BN_CLICKED(IDC_SEARCH, OnFind)
61 END_MESSAGE_MAP()
63 LRESULT CRefLogDlg::OnRefLogChanged(WPARAM /*wParam*/, LPARAM /*lParam*/)
65 OnCbnSelchangeRef();
66 return 0;
69 BOOL CRefLogDlg::OnInitDialog()
71 CResizableStandAloneDialog::OnInitDialog();
72 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
74 AddAnchor(IDOK,BOTTOM_RIGHT);
75 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
76 AddAnchor(IDC_REFLOG_BUTTONCLEARSTASH, BOTTOM_LEFT);
77 AddAnchor(IDC_SEARCH, BOTTOM_LEFT);
78 AddAnchor(IDC_REFLOG_LIST,TOP_LEFT,BOTTOM_RIGHT);
79 AddAnchor(IDHELP, BOTTOM_RIGHT);
80 AddAnchor(IDC_COMBOBOXEX_REF, TOP_LEFT, TOP_RIGHT);
82 AddOthersToAnchor();
83 this->EnableSaveRestore(L"RefLogDlg");
84 SetTheme(CTheme::Instance().IsDarkTheme());
86 CAppUtils::SetWindowTitle(*this, g_Git.m_CurrentDir);
88 m_ChooseRef.SetMaxHistoryItems(0x7FFFFFFF);
90 m_RefList.m_hasWC = !GitAdminDir::IsBareRepo(g_Git.m_CurrentDir);
92 this->m_RefList.InsertRefLogColumn();
94 Refresh();
96 return TRUE;
98 // CRefLogDlg message handlers
100 void CRefLogDlg::OnBnClickedOk()
102 if (m_RefList.GetSelectedCount() == 1)
104 // get the selected row
105 POSITION pos = m_RefList.GetFirstSelectedItemPosition();
106 size_t selIndex = m_RefList.GetNextSelectedItem(pos);
107 if (selIndex < m_RefList.m_arShownList.size())
109 // all ok, pick up the revision
110 GitRev* pLogEntry = m_RefList.m_arShownList.SafeGetAt(selIndex);
111 // extract the hash
112 m_SelectedHash = pLogEntry->m_CommitHash;
116 OnOK();
118 void CRefLogDlg::OnBnClickedClearStash()
120 size_t count = m_RefList.m_arShownList.size();
121 CString msg;
122 msg.Format(IDS_PROC_DELETEALLSTASH, count);
123 if (CMessageBox::Show(this->GetSafeHwnd(), msg, L"TortoiseGit", 2, IDI_QUESTION, CString(MAKEINTRESOURCE(IDS_DELETEBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 1)
125 CString cmdOut;
126 if (g_Git.Run(L"git.exe stash clear", &cmdOut, CP_UTF8))
128 MessageBox(cmdOut, L"TortoiseGit", MB_ICONERROR);
129 return;
132 OnCbnSelchangeRef();
136 void CRefLogDlg::OnCbnSelchangeRef()
138 m_CurrentBranch = m_ChooseRef.GetString(); // remember selected branch
139 m_RefList.m_CurrentBranch = m_CurrentBranch;
140 m_RefList.m_RevCache.clear();
141 m_RefList.ClearText();
142 m_RefList.SetRedraw(false);
144 if (CString err; GitRevLoglist::GetRefLog(m_CurrentBranch, m_RefList.m_RevCache, err))
145 MessageBox(L"Error while loading reflog.\n" + err, L"TortoiseGit", MB_ICONERROR);
147 m_RefList.SetItemCountEx(static_cast<int>(m_RefList.m_RevCache.size()));
149 this->m_RefList.m_arShownList.clear();
151 for (unsigned int i = 0; i < m_RefList.m_RevCache.size(); ++i)
153 GitRevLoglist* rev = &m_RefList.m_RevCache[i];
154 this->m_RefList.m_arShownList.SafeAdd(rev);
157 m_RefList.SetRedraw(true);
159 m_RefList.Invalidate();
161 // reset search start positions
162 m_RefList.m_nSearchIndex = 0;
163 m_nSearchLine = 0;
165 if (m_CurrentBranch == L"refs/stash")
167 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->ShowWindow(SW_SHOW);
168 const BOOL enabled = !m_RefList.m_arShownList.empty();
169 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->EnableWindow(enabled);
170 if (!enabled)
171 GetDlgItem(IDOK)->SetFocus();
173 else
175 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->ShowWindow(SW_HIDE);
176 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->EnableWindow(FALSE);
180 BOOL CRefLogDlg::PreTranslateMessage(MSG* pMsg)
182 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F5)
183 Refresh();
184 else if (pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_F3 || (pMsg->wParam == 'F' && (GetAsyncKeyState(VK_CONTROL) & 0x8000))))
185 OnFind();
187 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
190 void CRefLogDlg::OnLvnItemchangedRefLoglist(NMHDR* pNMHDR, LRESULT* pResult)
192 auto pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
193 *pResult = 0;
194 if (pNMLV->iItem < 0)
195 return;
196 m_RefList.m_nSearchIndex = pNMLV->iItem;
197 m_nSearchLine = pNMLV->iItem;
200 void CRefLogDlg::Refresh()
202 STRING_VECTOR list;
203 list.push_back(L"HEAD");
204 if (g_Git.GetRefList(list))
205 MessageBox(g_Git.GetGitLastErr(L"Could not get all refs."), L"TortoiseGit", MB_ICONERROR);
207 m_ChooseRef.SetList(list);
209 if (m_CurrentBranch.IsEmpty())
210 m_CurrentBranch = L"HEAD";
212 bool found = false;
213 for (int i = 0; i < static_cast<int>(list.size()); ++i)
215 if (list[i] == m_CurrentBranch)
217 m_ChooseRef.SetCurSel(i);
218 found = true;
219 break;
222 if (!found)
223 m_ChooseRef.SetCurSel(0); /* Choose HEAD */
225 OnCbnSelchangeRef();
228 void CRefLogDlg::OnFind()
230 if (m_pFindDialog)
232 m_pFindDialog->SetFocus();
233 return;
235 m_pFindDialog = new CFindReplaceDialog();
236 m_pFindDialog->Create(TRUE, L"", nullptr, FR_DOWN | FR_HIDEWHOLEWORD | FR_HIDEUPDOWN, this);
237 CTheme::Instance().SetThemeForDialog(m_pFindDialog->GetSafeHwnd(), CTheme::Instance().IsDarkTheme());
240 LRESULT CRefLogDlg::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
242 ASSERT(m_pFindDialog);
244 if (m_RefList.m_arShownList.empty())
245 return 0;
247 // If the FR_DIALOGTERM flag is set,
248 // invalidate the handle identifying the dialog box.
249 if (m_pFindDialog->IsTerminating())
251 m_pFindDialog = nullptr;
252 return 0;
255 // If the FR_FINDNEXT flag is set,
256 // call the application-defined search routine
257 // to search for the requested string.
258 if (m_pFindDialog->FindNext())
260 //read data from dialog
261 CString findString = m_pFindDialog->GetFindString();
263 bool bFound = false;
264 const bool bCaseSensitive = !!(m_pFindDialog->MatchCase());
266 if (!bCaseSensitive)
267 findString.MakeLower();
269 size_t i = m_nSearchLine;
270 if (i >= m_RefList.m_arShownList.size())
272 i = 0;
273 m_pFindDialog->FlashWindowEx(FLASHW_ALL, 2, 100);
278 GitRevLoglist* data = m_RefList.m_arShownList.SafeGetAt(i);
280 CString str;
281 str += data->m_Ref;
282 str += L'\n';
283 str += data->m_RefAction;
284 str += L'\n';
285 str += data->m_CommitHash.ToString();
286 str += L'\n';
287 str += data->GetSubject();
288 str += L'\n';
289 str += data->GetBody();
290 str += L'\n';
292 if (!bCaseSensitive)
293 str.MakeLower();
295 if (str.Find(findString) >= 0)
296 bFound = true;
298 ++i;
299 if(!bFound && i >= m_RefList.m_arShownList.size())
300 i=0;
301 } while (i != m_nSearchLine && (!bFound));
303 if (bFound)
305 m_RefList.SetHotItem(static_cast<int>(i) - 1);
306 m_RefList.EnsureVisible(static_cast<int>(i) - 1, FALSE);
307 m_nSearchLine = i;
309 else
310 MessageBox(L'"' + findString + L"\" " + CString(MAKEINTRESOURCE(IDS_NOTFOUND)), L"TortoiseGit", MB_ICONINFORMATION);
313 return 0;