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
24 #include "RefLogDlg.h"
27 #include "MessageBox.h"
28 #include "UnicodeUtils.h"
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
)
63 LRESULT
CRefLogDlg::OnRefLogChanged(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
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
);
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();
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
);
112 m_SelectedHash
= pLogEntry
->m_CommitHash
;
118 void CRefLogDlg::OnBnClickedClearStash()
120 size_t count
= m_RefList
.m_arShownList
.size();
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)
126 if (g_Git
.Run(L
"git.exe stash clear", &cmdOut
, CP_UTF8
))
128 MessageBox(cmdOut
, L
"TortoiseGit", MB_ICONERROR
);
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;
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
);
171 GetDlgItem(IDOK
)->SetFocus();
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
)
184 else if (pMsg
->message
== WM_KEYDOWN
&& (pMsg
->wParam
== VK_F3
|| (pMsg
->wParam
== 'F' && (GetAsyncKeyState(VK_CONTROL
) & 0x8000))))
187 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
190 void CRefLogDlg::OnLvnItemchangedRefLoglist(NMHDR
* pNMHDR
, LRESULT
* pResult
)
192 auto pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
194 if (pNMLV
->iItem
< 0)
196 m_RefList
.m_nSearchIndex
= pNMLV
->iItem
;
197 m_nSearchLine
= pNMLV
->iItem
;
200 void CRefLogDlg::Refresh()
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";
213 for (int i
= 0; i
< static_cast<int>(list
.size()); ++i
)
215 if (list
[i
] == m_CurrentBranch
)
217 m_ChooseRef
.SetCurSel(i
);
223 m_ChooseRef
.SetCurSel(0); /* Choose HEAD */
228 void CRefLogDlg::OnFind()
232 m_pFindDialog
->SetFocus();
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())
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;
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();
264 const bool bCaseSensitive
= !!(m_pFindDialog
->MatchCase());
267 findString
.MakeLower();
269 size_t i
= m_nSearchLine
;
270 if (i
>= m_RefList
.m_arShownList
.size())
273 m_pFindDialog
->FlashWindowEx(FLASHW_ALL
, 2, 100);
278 GitRevLoglist
* data
= m_RefList
.m_arShownList
.SafeGetAt(i
);
283 str
+= data
->m_RefAction
;
285 str
+= data
->m_CommitHash
.ToString();
287 str
+= data
->GetSubject();
289 str
+= data
->GetBody();
295 if (str
.Find(findString
) >= 0)
299 if(!bFound
&& i
>= m_RefList
.m_arShownList
.size())
301 } while (i
!= m_nSearchLine
&& (!bFound
));
305 m_RefList
.SetHotItem(static_cast<int>(i
) - 1);
306 m_RefList
.EnsureVisible(static_cast<int>(i
) - 1, FALSE
);
310 MessageBox(L
'"' + findString
+ L
"\" " + CString(MAKEINTRESOURCE(IDS_NOTFOUND
)), L
"TortoiseGit", MB_ICONINFORMATION
);