1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2009-2014 - 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
/*=NULL*/)
37 : CResizableStandAloneDialog(CRefLogDlg::IDD
, pParent
)
44 CRefLogDlg::~CRefLogDlg()
48 void CRefLogDlg::DoDataExchange(CDataExchange
* pDX
)
50 CDialog::DoDataExchange(pDX
);
51 DDX_Control(pDX
, IDC_COMBOBOXEX_REF
, m_ChooseRef
);
52 DDX_Control(pDX
, IDC_REFLOG_LIST
, m_RefList
);
56 BEGIN_MESSAGE_MAP(CRefLogDlg
, CResizableStandAloneDialog
)
57 ON_BN_CLICKED(IDOK
, &CRefLogDlg::OnBnClickedOk
)
58 ON_BN_CLICKED(IDC_REFLOG_BUTTONCLEARSTASH
, &CRefLogDlg::OnBnClickedClearStash
)
59 ON_CBN_SELCHANGE(IDC_COMBOBOXEX_REF
, &CRefLogDlg::OnCbnSelchangeRef
)
60 ON_MESSAGE(MSG_REFLOG_CHANGED
,OnRefLogChanged
)
61 ON_REGISTERED_MESSAGE(m_FindDialogMessage
, OnFindDialogMessage
)
64 LRESULT
CRefLogDlg::OnRefLogChanged(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
66 m_RefList
.m_RevCache
.clear();
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_REFLOG_LIST
,TOP_LEFT
,BOTTOM_RIGHT
);
80 AddAnchor(IDHELP
, BOTTOM_RIGHT
);
81 AddAnchor(IDC_COMBOBOXEX_REF
, TOP_LEFT
, TOP_RIGHT
);
84 this->EnableSaveRestore(_T("RefLogDlg"));
87 GetWindowText(sWindowTitle
);
88 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
90 m_ChooseRef
.SetMaxHistoryItems(0x7FFFFFFF);
92 m_RefList
.m_hasWC
= !g_GitAdminDir
.IsBareRepo(g_Git
.m_CurrentDir
);
94 this->m_RefList
.InsertRefLogColumn();
100 // CRefLogDlg message handlers
102 void CRefLogDlg::OnBnClickedOk()
104 if (m_RefList
.GetSelectedCount() == 1)
106 // get the selected row
107 POSITION pos
= m_RefList
.GetFirstSelectedItemPosition();
108 int selIndex
= m_RefList
.GetNextSelectedItem(pos
);
109 if (selIndex
< m_RefList
.m_arShownList
.GetCount())
111 // all ok, pick up the revision
112 GitRev
* pLogEntry
= reinterpret_cast<GitRev
*>(m_RefList
.m_arShownList
.GetAt(selIndex
));
114 m_SelectedHash
= pLogEntry
->m_CommitHash
;
120 void CRefLogDlg::OnBnClickedClearStash()
122 if (CMessageBox::Show(this->GetSafeHwnd(), IDS_PROC_DELETEALLSTASH
, IDS_APPNAME
, 2, IDI_QUESTION
, IDS_DELETEBUTTON
, IDS_ABORTBUTTON
) == 1)
125 if (g_Git
.Run(_T("git.exe stash clear"), &cmdOut
, CP_UTF8
))
127 MessageBox(cmdOut
, _T("TortoiseGit"), MB_ICONERROR
);
131 m_RefList
.m_RevCache
.clear();
137 int AddToRefLoglist(unsigned char * /*osha1*/, unsigned char *nsha1
, const char * /*name*/, unsigned long time
, int /*sz*/, const char *msg
, void *data
)
139 std::vector
<GitRev
> *vector
= (std::vector
<GitRev
> *)data
;
141 rev
.m_CommitHash
= (char *)nsha1
;
142 rev
.GetCommitterDate() = CTime(time
);
145 g_Git
.StringAppend(&one
, (BYTE
*)msg
);
147 int message
= one
.Find(_T(":"), 0);
150 rev
.m_RefAction
= one
.Left(message
);
151 rev
.GetSubject() = one
.Mid(message
+ 1);
154 vector
->insert(vector
->begin(), rev
);
159 int ParserFromRefLog(CString ref
, std::vector
<GitRev
> &refloglist
)
162 if (g_Git
.m_IsUseLibGit2
)
164 CAutoRepository
repo(g_Git
.GetGitRepository());
167 MessageBox(nullptr, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_ICONERROR
);
172 if (git_reflog_read(reflog
.GetPointer(), repo
, CUnicodeUtils::GetUTF8(ref
)) < 0)
174 MessageBox(nullptr, CGit::GetLibGit2LastErr(_T("Could not read reflog.")), _T("TortoiseGit"), MB_ICONERROR
);
178 for (size_t i
= 0; i
< git_reflog_entrycount(reflog
); ++i
)
180 const git_reflog_entry
*entry
= git_reflog_entry_byindex(reflog
, i
);
185 rev
.m_CommitHash
= (char *)git_reflog_entry_id_new(entry
)->id
;
186 rev
.m_Ref
.Format(_T("%s@{%d}"), ref
, i
);
187 rev
.GetCommitterDate() = CTime(git_reflog_entry_committer(entry
)->when
.time
);
188 if (git_reflog_entry_message(entry
) != nullptr)
191 g_Git
.StringAppend(&one
, (BYTE
*)git_reflog_entry_message(entry
));
192 int message
= one
.Find(_T(":"), 0);
195 rev
.m_RefAction
= one
.Left(message
);
196 rev
.GetSubject() = one
.Mid(message
+ 1);
199 refloglist
.push_back(rev
);
202 else if (g_Git
.m_IsUseGitDLL
)
204 git_for_each_reflog_ent(CUnicodeUtils::GetUTF8(ref
), AddToRefLoglist
, &refloglist
);
205 for (size_t i
= 0; i
< refloglist
.size(); ++i
)
206 refloglist
[i
].m_Ref
.Format(_T("%s@{%d}"), ref
, i
);
212 cmd
.Format(_T("git.exe reflog show --pretty=\"%%H %%gD: %%gs\" --date=raw %s"), ref
);
213 if (g_Git
.Run(cmd
, &out
, NULL
, CP_UTF8
))
217 CString prefix
= ref
+ _T("@{");
221 CString one
= out
.Tokenize(_T("\n"), pos
);
222 int refPos
= one
.Find(_T(' '), 0);
228 CString hashStr
= one
.Left(refPos
);
229 rev
.m_CommitHash
= hashStr
;
230 rev
.m_Ref
.Format(_T("%s@{%d}"), ref
, i
++);
231 int prefixPos
= one
.Find(prefix
, refPos
+ 1);
232 if (prefixPos
!= refPos
+ 1)
235 int spacePos
= one
.Find(_T(' '), prefixPos
+ prefix
.GetLength() + 1);
239 CString timeStr
= one
.Mid(prefixPos
+ prefix
.GetLength(), spacePos
- prefixPos
- prefix
.GetLength());
240 rev
.GetCommitterDate() = CTime(_ttoi(timeStr
));
241 int action
= one
.Find(_T("}: "), spacePos
+ 1);
245 int message
= one
.Find(_T(":"), action
);
248 rev
.m_RefAction
= one
.Mid(action
+ 1, message
- action
- 1);
249 rev
.GetSubject() = one
.Right(one
.GetLength() - message
- 1);
253 refloglist
.push_back(rev
);
260 void CRefLogDlg::OnCbnSelchangeRef()
262 CString ref
=m_ChooseRef
.GetString();
263 m_RefList
.ClearText();
265 //this->m_logEntries.ParserFromLog();
266 m_RefList
.SetRedraw(false);
268 ParserFromRefLog(ref
, m_RefList
.m_RevCache
);
270 m_RefList
.SetItemCountEx((int)m_RefList
.m_RevCache
.size());
272 this->m_RefList
.m_arShownList
.RemoveAll();
274 for (unsigned int i
= 0; i
< m_RefList
.m_RevCache
.size(); ++i
)
276 GitRev
*rev
= &m_RefList
.m_RevCache
[i
];
277 rev
->m_IsFull
= TRUE
;
278 this->m_RefList
.m_arShownList
.Add(rev
);
281 m_RefList
.SetRedraw(true);
283 m_RefList
.Invalidate();
285 if (ref
== _T("refs/stash"))
287 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH
)->ShowWindow(SW_SHOW
);
288 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH
)->EnableWindow((m_RefList
.m_arShownList
.GetSize() > 0));
291 GetDlgItem(IDC_REFLOG_BUTTONCLEARSTASH
)->ShowWindow(SW_HIDE
);
294 BOOL
CRefLogDlg::PreTranslateMessage(MSG
* pMsg
)
296 if (pMsg
->message
== WM_KEYDOWN
&& pMsg
->wParam
== VK_F5
)
298 else if (pMsg
->message
== WM_KEYDOWN
&& (pMsg
->wParam
== VK_F3
|| (pMsg
->wParam
== 'F' && (GetAsyncKeyState(VK_CONTROL
) & 0x8000))))
301 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
304 void CRefLogDlg::Refresh()
307 list
.push_back(_T("HEAD"));
308 if (g_Git
.GetRefList(list
))
309 MessageBox(g_Git
.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR
);
311 m_ChooseRef
.SetList(list
);
313 if (m_CurrentBranch
.IsEmpty())
315 m_CurrentBranch
.Format(_T("refs/heads/%s"), g_Git
.GetCurrentBranch());
316 m_ChooseRef
.SetCurSel(0); /* Choose HEAD */
321 for (int i
= 0; i
< (int)list
.size(); ++i
)
323 if(list
[i
] == m_CurrentBranch
)
325 m_ChooseRef
.SetCurSel(i
);
331 m_ChooseRef
.SetCurSel(0);
334 m_RefList
.m_RevCache
.clear();
339 void CRefLogDlg::OnFind()
342 m_pFindDialog
= new CFindReplaceDialog();
343 m_pFindDialog
->Create(TRUE
, _T(""), NULL
, FR_DOWN
| FR_HIDEWHOLEWORD
| FR_HIDEUPDOWN
, this);
346 LRESULT
CRefLogDlg::OnFindDialogMessage(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
348 ASSERT(m_pFindDialog
!= NULL
);
350 if (m_RefList
.m_arShownList
.IsEmpty())
353 // If the FR_DIALOGTERM flag is set,
354 // invalidate the handle identifying the dialog box.
355 if (m_pFindDialog
->IsTerminating())
357 m_pFindDialog
= NULL
;
361 // If the FR_FINDNEXT flag is set,
362 // call the application-defined search routine
363 // to search for the requested string.
364 if (m_pFindDialog
->FindNext())
366 //read data from dialog
367 CString findString
= m_pFindDialog
->GetFindString();
370 bool bCaseSensitive
= !!(m_pFindDialog
->m_nFlags
& FR_MATCHCASE
);
373 findString
.MakeLower();
375 int i
= m_nSearchLine
;
376 if (i
< 0 || i
>= m_RefList
.m_arShownList
.GetCount())
381 GitRev
* data
= (GitRev
*)m_RefList
.m_arShownList
.SafeGetAt(i
);
386 str
+= data
->m_RefAction
;
388 str
+= data
->m_CommitHash
.ToString();
390 str
+= data
->GetSubject();
392 str
+= data
->GetBody();
398 if (str
.Find(findString
) >= 0)
402 if(!bFound
&& i
>= m_RefList
.m_arShownList
.GetCount())
404 } while (i
!= m_nSearchLine
&& (!bFound
));
408 m_RefList
.SetHotItem(i
- 1);
409 m_RefList
.EnsureVisible(i
- 1, FALSE
);
413 MessageBox(_T("\"") + findString
+ _T("\" ") + CString(MAKEINTRESOURCE(IDS_NOTFOUND
)), _T("TortoiseGit"), MB_ICONINFORMATION
);