Do not pass big read-only parameters per value
[TortoiseGit.git] / src / TortoiseProc / FileDiffDlg.cpp
blob9ec86b29f59e5d9f34a954f1e0ffa02dd78cf859
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - 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 "UnicodeUtils.h"
23 #include "MessageBox.h"
24 #include "AppUtils.h"
25 #include "TempFile.h"
26 #include "SysImageList.h"
27 #include "IconMenu.h"
28 #include "StringUtils.h"
29 #include "PathUtils.h"
30 #include "BrowseFolder.h"
31 #include "FileDiffDlg.h"
32 #include "GitDiff.h"
33 #include "LoglistCommonResource.h"
34 #include "LoglistUtils.h"
35 #include "BrowseRefsDlg.h"
36 #include "LogDlg.h"
37 #include "RefLogDlg.h"
38 #include "GitStatusListCtrl.h"
39 #include "FormatMessageWrapper.h"
41 #define ID_COMPARE 1
42 #define ID_BLAME 2
43 #define ID_SAVEAS 3
44 #define ID_EXPORT 4
45 #define ID_CLIPBOARD_PATH 5
46 #define ID_CLIPBOARD_ALL 6
47 #define ID_LOG 7
48 #define ID_GNUDIFFCOMPARE 8
49 #define ID_REVERT1 9
50 #define ID_REVERT2 10
52 BOOL CFileDiffDlg::m_bAscending = FALSE;
53 int CFileDiffDlg::m_nSortedColumn = -1;
55 UINT CFileDiffDlg::WM_DISABLEBUTTONS = RegisterWindowMessage(_T("TORTOISEGIT_FILEDIFF_DISABLEBUTTONS"));
56 UINT CFileDiffDlg::WM_DIFFFINISHED = RegisterWindowMessage(_T("TORTOISEGIT_FILEDIFF_DIFFFINISHED"));
58 IMPLEMENT_DYNAMIC(CFileDiffDlg, CResizableStandAloneDialog)
59 CFileDiffDlg::CFileDiffDlg(CWnd* pParent /*=NULL*/)
60 : CResizableStandAloneDialog(CFileDiffDlg::IDD, pParent)
61 , m_bBlame(false)
62 , m_pProgDlg(NULL)
63 , m_bCancelled(false)
64 , m_nIconFolder(0)
65 , m_bThreadRunning(FALSE)
67 m_bLoadingRef=FALSE;
70 CFileDiffDlg::~CFileDiffDlg()
74 void CFileDiffDlg::DoDataExchange(CDataExchange* pDX)
76 CResizableStandAloneDialog::DoDataExchange(pDX);
77 DDX_Control(pDX, IDC_FILELIST, m_cFileList);
78 DDX_Control(pDX, IDC_SWITCHLEFTRIGHT, m_SwitchButton);
79 DDX_Control(pDX, IDC_REV1BTN, m_cRev1Btn);
80 DDX_Control(pDX, IDC_REV2BTN, m_cRev2Btn);
81 DDX_Control(pDX, IDC_FILTER, m_cFilter);
82 DDX_Control(pDX, IDC_REV1EDIT, m_ctrRev1Edit);
83 DDX_Control(pDX, IDC_REV2EDIT, m_ctrRev2Edit);
87 BEGIN_MESSAGE_MAP(CFileDiffDlg, CResizableStandAloneDialog)
88 ON_NOTIFY(NM_DBLCLK, IDC_FILELIST, OnNMDblclkFilelist)
89 ON_NOTIFY(LVN_GETINFOTIP, IDC_FILELIST, OnLvnGetInfoTipFilelist)
90 ON_NOTIFY(NM_CUSTOMDRAW, IDC_FILELIST, OnNMCustomdrawFilelist)
91 ON_WM_CONTEXTMENU()
92 ON_WM_SETCURSOR()
93 ON_EN_SETFOCUS(IDC_SECONDURL, &CFileDiffDlg::OnEnSetfocusSecondurl)
94 ON_EN_SETFOCUS(IDC_FIRSTURL, &CFileDiffDlg::OnEnSetfocusFirsturl)
95 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT, &CFileDiffDlg::OnBnClickedSwitchleftright)
96 ON_NOTIFY(HDN_ITEMCLICK, 0, &CFileDiffDlg::OnHdnItemclickFilelist)
97 ON_BN_CLICKED(IDC_REV1BTN, &CFileDiffDlg::OnBnClickedRev1btn)
98 ON_BN_CLICKED(IDC_REV2BTN, &CFileDiffDlg::OnBnClickedRev2btn)
99 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)
100 ON_EN_CHANGE(IDC_FILTER, &CFileDiffDlg::OnEnChangeFilter)
101 ON_WM_TIMER()
102 ON_MESSAGE(ENAC_UPDATE, &CFileDiffDlg::OnEnUpdate)
103 ON_MESSAGE(MSG_REF_LOADED, OnRefLoad)
104 ON_REGISTERED_MESSAGE(WM_DISABLEBUTTONS, OnDisableButtons)
105 ON_REGISTERED_MESSAGE(WM_DIFFFINISHED, OnDiffFinished)
106 ON_BN_CLICKED(IDC_LOG, &CFileDiffDlg::OnBnClickedLog)
107 END_MESSAGE_MAP()
110 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1, const GitRev &rev2)
112 if(path!=NULL)
114 m_path1 = *path;
115 m_path2 = *path;
116 m_sFilter = path->GetGitPathString();
118 m_rev1 = rev1;
119 m_rev2 = rev2;
122 void CFileDiffDlg::SetDiff(const CTGitPath * path, const CString &hash1, const CString &hash2)
124 if(path!=NULL)
126 m_path1 = *path;
127 m_path2 = *path;
128 m_sFilter = path->GetGitPathString();
131 BYTE_VECTOR logout;
133 if(hash1 == GIT_REV_ZERO)
135 m_rev1.m_CommitHash.Empty();
136 m_rev1.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
138 else
142 m_rev1.GetCommit(hash1);
144 catch (const char *msg)
146 MessageBox(_T("Could not get commit ") + hash1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
150 logout.clear();
152 if(hash2 == GIT_REV_ZERO)
154 m_rev2.m_CommitHash.Empty();
155 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
157 else
161 m_rev2.GetCommit(hash2);
163 catch (const char *msg)
165 MessageBox(_T("Could not get commit ") + hash2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
170 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1)
172 if(path!=NULL)
174 m_path1 = *path;
175 m_path2 = *path;
176 m_sFilter = path->GetGitPathString();
178 m_rev1 = rev1;
179 m_rev2.m_CommitHash.Empty();
180 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_PROC_PREVIOUSVERSION));
182 //this->GetDlgItem()->EnableWindow(FALSE);
185 BOOL CFileDiffDlg::OnInitDialog()
187 CResizableStandAloneDialog::OnInitDialog();
188 CString temp;
190 CString sWindowTitle;
191 GetWindowText(sWindowTitle);
192 CString pathText = g_Git.m_CurrentDir;
193 if (!m_path1.IsEmpty())
194 pathText = g_Git.m_CurrentDir + _T("\\") + m_path1.GetWinPathString();
195 CAppUtils::SetWindowTitle(m_hWnd, pathText, sWindowTitle);
197 this->m_ctrRev1Edit.Init();
198 this->m_ctrRev2Edit.Init();
200 m_tooltips.Create(this);
201 m_tooltips.AddTool(IDC_SWITCHLEFTRIGHT, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT);
203 m_cFileList.SetRedraw(false);
204 m_cFileList.DeleteAllItems();
205 DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
206 m_cFileList.SetExtendedStyle(exStyle);
208 m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();
209 m_cFileList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);
211 m_SwitchButton.SetImage((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
212 m_SwitchButton.Invalidate();
214 m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);
215 m_cFilter.SetInfoIcon(IDI_FILTEREDIT);
216 temp.LoadString(IDS_FILEDIFF_FILTERCUE);
217 temp = _T(" ")+temp;
218 m_cFilter.SetCueBanner(temp);
219 if (!m_sFilter.IsEmpty())
220 m_cFilter.SetWindowText(m_sFilter);
222 int c = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
223 while (c>=0)
224 m_cFileList.DeleteColumn(c--);
226 temp.LoadString(IDS_FILEDIFF_FILE);
227 m_cFileList.InsertColumn(0, temp);
228 temp.LoadString(IDS_FILEDIFF_EXT);
229 m_cFileList.InsertColumn(1, temp);
230 temp.LoadString(IDS_FILEDIFF_ACTION);
231 m_cFileList.InsertColumn(2, temp);
233 temp.LoadString(IDS_FILEDIFF_STATADD);
234 m_cFileList.InsertColumn(3, temp);
235 temp.LoadString(IDS_FILEDIFF_STATDEL);
236 m_cFileList.InsertColumn(4, temp);
238 int mincol = 0;
239 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
240 int col;
241 for (col = mincol; col <= maxcol; col++)
243 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);
246 m_cFileList.SetRedraw(true);
248 AddAnchor(IDC_DIFFSTATIC1, TOP_LEFT, TOP_RIGHT);
249 AddAnchor(IDC_SWITCHLEFTRIGHT, TOP_RIGHT);
250 AddAnchor(IDC_FIRSTURL, TOP_LEFT, TOP_RIGHT);
251 AddAnchor(IDC_REV1BTN, TOP_RIGHT);
252 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
253 AddAnchor(IDC_SECONDURL, TOP_LEFT, TOP_RIGHT);
254 AddAnchor(IDC_REV2BTN, TOP_RIGHT);
255 AddAnchor(IDC_FILTER, TOP_LEFT, TOP_RIGHT);
256 AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);
257 AddAnchor(IDC_REV1GROUP,TOP_LEFT,TOP_RIGHT);
258 AddAnchor(IDC_REV2GROUP,TOP_LEFT,TOP_RIGHT);
259 AddAnchor(IDC_REV1EDIT,TOP_LEFT);
260 AddAnchor(IDC_REV2EDIT,TOP_LEFT);
261 AddAnchor(IDC_LOG, TOP_RIGHT);
263 EnableSaveRestore(_T("FileDiffDlg"));
265 if(this->m_strRev1.IsEmpty())
266 this->m_ctrRev1Edit.SetWindowText(this->m_rev1.m_CommitHash.ToString());
267 else
269 bool rev1fail = false;
272 rev1fail = !!m_rev1.GetCommit(m_strRev1);
274 catch (const char *msg)
276 rev1fail = true;
277 MessageBox(_T("Could not get commit ") + m_strRev1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
279 if (rev1fail)
281 CString msg;
282 msg.Format(IDS_PROC_REFINVALID, m_strRev1);
283 this->m_FileListText += msg;
286 this->m_ctrRev1Edit.SetWindowText(m_strRev1);
289 if(this->m_strRev2.IsEmpty())
290 this->m_ctrRev2Edit.SetWindowText(this->m_rev2.m_CommitHash.ToString());
291 else
293 bool rev2fail = false;
296 rev2fail = !!m_rev2.GetCommit(m_strRev2);
298 catch (const char *msg)
300 rev2fail = true;
301 MessageBox(_T("Could not get commit ") + m_strRev2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
303 if (rev2fail)
305 CString msg;
306 msg.Format(IDS_PROC_REFINVALID, m_strRev2);
307 this->m_FileListText += msg;
310 this->m_ctrRev2Edit.SetWindowText(m_strRev2);
313 SetURLLabels();
315 InterlockedExchange(&m_bThreadRunning, TRUE);
316 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
318 InterlockedExchange(&m_bThreadRunning, FALSE);
319 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
322 InterlockedExchange(&m_bLoadingRef, TRUE);
323 if (AfxBeginThread(LoadRefThreadEntry, this)==NULL)
325 InterlockedExchange(&m_bLoadingRef, FALSE);
326 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
329 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
330 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
331 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
333 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
334 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
335 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
337 // Start with focus on file list
338 GetDlgItem(IDC_FILELIST)->SetFocus();
340 if(m_rev2.m_CommitHash.IsEmpty())
341 m_SwitchButton.EnableWindow(FALSE);
343 KillTimer(IDT_INPUT);
344 return FALSE;
347 UINT CFileDiffDlg::DiffThreadEntry(LPVOID pVoid)
349 return ((CFileDiffDlg*)pVoid)->DiffThread();
352 UINT CFileDiffDlg::DiffThread()
354 SendMessage(WM_DISABLEBUTTONS);
356 if( m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty())
357 g_Git.RefreshGitIndex();
359 g_Git.GetCommitDiffList(m_rev1.m_CommitHash.ToString(),m_rev2.m_CommitHash.ToString(),m_arFileList);
361 SendMessage(WM_DIFFFINISHED);
363 InterlockedExchange(&m_bThreadRunning, FALSE);
364 return 0;
367 LRESULT CFileDiffDlg::OnDisableButtons(WPARAM, LPARAM)
369 RefreshCursor();
370 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT)));
371 m_cFileList.DeleteAllItems();
372 m_arFileList.Clear();
373 EnableInputControl(false);
374 return 0;
377 LRESULT CFileDiffDlg::OnDiffFinished(WPARAM, LPARAM)
379 CString sFilterText;
380 m_cFilter.GetWindowText(sFilterText);
381 m_cFileList.SetRedraw(false);
382 Filter(sFilterText);
383 if (m_arFileList.GetCount() > 0)
385 // Highlight first entry in file list
386 m_cFileList.SetSelectionMark(0);
387 m_cFileList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
390 int mincol = 0;
391 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
392 int col;
393 for (col = mincol; col <= maxcol; ++col)
395 m_cFileList.SetColumnWidth(col, LVSCW_AUTOSIZE_USEHEADER);
398 m_cFileList.ClearText();
399 if (m_arFileList.GetCount() == 0)
400 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_COMPAREREV_NODIFF)));
401 m_cFileList.SetRedraw(true);
403 InvalidateRect(NULL);
404 RefreshCursor();
405 EnableInputControl(true);
406 return 0;
409 int CFileDiffDlg::AddEntry(const CTGitPath * fd)
411 int ret = -1;
412 if (fd)
414 int index = m_cFileList.GetItemCount();
416 int icon_idx = 0;
417 if (fd->IsDirectory())
418 icon_idx = m_nIconFolder;
419 else
420 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(fd->GetGitPathString());
422 ret = m_cFileList.InsertItem(index, fd->GetGitPathString(), icon_idx);
423 m_cFileList.SetItemText(index, 1, ((CTGitPath*)fd)->GetFileExtension());
424 m_cFileList.SetItemText(index, 2, ((CTGitPath*)fd)->GetActionName());
425 m_cFileList.SetItemText(index, 3, ((CTGitPath*)fd)->m_StatAdd);
426 m_cFileList.SetItemText(index, 4, ((CTGitPath*)fd)->m_StatDel);
428 return ret;
431 void CFileDiffDlg::EnableInputControl(bool b)
433 this->m_ctrRev1Edit.EnableWindow(b);
434 this->m_ctrRev2Edit.EnableWindow(b);
435 this->m_cRev1Btn.EnableWindow(b);
436 this->m_cRev2Btn.EnableWindow(b);
437 m_cFilter.EnableWindow(b);
438 m_SwitchButton.EnableWindow(b);
439 GetDlgItem(IDC_LOG)->EnableWindow(b && !(m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty()));
442 void CFileDiffDlg::DoDiff(int selIndex, bool blame)
444 CGitDiff diff;
445 CTGitPath* fd2 = m_arFilteredList[selIndex];
446 CTGitPath* fd1 = fd2;
447 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
448 fd1 = new CTGitPath(fd2->GetGitOldPathString());
449 diff.Diff(fd2, fd1, this->m_rev1.m_CommitHash.ToString(), this->m_rev2.m_CommitHash.ToString(), blame, FALSE);
453 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)
455 *pResult = 0;
456 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
457 int selIndex = pNMLV->iItem;
458 if (selIndex < 0)
459 return;
460 if (selIndex >= (int)m_arFilteredList.size())
461 return;
463 DoDiff(selIndex, m_bBlame);
466 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR *pNMHDR, LRESULT *pResult)
469 LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);
470 if (pGetInfoTip->iItem >= (int)m_arFilteredList.size())
471 return;
473 CString path = m_path1.GetGitPathString() + _T("/") + m_arFilteredList[pGetInfoTip->iItem]->GetGitPathString();
474 if (pGetInfoTip->cchTextMax > path.GetLength())
475 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path, pGetInfoTip->cchTextMax);
477 *pResult = 0;
480 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR *pNMHDR, LRESULT *pResult)
482 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
483 // Take the default processing unless we set this to something else below.
484 *pResult = CDRF_DODEFAULT;
486 // First thing - check the draw stage. If it's the control's prepaint
487 // stage, then tell Windows we want messages for every item.
489 if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
491 *pResult = CDRF_NOTIFYITEMDRAW;
493 else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
495 // This is the prepaint stage for an item. Here's where we set the
496 // item's text color. Our return value will tell Windows to draw the
497 // item itself, but it will use the new color we set here.
499 // Tell Windows to paint the control itself.
500 *pResult = CDRF_DODEFAULT;
502 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
504 if (m_arFilteredList.size() > pLVCD->nmcd.dwItemSpec)
506 CTGitPath * fd = m_arFilteredList[pLVCD->nmcd.dwItemSpec];
507 switch (fd->m_Action)
509 case CTGitPath::LOGACTIONS_ADDED:
510 crText = m_colors.GetColor(CColors::Added);
511 break;
512 case CTGitPath::LOGACTIONS_DELETED:
513 crText = m_colors.GetColor(CColors::Deleted);
514 break;
515 case CTGitPath::LOGACTIONS_MODIFIED:
516 crText = m_colors.GetColor(CColors::Modified);
517 break;
518 default:
519 crText = m_colors.GetColor(CColors::PropertyChanged);
520 break;
523 // Store the color back in the NMLVCUSTOMDRAW struct.
524 pLVCD->clrText = crText;
528 UINT CFileDiffDlg::LoadRefThread()
530 g_Git.GetBranchList(m_Reflist,NULL,CGit::BRANCH_ALL_F);
531 g_Git.GetTagList(m_Reflist);
533 this->PostMessage(MSG_REF_LOADED);
534 InterlockedExchange(&m_bLoadingRef, FALSE);
535 return 0;
538 void CFileDiffDlg::OnContextMenu(CWnd* pWnd, CPoint point)
540 if ((pWnd==0)||(pWnd != &m_cFileList))
541 return;
542 if (m_cFileList.GetSelectedCount() == 0)
543 return;
544 // if the context menu is invoked through the keyboard, we have to use
545 // a calculated position on where to anchor the menu on
546 if ((point.x == -1) && (point.y == -1))
548 CRect rect;
549 m_cFileList.GetItemRect(m_cFileList.GetSelectionMark(), &rect, LVIR_LABEL);
550 m_cFileList.ClientToScreen(&rect);
551 point = rect.CenterPoint();
553 CIconMenu popup;
554 if (popup.CreatePopupMenu())
556 CString menuText;
557 popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);
558 popup.AppendMenuIcon(ID_GNUDIFFCOMPARE, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);
559 popup.AppendMenu(MF_SEPARATOR, NULL);
560 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev1.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
561 popup.AppendMenuIcon(ID_REVERT1, menuText, IDI_REVERT);
562 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev2.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
563 popup.AppendMenuIcon(ID_REVERT2, menuText, IDI_REVERT);
564 popup.AppendMenu(MF_SEPARATOR, NULL);
565 popup.AppendMenuIcon(ID_LOG, IDS_FILEDIFF_LOG, IDI_LOG);
566 popup.AppendMenuIcon(ID_BLAME, IDS_FILEDIFF_POPBLAME, IDI_BLAME);
567 popup.AppendMenu(MF_SEPARATOR, NULL);
568 popup.AppendMenuIcon(ID_EXPORT, IDS_FILEDIFF_POPEXPORT, IDI_EXPORT);
569 popup.AppendMenu(MF_SEPARATOR, NULL);
570 popup.AppendMenuIcon(ID_SAVEAS, IDS_FILEDIFF_POPSAVELIST, IDI_SAVEAS);
571 popup.AppendMenuIcon(ID_CLIPBOARD_PATH, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);
572 popup.AppendMenuIcon(ID_CLIPBOARD_ALL, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);
574 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
575 m_bCancelled = false;
576 switch (cmd)
578 case ID_COMPARE:
580 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
581 while (pos)
583 int index = m_cFileList.GetNextSelectedItem(pos);
584 DoDiff(index, false);
587 break;
588 case ID_GNUDIFFCOMPARE:
590 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
591 while (pos)
593 CTGitPath *fd2 = m_arFilteredList[m_cFileList.GetNextSelectedItem(pos)];
594 CTGitPath *fd1 = fd2;
595 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
596 fd1 = new CTGitPath(fd2->GetGitOldPathString());
597 CAppUtils::StartShowUnifiedDiff(m_hWnd, *fd2, m_rev2.m_CommitHash.ToString(), *fd1, m_rev1.m_CommitHash.ToString());
600 break;
601 case ID_REVERT1:
602 RevertSelectedItemToVersion(m_rev1.m_CommitHash.ToString());
603 break;
604 case ID_REVERT2:
605 RevertSelectedItemToVersion(m_rev2.m_CommitHash.ToString());
606 break;
607 case ID_BLAME:
609 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
610 while (pos)
612 int index = m_cFileList.GetNextSelectedItem(pos);
613 CAppUtils::LaunchTortoiseBlame(m_arFilteredList[index]->GetWinPathString(), m_rev1.m_CommitHash.ToString());
616 break;
617 case ID_LOG:
619 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
620 while (pos)
622 int index = m_cFileList.GetNextSelectedItem(pos);
623 CString cmd = _T("/command:log");
624 cmd += _T(" /path:\"")+m_arFilteredList[index]->GetWinPathString()+_T("\" ");
625 cmd += _T(" /endrev:")+m_rev1.m_CommitHash.ToString();
626 CAppUtils::RunTortoiseGitProc(cmd);
629 break;
630 case ID_SAVEAS:
632 if (m_cFileList.GetSelectedCount() > 0)
634 CString temp;
635 CTGitPath savePath;
636 CString pathSave;
637 if (!CAppUtils::FileOpenSave(pathSave, NULL, IDS_REPOBROWSE_SAVEAS, IDS_COMMONFILEFILTER, false, m_hWnd))
639 break;
641 savePath = CTGitPath(pathSave);
643 // now open the selected file for writing
646 CStdioFile file(savePath.GetWinPathString(), CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);
647 // temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, (LPCTSTR)m_path1.GetGitPathString(), (LPCTSTR)m_rev1.ToString(), (LPCTSTR)m_path2.GetGitPathString(), (LPCTSTR)m_rev2.ToString());
648 file.WriteString(temp + _T("\n"));
649 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
650 while (pos)
652 int index = m_cFileList.GetNextSelectedItem(pos);
653 CTGitPath* fd = m_arFilteredList[index];
654 file.WriteString(fd->GetGitPathString());
655 file.WriteString(_T("\n"));
657 file.Close();
659 catch (CFileException* pE)
661 pE->ReportError();
665 break;
666 case ID_CLIPBOARD_PATH:
668 CopySelectionToClipboard();
670 break;
672 case ID_CLIPBOARD_ALL:
674 CopySelectionToClipboard(TRUE);
676 break;
677 case ID_EXPORT:
679 // export all changed files to a folder
680 CBrowseFolder browseFolder;
681 browseFolder.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
682 if (browseFolder.Show(GetSafeHwnd(), m_strExportDir) == CBrowseFolder::OK)
684 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
685 while (pos)
687 int index = m_cFileList.GetNextSelectedItem(pos);
688 CTGitPath* fd = m_arFilteredList[index];
689 // we cannot export directories or folders
690 if (fd->m_Action == CTGitPath::LOGACTIONS_DELETED || fd->IsDirectory())
691 continue;
692 CAppUtils::CreateMultipleDirectory(m_strExportDir + _T("\\") + fd->GetContainingDirectory().GetWinPathString());
693 CString filename = m_strExportDir + _T("\\") + fd->GetWinPathString();
694 if(m_rev1.m_CommitHash.ToString() == GIT_REV_ZERO)
696 if(!CopyFile(g_Git.m_CurrentDir + _T("\\") + fd->GetWinPath(), filename, false))
698 MessageBox(CFormatMessageWrapper(), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
699 return;
702 else
704 if(g_Git.GetOneFile(m_rev1.m_CommitHash, *fd, filename))
706 CString out;
707 out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, fd->GetGitPathString(), m_rev1.m_CommitHash.ToString(), filename);
708 if (CMessageBox::Show(NULL, out, _T("TortoiseGit"), 2, IDI_WARNING, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
709 return;
716 break;
722 BOOL CFileDiffDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
724 if (pWnd != &m_cFileList)
725 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
726 if (m_bThreadRunning == 0)
728 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
729 SetCursor(hCur);
730 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
732 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
733 SetCursor(hCur);
734 return TRUE;
737 void CFileDiffDlg::OnEnSetfocusFirsturl()
739 GetDlgItem(IDC_FIRSTURL)->HideCaret();
742 void CFileDiffDlg::OnEnSetfocusSecondurl()
744 GetDlgItem(IDC_SECONDURL)->HideCaret();
748 void CFileDiffDlg::OnBnClickedSwitchleftright()
751 if (m_bThreadRunning)
752 return;
754 #if 0
755 CString sFilterString;
756 m_cFilter.GetWindowText(sFilterString);
758 m_cFileList.SetRedraw(false);
759 m_cFileList.DeleteAllItems();
760 for (int i=0; i<(int)m_arFileList.GetCount(); ++i)
762 CTGitPath fd = m_arFileList[i];
763 if (fd.m_Action == CTGitPath::LOGACTIONS_ADDED)
764 fd.m_Action = CTGitPath::LOGACTIONS_DELETED;
765 else if (fd.m_Action == CTGitPath::LOGACTIONS_DELETED)
766 fd.m_Action = CTGitPath::LOGACTIONS_ADDED;
767 std::swap(fd.m_StatAdd, fd.m_StatDel);
768 (CTGitPath&)m_arFileList[i] = fd;
770 Filter(sFilterString);
771 #endif
773 m_cFileList.SetRedraw(true);
774 CTGitPath path = m_path1;
775 m_path1 = m_path2;
776 m_path2 = path;
777 GitRev rev = m_rev1;
778 m_rev1 = m_rev2;
779 m_rev2 = rev;
781 CString str1,str2;
782 this->m_ctrRev1Edit.GetWindowText(str1);
783 this->m_ctrRev2Edit.GetWindowText(str2);
785 this->m_ctrRev1Edit.SetWindowText(str2);
786 this->m_ctrRev2Edit.SetWindowText(str1);
788 SetURLLabels();
789 //KillTimer(IDT_INPUT);
792 void CFileDiffDlg::SetURLLabels(int mask)
795 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
796 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
798 if(mask &0x1)
800 SetDlgItemText(IDC_FIRSTURL, m_rev1.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev1.GetSubject());
801 m_tooltips.AddTool(IDC_FIRSTURL,
802 CLoglistUtils::FormatDateAndTime(m_rev1.GetAuthorDate(), DATE_SHORTDATE, false) + _T(" ") + m_rev1.GetAuthorName());
806 if(mask &0x2)
808 SetDlgItemText(IDC_SECONDURL,m_rev2.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev2.GetSubject());
810 m_tooltips.AddTool(IDC_SECONDURL,
811 CLoglistUtils::FormatDateAndTime(m_rev2.GetAuthorDate(), DATE_SHORTDATE, false) + _T(" ") + m_rev2.GetAuthorName());
814 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASE)));
815 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1)));
817 if( (mask&0x3) == 0x3)
818 if(m_rev2.GetCommitterDate() > m_rev1.GetCommitterDate())
820 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASENEWER)));
822 else
824 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1NEWER)));
828 void CFileDiffDlg::ClearURLabels(int mask)
830 if(mask&0x1)
832 SetDlgItemText(IDC_FIRSTURL, _T(""));
833 m_tooltips.AddTool(IDC_FIRSTURL, _T(""));
836 if(mask&0x2)
838 SetDlgItemText(IDC_SECONDURL, _T(""));
839 m_tooltips.AddTool(IDC_SECONDURL, _T(""));
842 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)
844 m_tooltips.RelayEvent(pMsg);
845 if (pMsg->message == WM_KEYDOWN)
847 switch (pMsg->wParam)
849 case 'A':
851 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
853 // select all entries
854 for (int i=0; i<m_cFileList.GetItemCount(); ++i)
856 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
858 return TRUE;
861 break;
862 case 'C':
863 case VK_INSERT:
865 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
867 CopySelectionToClipboard();
868 return TRUE;
871 break;
872 case '\r':
874 if (GetFocus() == GetDlgItem(IDC_FILELIST))
876 // Return pressed in file list. Show diff, as for double click
877 int selIndex = m_cFileList.GetSelectionMark();
878 if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))
879 DoDiff(selIndex, m_bBlame);
880 return TRUE;
883 break;
884 case VK_F5:
886 OnTimer(IDT_INPUT);
888 break;
891 return __super::PreTranslateMessage(pMsg);
894 void CFileDiffDlg::OnCancel()
896 if (m_bThreadRunning)
898 m_bCancelled = true;
899 return;
901 __super::OnCancel();
904 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)
906 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
907 if (m_bThreadRunning)
908 return;
910 if (m_nSortedColumn == phdr->iItem)
911 m_bAscending = !m_bAscending;
912 else
913 m_bAscending = TRUE;
914 m_nSortedColumn = phdr->iItem;
915 Sort();
917 CString temp;
918 m_cFileList.SetRedraw(FALSE);
919 m_cFileList.DeleteAllItems();
920 m_cFilter.GetWindowText(temp);
921 Filter(temp);
923 CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();
924 HDITEM HeaderItem = {0};
925 HeaderItem.mask = HDI_FORMAT;
926 for (int i=0; i<pHeader->GetItemCount(); ++i)
928 pHeader->GetItem(i, &HeaderItem);
929 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
930 pHeader->SetItem(i, &HeaderItem);
932 pHeader->GetItem(m_nSortedColumn, &HeaderItem);
933 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);
934 pHeader->SetItem(m_nSortedColumn, &HeaderItem);
936 m_cFileList.SetRedraw(TRUE);
938 *pResult = 0;
941 void CFileDiffDlg::Sort()
943 if(m_arFileList.GetCount() < 2)
945 return;
948 std::sort(m_arFileList.m_paths.begin(), m_arFileList.m_paths.end(), &CFileDiffDlg::SortCompare);
951 bool CFileDiffDlg::SortCompare(const CTGitPath& Data1, const CTGitPath& Data2)
953 int result = 0;
954 int d1, d2;
955 switch (m_nSortedColumn)
957 case 0: //path column
958 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
959 break;
960 case 1: //extension column
961 result = Data1.GetFileExtension().Compare(Data2.GetFileExtension());
962 break;
963 case 2: //action column
964 result = Data1.m_Action - Data2.m_Action;
965 break;
966 case 3:
967 d1 = CSorter::A2L(Data1.m_StatAdd);
968 d2 = CSorter::A2L(Data2.m_StatAdd);
969 result = d1 - d2;
970 break;
971 case 4:
972 d1 = CSorter::A2L(Data1.m_StatDel);;
973 d2 = CSorter::A2L(Data2.m_StatDel);
974 result = d1 - d2;
975 break;
976 default:
977 break;
979 // sort by path name as second priority
980 if (m_nSortedColumn != 0 && result == 0)
981 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
983 if (!m_bAscending)
984 result = -result;
985 return result < 0;
989 void CFileDiffDlg::OnBnClickedRev1btn()
991 ClickRevButton(&this->m_cRev1Btn,&this->m_rev1, &this->m_ctrRev1Edit);
994 void CFileDiffDlg::ClickRevButton(CMenuButton *button, GitRev *rev, CACEdit *edit)
996 INT_PTR entry=button->GetCurrentEntry();
997 if(entry == 0) /* Browse Refence*/
1000 CString str = CBrowseRefsDlg::PickRef();
1001 if(str.IsEmpty())
1002 return;
1004 if(FillRevFromString(rev,str))
1005 return;
1007 edit->SetWindowText(str);
1011 if(entry == 1) /*Log*/
1013 CLogDlg dlg;
1014 dlg.SetSelect(true);
1015 if(dlg.DoModal() == IDOK)
1017 if( dlg.GetSelectedHash().IsEmpty() )
1018 return;
1020 if(FillRevFromString(rev,dlg.GetSelectedHash()))
1021 return;
1023 edit->SetWindowText(dlg.GetSelectedHash());
1026 else
1027 return;
1030 if(entry == 2) /*RefLog*/
1032 CRefLogDlg dlg;
1033 if(dlg.DoModal() == IDOK)
1035 if(FillRevFromString(rev,dlg.m_SelectedHash))
1036 return;
1038 edit->SetWindowText(dlg.m_SelectedHash);
1041 else
1042 return;
1045 SetURLLabels();
1047 InterlockedExchange(&m_bThreadRunning, TRUE);
1048 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1050 InterlockedExchange(&m_bThreadRunning, FALSE);
1051 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1053 KillTimer(IDT_INPUT);
1056 void CFileDiffDlg::OnBnClickedRev2btn()
1058 ClickRevButton(&this->m_cRev2Btn,&this->m_rev2, &this->m_ctrRev2Edit);
1061 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)
1063 if (m_bThreadRunning)
1065 SetTimer(IDT_FILTER, 1000, NULL);
1066 return 0L;
1069 KillTimer(IDT_FILTER);
1071 m_cFileList.SetRedraw(FALSE);
1072 m_arFilteredList.clear();
1073 m_cFileList.DeleteAllItems();
1075 Filter(_T(""));
1077 m_cFileList.SetRedraw(TRUE);
1078 return 0L;
1081 void CFileDiffDlg::OnEnChangeFilter()
1083 SetTimer(IDT_FILTER, 1000, NULL);
1086 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)
1088 if (m_bThreadRunning)
1089 return;
1091 if( nIDEvent == IDT_FILTER)
1093 CString sFilterText;
1094 KillTimer(IDT_FILTER);
1095 m_cFilter.GetWindowText(sFilterText);
1097 m_cFileList.SetRedraw(FALSE);
1098 m_cFileList.DeleteAllItems();
1100 Filter(sFilterText);
1102 m_cFileList.SetRedraw(TRUE);
1104 __super::OnTimer(nIDEvent);
1107 if( nIDEvent == IDT_INPUT)
1109 KillTimer(IDT_INPUT);
1110 TRACE(_T("Input Timer\r\n"));
1112 GitRev gitrev;
1113 CString str;
1114 int mask = 0;
1115 this->m_ctrRev1Edit.GetWindowText(str);
1118 if (!gitrev.GetCommit(str))
1120 m_rev1 = gitrev;
1121 mask |= 0x1;
1124 catch (const char *msg)
1126 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1129 this->m_ctrRev2Edit.GetWindowText(str);
1133 if (!gitrev.GetCommit(str))
1135 m_rev2 = gitrev;
1136 mask |= 0x2;
1139 catch (const char *msg)
1141 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1144 this->SetURLLabels(mask);
1146 if(mask == 0x3)
1149 InterlockedExchange(&m_bThreadRunning, TRUE);
1150 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1152 InterlockedExchange(&m_bThreadRunning, FALSE);
1153 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1159 void CFileDiffDlg::Filter(CString sFilterText)
1161 sFilterText.MakeLower();
1163 m_arFilteredList.clear();
1165 for (int i=0;i<m_arFileList.GetCount();i++)
1167 CString sPath = m_arFileList[i].GetGitPathString();
1168 sPath.MakeLower();
1169 if (sPath.Find(sFilterText) >= 0)
1171 m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));
1174 for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)
1176 AddEntry(*it);
1180 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull)
1182 // copy all selected paths to the clipboard
1183 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1184 int index;
1185 CString sTextForClipboard;
1186 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1188 sTextForClipboard += m_cFileList.GetItemText(index, 0);
1189 sTextForClipboard += _T("\t");
1191 if(!isFull)
1193 sTextForClipboard += _T("\r\n");
1196 else
1198 sTextForClipboard += m_cFileList.GetItemText(index, 1);
1199 sTextForClipboard += _T("\t");
1200 sTextForClipboard += m_cFileList.GetItemText(index, 2);
1201 sTextForClipboard += _T("\t");
1202 sTextForClipboard += m_cFileList.GetItemText(index, 3);
1203 sTextForClipboard += _T("\t");
1204 sTextForClipboard += m_cFileList.GetItemText(index, 4);
1205 sTextForClipboard += _T("\r\n");
1208 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);
1212 LRESULT CFileDiffDlg::OnRefLoad(WPARAM /*wParam*/, LPARAM /*lParam*/)
1214 for(int i=0;i<m_Reflist.size();i++)
1216 CString str=m_Reflist[i];
1218 if(str.Find(_T("remotes/")) == 0)
1219 str=str.Mid(8);
1221 m_ctrRev1Edit.AddSearchString(str);
1222 m_ctrRev2Edit.AddSearchString(str);
1224 return 0;
1227 BOOL CFileDiffDlg::DestroyWindow()
1229 return CResizableStandAloneDialog::DestroyWindow();
1232 LRESULT CFileDiffDlg::OnEnUpdate(WPARAM /*wParam*/, LPARAM lParam)
1234 if(lParam == IDC_REV1EDIT)
1236 OnTextUpdate(&this->m_ctrRev1Edit);
1237 ClearURLabels(1);
1239 if(lParam == IDC_REV2EDIT)
1241 OnTextUpdate(&this->m_ctrRev2Edit);
1242 ClearURLabels(1<<1);
1244 return 0;
1247 void CFileDiffDlg::OnTextUpdate(CACEdit * /*pEdit*/)
1249 SetTimer(IDT_INPUT, 1000, NULL);
1250 this->m_cFileList.ShowText(_T("Wait For input validate version"));
1253 int CFileDiffDlg::RevertSelectedItemToVersion(CString rev)
1255 if (rev.IsEmpty() || rev == GIT_REV_ZERO)
1256 return 0;
1258 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1259 int index;
1260 int count = 0;
1261 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1263 CString cmd, out;
1264 CTGitPath *fentry = (CTGitPath *)m_arFilteredList[index];
1265 cmd.Format(_T("git.exe checkout %s -- \"%s\""), rev, fentry->GetGitPathString());
1266 if (g_Git.Run(cmd, &out, CP_UTF8))
1268 if (CMessageBox::Show(NULL, out, _T("TortoiseGit"), 2, IDI_WARNING, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
1269 break;
1271 else
1272 count++;
1275 CString out;
1276 out.Format(IDS_STATUSLIST_FILESREVERTED, count, rev);
1277 CMessageBox::Show(NULL, out, _T("TortoiseGit"), MB_OK);
1278 return 0;
1281 void CFileDiffDlg::OnBnClickedLog()
1283 CLogDlg dlg;
1284 dlg.SetRange(m_rev2.m_CommitHash.ToString() + _T("..") + m_rev1.m_CommitHash.ToString());
1285 dlg.DoModal();