Fixed issue #2550: Search functionality on message in the RefLog window
[TortoiseGit.git] / src / TortoiseProc / RefLogDlg.cpp
blob613c4566922e525c68fbb0bd1ce928efd2c7ee77
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2009-2017 - 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)
38 , m_pFindDialog(nullptr)
39 , m_nSearchLine(0)
43 CRefLogDlg::~CRefLogDlg()
47 void CRefLogDlg::DoDataExchange(CDataExchange* pDX)
49 CDialog::DoDataExchange(pDX);
50 DDX_Control(pDX, IDC_COMBOBOXEX_REF, m_ChooseRef);
51 DDX_Control(pDX, IDC_REFLOG_LIST, m_RefList);
55 BEGIN_MESSAGE_MAP(CRefLogDlg, CResizableStandAloneDialog)
56 ON_BN_CLICKED(IDOK, &CRefLogDlg::OnBnClickedOk)
57 ON_BN_CLICKED(IDC_REFLOG_BUTTONCLEARSTASH, &CRefLogDlg::OnBnClickedClearStash)
58 ON_CBN_SELCHANGE(IDC_COMBOBOXEX_REF, &CRefLogDlg::OnCbnSelchangeRef)
59 ON_MESSAGE(MSG_REFLOG_CHANGED,OnRefLogChanged)
60 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
61 ON_BN_CLICKED(IDC_SEARCH, OnFind)
62 END_MESSAGE_MAP()
64 LRESULT CRefLogDlg::OnRefLogChanged(WPARAM /*wParam*/, LPARAM /*lParam*/)
66 m_RefList.m_RevCache.clear();
67 OnCbnSelchangeRef();
68 return 0;
71 BOOL CRefLogDlg::OnInitDialog()
73 CResizableStandAloneDialog::OnInitDialog();
74 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
76 AddAnchor(IDOK,BOTTOM_RIGHT);
77 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
78 AddAnchor(IDC_REFLOG_BUTTONCLEARSTASH, BOTTOM_LEFT);
79 AddAnchor(IDC_SEARCH, BOTTOM_LEFT);
80 AddAnchor(IDC_REFLOG_LIST,TOP_LEFT,BOTTOM_RIGHT);
81 AddAnchor(IDHELP, BOTTOM_RIGHT);
82 AddAnchor(IDC_COMBOBOXEX_REF, TOP_LEFT, TOP_RIGHT);
84 AddOthersToAnchor();
85 this->EnableSaveRestore(L"RefLogDlg");
87 CString sWindowTitle;
88 GetWindowText(sWindowTitle);
89 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
91 m_ChooseRef.SetMaxHistoryItems(0x7FFFFFFF);
93 m_RefList.m_hasWC = !GitAdminDir::IsBareRepo(g_Git.m_CurrentDir);
95 this->m_RefList.InsertRefLogColumn();
97 Refresh();
99 return TRUE;
101 // CRefLogDlg message handlers
103 void CRefLogDlg::OnBnClickedOk()
105 if (m_RefList.GetSelectedCount() == 1)
107 // get the selected row
108 POSITION pos = m_RefList.GetFirstSelectedItemPosition();
109 size_t selIndex = m_RefList.GetNextSelectedItem(pos);
110 if (selIndex < m_RefList.m_arShownList.size())
112 // all ok, pick up the revision
113 GitRev* pLogEntry = m_RefList.m_arShownList.SafeGetAt(selIndex);
114 // extract the hash
115 m_SelectedHash = pLogEntry->m_CommitHash;
119 OnOK();
121 void CRefLogDlg::OnBnClickedClearStash()
123 size_t count = m_RefList.m_arShownList.size();
124 CString msg;
125 msg.Format(IDS_PROC_DELETEALLSTASH, count);
126 if (CMessageBox::Show(this->GetSafeHwnd(), msg, L"TortoiseGit", 2, IDI_QUESTION, CString(MAKEINTRESOURCE(IDS_DELETEBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 1)
128 CString cmdOut;
129 if (g_Git.Run(L"git.exe stash clear", &cmdOut, CP_UTF8))
131 MessageBox(cmdOut, L"TortoiseGit", MB_ICONERROR);
132 return;
135 m_RefList.m_RevCache.clear();
137 OnCbnSelchangeRef();
141 void CRefLogDlg::OnCbnSelchangeRef()
143 CString ref=m_ChooseRef.GetString();
144 m_RefList.ClearText();
146 m_RefList.SetRedraw(false);
148 CString err;
149 if (GitRevLoglist::GetRefLog(ref, m_RefList.m_RevCache, err))
150 MessageBox(L"Error while loading reflog.\n" + err, L"TortoiseGit", MB_ICONERROR);
152 m_RefList.SetItemCountEx((int)m_RefList.m_RevCache.size());
154 this->m_RefList.m_arShownList.clear();
156 for (unsigned int i = 0; i < m_RefList.m_RevCache.size(); ++i)
158 GitRevLoglist* rev = &m_RefList.m_RevCache[i];
159 rev->m_IsFull = TRUE;
160 this->m_RefList.m_arShownList.SafeAdd(rev);
163 m_RefList.SetRedraw(true);
165 m_RefList.Invalidate();
167 if (ref == L"refs/stash")
169 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->ShowWindow(SW_SHOW);
170 BOOL enabled = !m_RefList.m_arShownList.empty();
171 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->EnableWindow(enabled);
172 if (!enabled)
173 GetDlgItem(IDOK)->SetFocus();
175 else
176 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH)->ShowWindow(SW_HIDE);
179 BOOL CRefLogDlg::PreTranslateMessage(MSG* pMsg)
181 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F5)
182 Refresh();
183 else if (pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_F3 || (pMsg->wParam == 'F' && (GetAsyncKeyState(VK_CONTROL) & 0x8000))))
184 OnFind();
186 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
189 void CRefLogDlg::Refresh()
191 STRING_VECTOR list;
192 list.push_back(L"HEAD");
193 if (g_Git.GetRefList(list))
194 MessageBox(g_Git.GetGitLastErr(L"Could not get all refs."), L"TortoiseGit", MB_ICONERROR);
196 m_ChooseRef.SetList(list);
198 if (m_CurrentBranch.IsEmpty())
200 m_CurrentBranch.Format(L"refs/heads/%s", (LPCTSTR)g_Git.GetCurrentBranch());
201 m_ChooseRef.SetCurSel(0); /* Choose HEAD */
203 else
205 bool found = false;
206 for (int i = 0; i < (int)list.size(); ++i)
208 if(list[i] == m_CurrentBranch)
210 m_ChooseRef.SetCurSel(i);
211 found = true;
212 break;
215 if (!found)
216 m_ChooseRef.SetCurSel(0);
219 m_RefList.m_RevCache.clear();
221 OnCbnSelchangeRef();
224 void CRefLogDlg::OnFind()
226 m_nSearchLine = 0;
227 m_pFindDialog = new CFindReplaceDialog();
228 m_pFindDialog->Create(TRUE, L"", nullptr, FR_DOWN | FR_HIDEWHOLEWORD | FR_HIDEUPDOWN, this);
231 LRESULT CRefLogDlg::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
233 ASSERT(m_pFindDialog);
235 if (m_RefList.m_arShownList.empty())
236 return 0;
238 // If the FR_DIALOGTERM flag is set,
239 // invalidate the handle identifying the dialog box.
240 if (m_pFindDialog->IsTerminating())
242 m_pFindDialog = nullptr;
243 return 0;
246 // If the FR_FINDNEXT flag is set,
247 // call the application-defined search routine
248 // to search for the requested string.
249 if (m_pFindDialog->FindNext())
251 //read data from dialog
252 CString findString = m_pFindDialog->GetFindString();
254 bool bFound = false;
255 bool bCaseSensitive = !!(m_pFindDialog->m_nFlags & FR_MATCHCASE);
257 if (!bCaseSensitive)
258 findString.MakeLower();
260 size_t i = m_nSearchLine;
261 if (i >= m_RefList.m_arShownList.size())
262 i = 0;
266 GitRevLoglist* data = m_RefList.m_arShownList.SafeGetAt(i);
268 CString str;
269 str += data->m_Ref;
270 str += L'\n';
271 str += data->m_RefAction;
272 str += L'\n';
273 str += data->m_CommitHash.ToString();
274 str += L'\n';
275 str += data->GetSubject();
276 str += L'\n';
277 str += data->GetBody();
278 str += L'\n';
280 if (!bCaseSensitive)
281 str.MakeLower();
283 if (str.Find(findString) >= 0)
284 bFound = true;
286 ++i;
287 if(!bFound && i >= m_RefList.m_arShownList.size())
288 i=0;
289 } while (i != m_nSearchLine && (!bFound));
291 if (bFound)
293 m_RefList.SetHotItem((int)i - 1);
294 m_RefList.EnsureVisible((int)i - 1, FALSE);
295 m_nSearchLine = i;
297 else
298 MessageBox(L'"' + findString + L"\" " + CString(MAKEINTRESOURCE(IDS_NOTFOUND)), L"TortoiseGit", MB_ICONINFORMATION);
301 return 0;