Revision Graph: Add filter to walk from Only Local Branches
[TortoiseGit.git] / src / TortoiseProc / FileDiffDlg.cpp
blobe9e14358858ca246f9e74aacacc668b1b0efc8e7
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - 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
51 #define ID_LOGSUBMODULE 11
53 BOOL CFileDiffDlg::m_bAscending = TRUE;
54 int CFileDiffDlg::m_nSortedColumn = -1;
56 UINT CFileDiffDlg::WM_DISABLEBUTTONS = RegisterWindowMessage(_T("TORTOISEGIT_FILEDIFF_DISABLEBUTTONS"));
57 UINT CFileDiffDlg::WM_DIFFFINISHED = RegisterWindowMessage(_T("TORTOISEGIT_FILEDIFF_DIFFFINISHED"));
59 IMPLEMENT_DYNAMIC(CFileDiffDlg, CResizableStandAloneDialog)
60 CFileDiffDlg::CFileDiffDlg(CWnd* pParent /*=NULL*/)
61 : CResizableStandAloneDialog(CFileDiffDlg::IDD, pParent)
62 , m_bBlame(false)
63 , m_pProgDlg(NULL)
64 , m_bCancelled(false)
65 , m_nIconFolder(0)
66 , m_bThreadRunning(FALSE)
67 , m_bIgnoreSpaceAtEol(false)
68 , m_bIgnoreSpaceChange(false)
69 , m_bIgnoreAllSpace(false)
70 , m_bIgnoreBlankLines(false)
71 , m_bIsBare(false)
73 m_bLoadingRef=FALSE;
76 CFileDiffDlg::~CFileDiffDlg()
80 void CFileDiffDlg::DoDataExchange(CDataExchange* pDX)
82 CResizableStandAloneDialog::DoDataExchange(pDX);
83 DDX_Control(pDX, IDC_FILELIST, m_cFileList);
84 DDX_Control(pDX, IDC_SWITCHLEFTRIGHT, m_SwitchButton);
85 DDX_Control(pDX, IDC_REV1BTN, m_cRev1Btn);
86 DDX_Control(pDX, IDC_REV2BTN, m_cRev2Btn);
87 DDX_Control(pDX, IDC_FILTER, m_cFilter);
88 DDX_Control(pDX, IDC_REV1EDIT, m_ctrRev1Edit);
89 DDX_Control(pDX, IDC_REV2EDIT, m_ctrRev2Edit);
93 BEGIN_MESSAGE_MAP(CFileDiffDlg, CResizableStandAloneDialog)
94 ON_NOTIFY(NM_DBLCLK, IDC_FILELIST, OnNMDblclkFilelist)
95 ON_NOTIFY(LVN_GETINFOTIP, IDC_FILELIST, OnLvnGetInfoTipFilelist)
96 ON_NOTIFY(NM_CUSTOMDRAW, IDC_FILELIST, OnNMCustomdrawFilelist)
97 ON_WM_CONTEXTMENU()
98 ON_WM_SETCURSOR()
99 ON_EN_SETFOCUS(IDC_SECONDURL, &CFileDiffDlg::OnEnSetfocusSecondurl)
100 ON_EN_SETFOCUS(IDC_FIRSTURL, &CFileDiffDlg::OnEnSetfocusFirsturl)
101 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT, &CFileDiffDlg::OnBnClickedSwitchleftright)
102 ON_NOTIFY(HDN_ITEMCLICK, 0, &CFileDiffDlg::OnHdnItemclickFilelist)
103 ON_BN_CLICKED(IDC_REV1BTN, &CFileDiffDlg::OnBnClickedRev1btn)
104 ON_BN_CLICKED(IDC_REV2BTN, &CFileDiffDlg::OnBnClickedRev2btn)
105 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)
106 ON_EN_CHANGE(IDC_FILTER, &CFileDiffDlg::OnEnChangeFilter)
107 ON_WM_TIMER()
108 ON_MESSAGE(ENAC_UPDATE, &CFileDiffDlg::OnEnUpdate)
109 ON_MESSAGE(MSG_REF_LOADED, OnRefLoad)
110 ON_REGISTERED_MESSAGE(WM_DISABLEBUTTONS, OnDisableButtons)
111 ON_REGISTERED_MESSAGE(WM_DIFFFINISHED, OnDiffFinished)
112 ON_BN_CLICKED(IDC_DIFFOPTION, OnBnClickedDiffoption)
113 ON_BN_CLICKED(IDC_LOG, &CFileDiffDlg::OnBnClickedLog)
114 END_MESSAGE_MAP()
117 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1, const GitRev &rev2)
119 if(path!=NULL)
121 m_path1 = *path;
122 m_path2 = *path;
123 m_sFilter = path->GetGitPathString();
125 m_rev1 = rev1;
126 m_rev2 = rev2;
129 void CFileDiffDlg::SetDiff(const CTGitPath * path, const CString &hash1, const CString &hash2)
131 if(path!=NULL)
133 m_path1 = *path;
134 m_path2 = *path;
135 m_sFilter = path->GetGitPathString();
138 BYTE_VECTOR logout;
140 if(hash1 == GIT_REV_ZERO)
142 m_rev1.m_CommitHash.Empty();
143 m_rev1.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
145 else
149 m_rev1.GetCommit(hash1);
151 catch (const char *msg)
153 MessageBox(_T("Could not get commit ") + hash1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
157 logout.clear();
159 if(hash2 == GIT_REV_ZERO)
161 m_rev2.m_CommitHash.Empty();
162 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
164 else
168 m_rev2.GetCommit(hash2);
170 catch (const char *msg)
172 MessageBox(_T("Could not get commit ") + hash2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
177 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1)
179 if(path!=NULL)
181 m_path1 = *path;
182 m_path2 = *path;
183 m_sFilter = path->GetGitPathString();
185 m_rev1 = rev1;
186 m_rev2.m_CommitHash.Empty();
187 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_PROC_PREVIOUSVERSION));
189 //this->GetDlgItem()->EnableWindow(FALSE);
192 BOOL CFileDiffDlg::OnInitDialog()
194 CResizableStandAloneDialog::OnInitDialog();
195 CString temp;
197 CString sWindowTitle;
198 GetWindowText(sWindowTitle);
199 CString pathText = g_Git.m_CurrentDir;
200 if (!m_path1.IsEmpty())
201 pathText = g_Git.CombinePath(m_path1);
202 CAppUtils::SetWindowTitle(m_hWnd, pathText, sWindowTitle);
204 this->m_ctrRev1Edit.Init();
205 this->m_ctrRev2Edit.Init();
207 m_tooltips.Create(this);
208 m_tooltips.AddTool(IDC_SWITCHLEFTRIGHT, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT);
210 m_cFileList.SetRedraw(false);
211 m_cFileList.DeleteAllItems();
212 DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
213 m_cFileList.SetExtendedStyle(exStyle);
215 m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();
216 m_cFileList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);
218 m_SwitchButton.SetImage((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
219 m_SwitchButton.Invalidate();
221 m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);
222 m_cFilter.SetInfoIcon(IDI_FILTEREDIT);
223 temp.LoadString(IDS_FILEDIFF_FILTERCUE);
224 temp = _T(" ")+temp;
225 m_cFilter.SetCueBanner(temp);
226 if (!m_sFilter.IsEmpty())
227 m_cFilter.SetWindowText(m_sFilter);
229 int c = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
230 while (c>=0)
231 m_cFileList.DeleteColumn(c--);
233 temp.LoadString(IDS_FILEDIFF_FILE);
234 m_cFileList.InsertColumn(0, temp);
235 temp.LoadString(IDS_FILEDIFF_EXT);
236 m_cFileList.InsertColumn(1, temp);
237 temp.LoadString(IDS_FILEDIFF_ACTION);
238 m_cFileList.InsertColumn(2, temp);
240 temp.LoadString(IDS_FILEDIFF_STATADD);
241 m_cFileList.InsertColumn(3, temp);
242 temp.LoadString(IDS_FILEDIFF_STATDEL);
243 m_cFileList.InsertColumn(4, temp);
245 int mincol = 0;
246 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
247 int col;
248 for (col = mincol; col <= maxcol; col++)
250 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);
253 m_cFileList.SetRedraw(true);
255 AddAnchor(IDC_DIFFSTATIC1, TOP_LEFT, TOP_RIGHT);
256 AddAnchor(IDC_SWITCHLEFTRIGHT, TOP_RIGHT);
257 AddAnchor(IDC_FIRSTURL, TOP_LEFT, TOP_RIGHT);
258 AddAnchor(IDC_REV1BTN, TOP_RIGHT);
259 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
260 AddAnchor(IDC_SECONDURL, TOP_LEFT, TOP_RIGHT);
261 AddAnchor(IDC_REV2BTN, TOP_RIGHT);
262 AddAnchor(IDC_FILTER, TOP_LEFT, TOP_RIGHT);
263 AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);
264 AddAnchor(IDC_REV1GROUP,TOP_LEFT,TOP_RIGHT);
265 AddAnchor(IDC_REV2GROUP,TOP_LEFT,TOP_RIGHT);
266 AddAnchor(IDC_REV1EDIT,TOP_LEFT);
267 AddAnchor(IDC_REV2EDIT,TOP_LEFT);
268 AddAnchor(IDC_DIFFOPTION, TOP_RIGHT);
269 AddAnchor(IDC_LOG, TOP_RIGHT);
271 EnableSaveRestore(_T("FileDiffDlg"));
273 m_bIsBare = GitAdminDir().IsBareRepo(g_Git.m_CurrentDir);
275 if(this->m_strRev1.IsEmpty())
276 this->m_ctrRev1Edit.SetWindowText(this->m_rev1.m_CommitHash.ToString());
277 else
279 bool rev1fail = false;
282 rev1fail = !!m_rev1.GetCommit(m_strRev1);
284 catch (const char *msg)
286 rev1fail = true;
287 MessageBox(_T("Could not get commit ") + m_strRev1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
289 if (rev1fail)
291 CString msg;
292 msg.Format(IDS_PROC_REFINVALID, m_strRev1);
293 this->m_FileListText += msg;
296 this->m_ctrRev1Edit.SetWindowText(m_strRev1);
299 if(this->m_strRev2.IsEmpty())
300 this->m_ctrRev2Edit.SetWindowText(this->m_rev2.m_CommitHash.ToString());
301 else
303 bool rev2fail = false;
306 rev2fail = !!m_rev2.GetCommit(m_strRev2);
308 catch (const char *msg)
310 rev2fail = true;
311 MessageBox(_T("Could not get commit ") + m_strRev2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
313 if (rev2fail)
315 CString msg;
316 msg.Format(IDS_PROC_REFINVALID, m_strRev2);
317 this->m_FileListText += msg;
320 this->m_ctrRev2Edit.SetWindowText(m_strRev2);
323 SetURLLabels();
325 InterlockedExchange(&m_bThreadRunning, TRUE);
326 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
328 InterlockedExchange(&m_bThreadRunning, FALSE);
329 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
332 InterlockedExchange(&m_bLoadingRef, TRUE);
333 if (AfxBeginThread(LoadRefThreadEntry, this)==NULL)
335 InterlockedExchange(&m_bLoadingRef, FALSE);
336 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
339 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
340 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
341 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
343 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
344 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
345 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
347 // Start with focus on file list
348 GetDlgItem(IDC_FILELIST)->SetFocus();
350 if(m_rev2.m_CommitHash.IsEmpty())
351 m_SwitchButton.EnableWindow(FALSE);
353 KillTimer(IDT_INPUT);
354 return FALSE;
357 UINT CFileDiffDlg::DiffThreadEntry(LPVOID pVoid)
359 return ((CFileDiffDlg*)pVoid)->DiffThread();
362 UINT CFileDiffDlg::DiffThread()
364 SendMessage(WM_DISABLEBUTTONS);
366 if( m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty())
367 g_Git.RefreshGitIndex();
369 g_Git.GetCommitDiffList(m_rev1.m_CommitHash.ToString(), m_rev2.m_CommitHash.ToString(), m_arFileList, m_bIgnoreSpaceAtEol, m_bIgnoreSpaceChange, m_bIgnoreAllSpace, m_bIgnoreBlankLines);
370 Sort();
372 SendMessage(WM_DIFFFINISHED);
374 InterlockedExchange(&m_bThreadRunning, FALSE);
375 return 0;
378 LRESULT CFileDiffDlg::OnDisableButtons(WPARAM, LPARAM)
380 RefreshCursor();
381 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT)));
382 m_cFileList.DeleteAllItems();
383 m_arFileList.Clear();
384 EnableInputControl(false);
385 return 0;
388 LRESULT CFileDiffDlg::OnDiffFinished(WPARAM, LPARAM)
390 CString sFilterText;
391 m_cFilter.GetWindowText(sFilterText);
392 m_cFileList.SetRedraw(false);
393 Filter(sFilterText);
394 if (!m_arFileList.IsEmpty())
396 // Highlight first entry in file list
397 m_cFileList.SetSelectionMark(0);
398 m_cFileList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
401 int mincol = 0;
402 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
403 int col;
404 for (col = mincol; col <= maxcol; ++col)
406 m_cFileList.SetColumnWidth(col, LVSCW_AUTOSIZE_USEHEADER);
409 m_cFileList.ClearText();
410 if (m_arFileList.IsEmpty())
411 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_COMPAREREV_NODIFF)));
412 m_cFileList.SetRedraw(true);
414 InvalidateRect(NULL);
415 RefreshCursor();
416 EnableInputControl(true);
417 return 0;
420 int CFileDiffDlg::AddEntry(const CTGitPath * fd)
422 int ret = -1;
423 if (fd)
425 int index = m_cFileList.GetItemCount();
427 int icon_idx = 0;
428 if (fd->IsDirectory())
429 icon_idx = m_nIconFolder;
430 else
431 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(fd->GetGitPathString());
433 ret = m_cFileList.InsertItem(index, fd->GetGitPathString(), icon_idx);
434 m_cFileList.SetItemText(index, 1, ((CTGitPath*)fd)->GetFileExtension());
435 m_cFileList.SetItemText(index, 2, ((CTGitPath*)fd)->GetActionName());
436 m_cFileList.SetItemText(index, 3, ((CTGitPath*)fd)->m_StatAdd);
437 m_cFileList.SetItemText(index, 4, ((CTGitPath*)fd)->m_StatDel);
439 return ret;
442 void CFileDiffDlg::EnableInputControl(bool b)
444 this->m_ctrRev1Edit.EnableWindow(b);
445 this->m_ctrRev2Edit.EnableWindow(b);
446 this->m_cRev1Btn.EnableWindow(b);
447 this->m_cRev2Btn.EnableWindow(b);
448 m_cFilter.EnableWindow(b);
449 m_SwitchButton.EnableWindow(b);
450 GetDlgItem(IDC_LOG)->EnableWindow(b && !(m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty()));
453 void CFileDiffDlg::DoDiff(int selIndex, bool blame)
455 CGitDiff diff;
456 CTGitPath* fd2 = m_arFilteredList[selIndex];
457 CTGitPath* fd1 = fd2;
458 if (m_rev1.m_CommitHash.IsEmpty() && g_Git.IsInitRepos())
460 CGitDiff::DiffNull(fd2, GIT_REV_ZERO);
461 return;
463 if (fd2->m_Action & CTGitPath::LOGACTIONS_ADDED)
465 CGitDiff::DiffNull(fd2, m_rev1.m_CommitHash.ToString(), true);
466 return;
468 if (fd2->m_Action & CTGitPath::LOGACTIONS_DELETED)
470 CGitDiff::DiffNull(fd2, m_rev2.m_CommitHash.ToString(), false);
471 return;
473 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
474 fd1 = new CTGitPath(fd2->GetGitOldPathString());
475 diff.Diff(fd2, fd1, this->m_rev1.m_CommitHash.ToString(), this->m_rev2.m_CommitHash.ToString(), blame, FALSE);
476 if (fd1 != fd2)
477 delete fd1;
481 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)
483 *pResult = 0;
484 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
485 int selIndex = pNMLV->iItem;
486 if (selIndex < 0)
487 return;
488 if (selIndex >= (int)m_arFilteredList.size())
489 return;
491 DoDiff(selIndex, m_bBlame);
494 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR *pNMHDR, LRESULT *pResult)
497 LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);
498 if (pGetInfoTip->iItem >= (int)m_arFilteredList.size())
499 return;
501 CString path = m_path1.GetGitPathString() + _T("/") + m_arFilteredList[pGetInfoTip->iItem]->GetGitPathString();
502 if (pGetInfoTip->cchTextMax > path.GetLength())
503 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path, pGetInfoTip->cchTextMax);
505 *pResult = 0;
508 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR *pNMHDR, LRESULT *pResult)
510 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
511 // Take the default processing unless we set this to something else below.
512 *pResult = CDRF_DODEFAULT;
514 // First thing - check the draw stage. If it's the control's prepaint
515 // stage, then tell Windows we want messages for every item.
517 if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
519 *pResult = CDRF_NOTIFYITEMDRAW;
521 else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
523 // This is the prepaint stage for an item. Here's where we set the
524 // item's text color. Our return value will tell Windows to draw the
525 // item itself, but it will use the new color we set here.
527 // Tell Windows to paint the control itself.
528 *pResult = CDRF_DODEFAULT;
530 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
532 if (m_arFilteredList.size() > pLVCD->nmcd.dwItemSpec)
534 CTGitPath * fd = m_arFilteredList[pLVCD->nmcd.dwItemSpec];
535 switch (fd->m_Action)
537 case CTGitPath::LOGACTIONS_ADDED:
538 crText = m_colors.GetColor(CColors::Added);
539 break;
540 case CTGitPath::LOGACTIONS_DELETED:
541 crText = m_colors.GetColor(CColors::Deleted);
542 break;
543 case CTGitPath::LOGACTIONS_MODIFIED:
544 crText = m_colors.GetColor(CColors::Modified);
545 break;
546 default:
547 crText = m_colors.GetColor(CColors::PropertyChanged);
548 break;
551 // Store the color back in the NMLVCUSTOMDRAW struct.
552 pLVCD->clrText = crText;
556 UINT CFileDiffDlg::LoadRefThread()
558 g_Git.GetBranchList(m_Reflist,NULL,CGit::BRANCH_ALL_F);
559 g_Git.GetTagList(m_Reflist);
561 this->PostMessage(MSG_REF_LOADED);
562 InterlockedExchange(&m_bLoadingRef, FALSE);
563 return 0;
566 void CFileDiffDlg::OnContextMenu(CWnd* pWnd, CPoint point)
568 if ((pWnd==0)||(pWnd != &m_cFileList))
569 return;
570 if (m_cFileList.GetSelectedCount() == 0)
571 return;
572 // if the context menu is invoked through the keyboard, we have to use
573 // a calculated position on where to anchor the menu on
574 if ((point.x == -1) && (point.y == -1))
576 CRect rect;
577 m_cFileList.GetItemRect(m_cFileList.GetSelectionMark(), &rect, LVIR_LABEL);
578 m_cFileList.ClientToScreen(&rect);
579 point = rect.CenterPoint();
581 CIconMenu popup;
582 if (popup.CreatePopupMenu())
584 int firstEntry = -1;
585 POSITION firstPos = m_cFileList.GetFirstSelectedItemPosition();
586 if (firstPos)
587 firstEntry = m_cFileList.GetNextSelectedItem(firstPos);
589 CString menuText;
590 popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);
591 popup.AppendMenuIcon(ID_GNUDIFFCOMPARE, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);
592 popup.AppendMenu(MF_SEPARATOR, NULL);
593 if (!m_bIsBare)
595 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev1.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
596 popup.AppendMenuIcon(ID_REVERT1, menuText, IDI_REVERT);
597 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev2.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
598 popup.AppendMenuIcon(ID_REVERT2, menuText, IDI_REVERT);
599 popup.AppendMenu(MF_SEPARATOR, NULL);
601 popup.AppendMenuIcon(ID_LOG, IDS_FILEDIFF_LOG, IDI_LOG);
602 if (firstEntry >= 0 && !m_arFilteredList[firstEntry]->IsDirectory())
604 if (!m_bIsBare)
606 popup.AppendMenuIcon(ID_BLAME, IDS_FILEDIFF_POPBLAME, IDI_BLAME);
607 popup.AppendMenu(MF_SEPARATOR, NULL);
609 popup.AppendMenuIcon(ID_EXPORT, IDS_FILEDIFF_POPEXPORT, IDI_EXPORT);
611 else if (firstEntry >= 0)
612 popup.AppendMenuIcon(ID_LOGSUBMODULE, IDS_MENULOGSUBMODULE, IDI_LOG);
613 popup.AppendMenu(MF_SEPARATOR, NULL);
614 popup.AppendMenuIcon(ID_SAVEAS, IDS_FILEDIFF_POPSAVELIST, IDI_SAVEAS);
615 popup.AppendMenuIcon(ID_CLIPBOARD_PATH, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);
616 popup.AppendMenuIcon(ID_CLIPBOARD_ALL, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);
618 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
619 m_bCancelled = false;
620 switch (cmd)
622 case ID_COMPARE:
624 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
625 while (pos)
627 int index = m_cFileList.GetNextSelectedItem(pos);
628 DoDiff(index, false);
631 break;
632 case ID_GNUDIFFCOMPARE:
634 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
635 while (pos)
637 CTGitPath *fd2 = m_arFilteredList[m_cFileList.GetNextSelectedItem(pos)];
638 CTGitPath *fd1 = fd2;
639 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
640 fd1 = new CTGitPath(fd2->GetGitOldPathString());
641 CAppUtils::StartShowUnifiedDiff(m_hWnd, *fd2, m_rev2.m_CommitHash.ToString(), *fd1, m_rev1.m_CommitHash.ToString());
642 if (fd1 != fd2)
643 delete fd1;
646 break;
647 case ID_REVERT1:
648 RevertSelectedItemToVersion(m_rev1.m_CommitHash.ToString());
649 break;
650 case ID_REVERT2:
651 RevertSelectedItemToVersion(m_rev2.m_CommitHash.ToString());
652 break;
653 case ID_BLAME:
655 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
656 while (pos)
658 int index = m_cFileList.GetNextSelectedItem(pos);
659 CAppUtils::LaunchTortoiseBlame(m_arFilteredList[index]->GetWinPathString(), m_rev1.m_CommitHash.ToString());
662 break;
663 case ID_LOG:
664 case ID_LOGSUBMODULE:
666 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
667 while (pos)
669 int index = m_cFileList.GetNextSelectedItem(pos);
670 CString cmd = _T("/command:log");
671 if (cmd == ID_LOGSUBMODULE)
672 cmd += _T(" /submodule");
673 cmd += _T(" /path:\"")+m_arFilteredList[index]->GetWinPathString()+_T("\" ");
674 cmd += _T(" /endrev:")+m_rev1.m_CommitHash.ToString();
675 CAppUtils::RunTortoiseGitProc(cmd);
678 break;
679 case ID_SAVEAS:
681 if (m_cFileList.GetSelectedCount() > 0)
683 CString temp;
684 CTGitPath savePath;
685 CString pathSave;
686 if (!CAppUtils::FileOpenSave(pathSave, NULL, IDS_REPOBROWSE_SAVEAS, IDS_TEXTFILEFILTER, false, m_hWnd, _T(".txt")))
688 break;
690 savePath = CTGitPath(pathSave);
692 // now open the selected file for writing
695 CStdioFile file(savePath.GetWinPathString(), CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);
696 if (m_path1.IsEmpty() && m_path2.IsEmpty())
697 temp.Format(IDS_FILEDIFF_CHANGEDLISTINTROROOT, m_rev1.m_CommitHash.ToString(), m_rev2.m_CommitHash.ToString());
698 else
699 temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, m_path1.GetGitPathString(), m_rev1.m_CommitHash.ToString(), m_path2.GetGitPathString(), m_rev2.m_CommitHash.ToString());
700 file.WriteString(temp + _T("\r\n"));
701 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
702 while (pos)
704 int index = m_cFileList.GetNextSelectedItem(pos);
705 CTGitPath* fd = m_arFilteredList[index];
706 file.WriteString(fd->GetGitPathString());
707 file.WriteString(_T("\r\n"));
709 file.Close();
711 catch (CFileException* pE)
713 pE->ReportError();
717 break;
718 case ID_CLIPBOARD_PATH:
720 CopySelectionToClipboard();
722 break;
724 case ID_CLIPBOARD_ALL:
726 CopySelectionToClipboard(TRUE);
728 break;
729 case ID_EXPORT:
731 // export all changed files to a folder
732 CBrowseFolder browseFolder;
733 browseFolder.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
734 if (browseFolder.Show(GetSafeHwnd(), m_strExportDir) == CBrowseFolder::OK)
736 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
737 while (pos)
739 int index = m_cFileList.GetNextSelectedItem(pos);
740 CTGitPath* fd = m_arFilteredList[index];
741 // we cannot export directories or folders
742 if (fd->m_Action == CTGitPath::LOGACTIONS_DELETED || fd->IsDirectory())
743 continue;
744 CAppUtils::CreateMultipleDirectory(m_strExportDir + _T("\\") + fd->GetContainingDirectory().GetWinPathString());
745 CString filename = m_strExportDir + _T("\\") + fd->GetWinPathString();
746 if(m_rev1.m_CommitHash.ToString() == GIT_REV_ZERO)
748 if(!CopyFile(g_Git.CombinePath(fd), filename, false))
750 MessageBox(CFormatMessageWrapper(), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
751 return;
754 else
756 if(g_Git.GetOneFile(m_rev1.m_CommitHash, *fd, filename))
758 CString out;
759 out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, fd->GetGitPathString(), m_rev1.m_CommitHash.ToString(), filename);
760 if (CMessageBox::Show(nullptr, g_Git.GetGitLastErr(out, CGit::GIT_CMD_GETONEFILE), _T("TortoiseGit"), 2, IDI_WARNING, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
761 return;
768 break;
774 BOOL CFileDiffDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
776 if (pWnd != &m_cFileList)
777 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
778 if (m_bThreadRunning == 0)
780 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
781 SetCursor(hCur);
782 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
784 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
785 SetCursor(hCur);
786 return TRUE;
789 void CFileDiffDlg::OnEnSetfocusFirsturl()
791 GetDlgItem(IDC_FIRSTURL)->HideCaret();
794 void CFileDiffDlg::OnEnSetfocusSecondurl()
796 GetDlgItem(IDC_SECONDURL)->HideCaret();
800 void CFileDiffDlg::OnBnClickedSwitchleftright()
803 if (m_bThreadRunning)
804 return;
806 #if 0
807 CString sFilterString;
808 m_cFilter.GetWindowText(sFilterString);
810 m_cFileList.SetRedraw(false);
811 m_cFileList.DeleteAllItems();
812 for (int i=0; i<(int)m_arFileList.GetCount(); ++i)
814 CTGitPath fd = m_arFileList[i];
815 if (fd.m_Action == CTGitPath::LOGACTIONS_ADDED)
816 fd.m_Action = CTGitPath::LOGACTIONS_DELETED;
817 else if (fd.m_Action == CTGitPath::LOGACTIONS_DELETED)
818 fd.m_Action = CTGitPath::LOGACTIONS_ADDED;
819 std::swap(fd.m_StatAdd, fd.m_StatDel);
820 (CTGitPath&)m_arFileList[i] = fd;
822 Filter(sFilterString);
823 #endif
825 m_cFileList.SetRedraw(true);
826 CTGitPath path = m_path1;
827 m_path1 = m_path2;
828 m_path2 = path;
829 GitRev rev = m_rev1;
830 m_rev1 = m_rev2;
831 m_rev2 = rev;
833 CString str1,str2;
834 this->m_ctrRev1Edit.GetWindowText(str1);
835 this->m_ctrRev2Edit.GetWindowText(str2);
837 this->m_ctrRev1Edit.SetWindowText(str2);
838 this->m_ctrRev2Edit.SetWindowText(str1);
840 SetURLLabels();
841 //KillTimer(IDT_INPUT);
844 void CFileDiffDlg::SetURLLabels(int mask)
847 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
848 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
850 if(mask &0x1)
852 SetDlgItemText(IDC_FIRSTURL, m_rev1.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev1.GetSubject());
853 if (!m_rev1.m_CommitHash.IsEmpty())
854 m_tooltips.AddTool(IDC_FIRSTURL,
855 CLoglistUtils::FormatDateAndTime(m_rev1.GetAuthorDate(), DATE_SHORTDATE) + _T(" ") + m_rev1.GetAuthorName());
859 if(mask &0x2)
861 SetDlgItemText(IDC_SECONDURL,m_rev2.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev2.GetSubject());
862 if (!m_rev2.m_CommitHash.IsEmpty())
863 m_tooltips.AddTool(IDC_SECONDURL,
864 CLoglistUtils::FormatDateAndTime(m_rev2.GetAuthorDate(), DATE_SHORTDATE) + _T(" ") + m_rev2.GetAuthorName());
867 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASE)));
868 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1)));
870 if( (mask&0x3) == 0x3 && !m_rev1.m_CommitHash.IsEmpty() && !m_rev2.m_CommitHash.IsEmpty())
871 if(m_rev2.GetCommitterDate() > m_rev1.GetCommitterDate())
873 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASENEWER)));
875 else if (m_rev2.GetCommitterDate() < m_rev1.GetCommitterDate())
877 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1NEWER)));
881 void CFileDiffDlg::ClearURLabels(int mask)
883 if(mask&0x1)
885 SetDlgItemText(IDC_FIRSTURL, _T(""));
886 m_tooltips.AddTool(IDC_FIRSTURL, _T(""));
889 if(mask&0x2)
891 SetDlgItemText(IDC_SECONDURL, _T(""));
892 m_tooltips.AddTool(IDC_SECONDURL, _T(""));
895 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)
897 m_tooltips.RelayEvent(pMsg);
898 if (pMsg->message == WM_KEYDOWN)
900 switch (pMsg->wParam)
902 case 'A':
904 if (GetFocus() != GetDlgItem(IDC_FILELIST))
905 break;
906 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
908 // select all entries
909 for (int i=0; i<m_cFileList.GetItemCount(); ++i)
911 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
913 return TRUE;
916 break;
917 case 'C':
918 case VK_INSERT:
920 if (GetFocus() != GetDlgItem(IDC_FILELIST))
921 break;
922 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
924 CopySelectionToClipboard();
925 return TRUE;
928 break;
929 case '\r':
931 if (GetFocus() == GetDlgItem(IDC_FILELIST))
933 // Return pressed in file list. Show diff, as for double click
934 int selIndex = m_cFileList.GetSelectionMark();
935 if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))
936 DoDiff(selIndex, m_bBlame);
937 return TRUE;
940 break;
941 case VK_F5:
943 OnTimer(IDT_INPUT);
945 break;
948 return __super::PreTranslateMessage(pMsg);
951 void CFileDiffDlg::OnCancel()
953 if (m_bThreadRunning)
955 m_bCancelled = true;
956 return;
958 __super::OnCancel();
961 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)
963 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
964 if (m_bThreadRunning)
965 return;
967 if (m_nSortedColumn == phdr->iItem)
968 m_bAscending = !m_bAscending;
969 else
970 m_bAscending = TRUE;
971 m_nSortedColumn = phdr->iItem;
972 Sort();
974 CString temp;
975 m_cFileList.SetRedraw(FALSE);
976 m_cFileList.DeleteAllItems();
977 m_cFilter.GetWindowText(temp);
978 Filter(temp);
980 CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();
981 HDITEM HeaderItem = {0};
982 HeaderItem.mask = HDI_FORMAT;
983 for (int i=0; i<pHeader->GetItemCount(); ++i)
985 pHeader->GetItem(i, &HeaderItem);
986 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
987 pHeader->SetItem(i, &HeaderItem);
989 pHeader->GetItem(m_nSortedColumn, &HeaderItem);
990 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);
991 pHeader->SetItem(m_nSortedColumn, &HeaderItem);
993 m_cFileList.SetRedraw(TRUE);
995 *pResult = 0;
998 void CFileDiffDlg::Sort()
1000 if(m_arFileList.GetCount() < 2)
1002 return;
1005 std::sort(m_arFileList.m_paths.begin(), m_arFileList.m_paths.end(), &CFileDiffDlg::SortCompare);
1008 bool CFileDiffDlg::SortCompare(const CTGitPath& Data1, const CTGitPath& Data2)
1010 int result = 0;
1011 int d1, d2;
1012 switch (m_nSortedColumn)
1014 case 0: //path column
1015 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
1016 break;
1017 case 1: //extension column
1018 result = Data1.GetFileExtension().Compare(Data2.GetFileExtension());
1019 break;
1020 case 2: //action column
1021 result = Data1.m_Action - Data2.m_Action;
1022 break;
1023 case 3:
1024 d1 = CSorter::A2L(Data1.m_StatAdd);
1025 d2 = CSorter::A2L(Data2.m_StatAdd);
1026 result = d1 - d2;
1027 break;
1028 case 4:
1029 d1 = CSorter::A2L(Data1.m_StatDel);;
1030 d2 = CSorter::A2L(Data2.m_StatDel);
1031 result = d1 - d2;
1032 break;
1033 default:
1034 break;
1036 // sort by path name as second priority
1037 if (m_nSortedColumn != 0 && result == 0)
1038 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
1040 if (!m_bAscending)
1041 result = -result;
1042 return result < 0;
1046 void CFileDiffDlg::OnBnClickedRev1btn()
1048 ClickRevButton(&this->m_cRev1Btn,&this->m_rev1, &this->m_ctrRev1Edit);
1051 void CFileDiffDlg::ClickRevButton(CMenuButton *button, GitRev *rev, CACEdit *edit)
1053 INT_PTR entry=button->GetCurrentEntry();
1054 if(entry == 0) /* Browse Refence*/
1057 CString str = CBrowseRefsDlg::PickRef();
1058 if(str.IsEmpty())
1059 return;
1061 if(FillRevFromString(rev,str))
1062 return;
1064 edit->SetWindowText(str);
1068 if(entry == 1) /*Log*/
1070 CLogDlg dlg;
1071 dlg.SetSelect(true);
1072 if(dlg.DoModal() == IDOK)
1074 if( dlg.GetSelectedHash().IsEmpty() )
1075 return;
1077 if(FillRevFromString(rev,dlg.GetSelectedHash()))
1078 return;
1080 edit->SetWindowText(dlg.GetSelectedHash());
1083 else
1084 return;
1087 if(entry == 2) /*RefLog*/
1089 CRefLogDlg dlg;
1090 if(dlg.DoModal() == IDOK)
1092 if(FillRevFromString(rev,dlg.m_SelectedHash))
1093 return;
1095 edit->SetWindowText(dlg.m_SelectedHash);
1098 else
1099 return;
1102 SetURLLabels();
1104 InterlockedExchange(&m_bThreadRunning, TRUE);
1105 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1107 InterlockedExchange(&m_bThreadRunning, FALSE);
1108 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1110 KillTimer(IDT_INPUT);
1113 void CFileDiffDlg::OnBnClickedRev2btn()
1115 ClickRevButton(&this->m_cRev2Btn,&this->m_rev2, &this->m_ctrRev2Edit);
1118 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)
1120 if (m_bThreadRunning)
1122 SetTimer(IDT_FILTER, 1000, NULL);
1123 return 0L;
1126 KillTimer(IDT_FILTER);
1128 m_cFileList.SetRedraw(FALSE);
1129 m_arFilteredList.clear();
1130 m_cFileList.DeleteAllItems();
1132 Filter(_T(""));
1134 m_cFileList.SetRedraw(TRUE);
1135 return 0L;
1138 void CFileDiffDlg::OnEnChangeFilter()
1140 SetTimer(IDT_FILTER, 1000, NULL);
1143 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)
1145 if (m_bThreadRunning)
1146 return;
1148 if( nIDEvent == IDT_FILTER)
1150 CString sFilterText;
1151 KillTimer(IDT_FILTER);
1152 m_cFilter.GetWindowText(sFilterText);
1154 m_cFileList.SetRedraw(FALSE);
1155 m_cFileList.DeleteAllItems();
1157 Filter(sFilterText);
1159 m_cFileList.SetRedraw(TRUE);
1161 __super::OnTimer(nIDEvent);
1164 if( nIDEvent == IDT_INPUT)
1166 KillTimer(IDT_INPUT);
1167 TRACE(_T("Input Timer\r\n"));
1169 GitRev gitrev;
1170 CString str;
1171 int mask = 0;
1172 this->m_ctrRev1Edit.GetWindowText(str);
1175 if (!gitrev.GetCommit(str))
1177 m_rev1 = gitrev;
1178 mask |= 0x1;
1181 catch (const char *msg)
1183 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1186 this->m_ctrRev2Edit.GetWindowText(str);
1190 if (!gitrev.GetCommit(str))
1192 m_rev2 = gitrev;
1193 mask |= 0x2;
1196 catch (const char *msg)
1198 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1201 this->SetURLLabels(mask);
1203 if(mask == 0x3)
1206 InterlockedExchange(&m_bThreadRunning, TRUE);
1207 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1209 InterlockedExchange(&m_bThreadRunning, FALSE);
1210 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1216 void CFileDiffDlg::Filter(CString sFilterText)
1218 sFilterText.MakeLower();
1220 m_arFilteredList.clear();
1222 for (int i=0;i<m_arFileList.GetCount();i++)
1224 CString sPath = m_arFileList[i].GetGitPathString();
1225 sPath.MakeLower();
1226 if (sPath.Find(sFilterText) >= 0)
1228 m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));
1231 for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)
1233 AddEntry(*it);
1237 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull)
1239 // copy all selected paths to the clipboard
1240 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1241 int index;
1242 CString sTextForClipboard;
1243 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1245 sTextForClipboard += m_cFileList.GetItemText(index, 0);
1246 sTextForClipboard += _T("\t");
1248 if(!isFull)
1250 sTextForClipboard += _T("\r\n");
1253 else
1255 sTextForClipboard += m_cFileList.GetItemText(index, 1);
1256 sTextForClipboard += _T("\t");
1257 sTextForClipboard += m_cFileList.GetItemText(index, 2);
1258 sTextForClipboard += _T("\t");
1259 sTextForClipboard += m_cFileList.GetItemText(index, 3);
1260 sTextForClipboard += _T("\t");
1261 sTextForClipboard += m_cFileList.GetItemText(index, 4);
1262 sTextForClipboard += _T("\r\n");
1265 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);
1269 LRESULT CFileDiffDlg::OnRefLoad(WPARAM /*wParam*/, LPARAM /*lParam*/)
1271 for (size_t i = 0; i < m_Reflist.size(); ++i)
1273 CString str=m_Reflist[i];
1275 if(str.Find(_T("remotes/")) == 0)
1276 str=str.Mid(8);
1278 m_ctrRev1Edit.AddSearchString(str);
1279 m_ctrRev2Edit.AddSearchString(str);
1281 return 0;
1284 BOOL CFileDiffDlg::DestroyWindow()
1286 return CResizableStandAloneDialog::DestroyWindow();
1289 LRESULT CFileDiffDlg::OnEnUpdate(WPARAM /*wParam*/, LPARAM lParam)
1291 if(lParam == IDC_REV1EDIT)
1293 OnTextUpdate(&this->m_ctrRev1Edit);
1294 ClearURLabels(1);
1296 if(lParam == IDC_REV2EDIT)
1298 OnTextUpdate(&this->m_ctrRev2Edit);
1299 ClearURLabels(1<<1);
1301 return 0;
1304 void CFileDiffDlg::OnTextUpdate(CACEdit * /*pEdit*/)
1306 SetTimer(IDT_INPUT, 1000, NULL);
1307 this->m_cFileList.ShowText(_T("Wait For input validate version"));
1310 int CFileDiffDlg::RevertSelectedItemToVersion(CString rev)
1312 if (rev.IsEmpty() || rev == GIT_REV_ZERO)
1313 return 0;
1315 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1316 int index;
1317 int count = 0;
1318 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1320 CString cmd, out;
1321 CTGitPath *fentry = (CTGitPath *)m_arFilteredList[index];
1322 cmd.Format(_T("git.exe checkout %s -- \"%s\""), rev, fentry->GetGitPathString());
1323 if (g_Git.Run(cmd, &out, CP_UTF8))
1325 if (CMessageBox::Show(NULL, out, _T("TortoiseGit"), 2, IDI_WARNING, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
1326 break;
1328 else
1329 count++;
1332 CString out;
1333 out.Format(IDS_STATUSLIST_FILESREVERTED, count, rev);
1334 CMessageBox::Show(NULL, out, _T("TortoiseGit"), MB_OK);
1335 return 0;
1338 static void AppendMenuChecked(CMenu &menu, UINT nTextID, UINT_PTR nItemID, BOOL checked = FALSE, BOOL enabled = TRUE)
1340 CString text;
1341 text.LoadString(nTextID);
1342 menu.AppendMenu(MF_STRING | (enabled ? MF_ENABLED : MF_DISABLED) | (checked ? MF_CHECKED : MF_UNCHECKED), nItemID, text);
1345 #define DIFFOPTION_IGNORESPACEATEOL 1
1346 #define DIFFOPTION_IGNORESPACECHANGE 2
1347 #define DIFFOPTION_IGNOREALLSPACE 3
1348 #define DIFFOPTION_IGNORBLANKLINES 4
1350 void CFileDiffDlg::OnBnClickedDiffoption()
1352 CMenu popup;
1353 if (popup.CreatePopupMenu())
1355 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORESPACEATEOL, DIFFOPTION_IGNORESPACEATEOL, m_bIgnoreSpaceAtEol);
1356 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORESPACECHANGE, DIFFOPTION_IGNORESPACECHANGE, m_bIgnoreSpaceChange);
1357 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNOREALLSPACE, DIFFOPTION_IGNOREALLSPACE, m_bIgnoreAllSpace);
1358 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORBLANKLINES, DIFFOPTION_IGNORBLANKLINES, m_bIgnoreBlankLines);
1360 m_tooltips.Pop();
1361 RECT rect;
1362 GetDlgItem(IDC_DIFFOPTION)->GetWindowRect(&rect);
1363 int selection = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, rect.left, rect.bottom, this, 0);
1364 switch (selection)
1366 case DIFFOPTION_IGNORESPACEATEOL:
1367 m_bIgnoreSpaceAtEol = !m_bIgnoreSpaceAtEol;
1368 OnTimer(IDT_INPUT);
1369 break;
1370 case DIFFOPTION_IGNORESPACECHANGE:
1371 m_bIgnoreSpaceChange = !m_bIgnoreSpaceChange;
1372 OnTimer(IDT_INPUT);
1373 break;
1374 case DIFFOPTION_IGNOREALLSPACE:
1375 m_bIgnoreAllSpace = !m_bIgnoreAllSpace;
1376 OnTimer(IDT_INPUT);
1377 break;
1378 case DIFFOPTION_IGNORBLANKLINES:
1379 m_bIgnoreBlankLines = !m_bIgnoreBlankLines;
1380 OnTimer(IDT_INPUT);
1381 break;
1382 default:
1383 break;
1385 UpdateData(FALSE);
1389 void CFileDiffDlg::OnBnClickedLog()
1391 CLogDlg dlg;
1392 dlg.SetRange(m_rev2.m_CommitHash.ToString() + _T("..") + m_rev1.m_CommitHash.ToString());
1393 dlg.DoModal();