Do not use GitAdminDir objects
[TortoiseGit.git] / src / TortoiseProc / FileDiffDlg.cpp
blob83bd099920c7dd4d3606172241d816076444d58d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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 "SysImageList.h"
26 #include "IconMenu.h"
27 #include "StringUtils.h"
28 #include "PathUtils.h"
29 #include "BrowseFolder.h"
30 #include "FileDiffDlg.h"
31 #include "GitDiff.h"
32 #include "LoglistCommonResource.h"
33 #include "LoglistUtils.h"
34 #include "BrowseRefsDlg.h"
35 #include "LogDlg.h"
36 #include "RefLogDlg.h"
37 #include "GitStatusListCtrl.h"
38 #include "FormatMessageWrapper.h"
40 #define ID_COMPARE 1
41 #define ID_BLAME 2
42 #define ID_SAVEAS 3
43 #define ID_EXPORT 4
44 #define ID_CLIPBOARD_PATH 5
45 #define ID_CLIPBOARD_ALL 6
46 #define ID_LOG 7
47 #define ID_GNUDIFFCOMPARE 8
48 #define ID_REVERT1 9
49 #define ID_REVERT2 10
50 #define ID_LOGSUBMODULE 11
52 BOOL CFileDiffDlg::m_bAscending = TRUE;
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_bCancelled(false)
63 , m_nIconFolder(0)
64 , m_bThreadRunning(FALSE)
65 , m_bIgnoreSpaceAtEol(false)
66 , m_bIgnoreSpaceChange(false)
67 , m_bIgnoreAllSpace(false)
68 , m_bIgnoreBlankLines(false)
69 , m_bIsBare(false)
71 m_bLoadingRef=FALSE;
74 CFileDiffDlg::~CFileDiffDlg()
78 void CFileDiffDlg::DoDataExchange(CDataExchange* pDX)
80 CResizableStandAloneDialog::DoDataExchange(pDX);
81 DDX_Control(pDX, IDC_FILELIST, m_cFileList);
82 DDX_Control(pDX, IDC_SWITCHLEFTRIGHT, m_SwitchButton);
83 DDX_Control(pDX, IDC_REV1BTN, m_cRev1Btn);
84 DDX_Control(pDX, IDC_REV2BTN, m_cRev2Btn);
85 DDX_Control(pDX, IDC_FILTER, m_cFilter);
86 DDX_Control(pDX, IDC_REV1EDIT, m_ctrRev1Edit);
87 DDX_Control(pDX, IDC_REV2EDIT, m_ctrRev2Edit);
91 BEGIN_MESSAGE_MAP(CFileDiffDlg, CResizableStandAloneDialog)
92 ON_NOTIFY(NM_DBLCLK, IDC_FILELIST, OnNMDblclkFilelist)
93 ON_NOTIFY(LVN_GETINFOTIP, IDC_FILELIST, OnLvnGetInfoTipFilelist)
94 ON_NOTIFY(NM_CUSTOMDRAW, IDC_FILELIST, OnNMCustomdrawFilelist)
95 ON_WM_CONTEXTMENU()
96 ON_WM_SETCURSOR()
97 ON_EN_SETFOCUS(IDC_SECONDURL, &CFileDiffDlg::OnEnSetfocusSecondurl)
98 ON_EN_SETFOCUS(IDC_FIRSTURL, &CFileDiffDlg::OnEnSetfocusFirsturl)
99 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT, &CFileDiffDlg::OnBnClickedSwitchleftright)
100 ON_NOTIFY(HDN_ITEMCLICK, 0, &CFileDiffDlg::OnHdnItemclickFilelist)
101 ON_BN_CLICKED(IDC_REV1BTN, &CFileDiffDlg::OnBnClickedRev1btn)
102 ON_BN_CLICKED(IDC_REV2BTN, &CFileDiffDlg::OnBnClickedRev2btn)
103 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)
104 ON_EN_CHANGE(IDC_FILTER, &CFileDiffDlg::OnEnChangeFilter)
105 ON_WM_TIMER()
106 ON_MESSAGE(ENAC_UPDATE, &CFileDiffDlg::OnEnUpdate)
107 ON_MESSAGE(MSG_REF_LOADED, OnRefLoad)
108 ON_REGISTERED_MESSAGE(WM_DISABLEBUTTONS, OnDisableButtons)
109 ON_REGISTERED_MESSAGE(WM_DIFFFINISHED, OnDiffFinished)
110 ON_BN_CLICKED(IDC_DIFFOPTION, OnBnClickedDiffoption)
111 ON_BN_CLICKED(IDC_LOG, &CFileDiffDlg::OnBnClickedLog)
112 END_MESSAGE_MAP()
115 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1, const GitRev &rev2)
117 if(path!=NULL)
119 m_path1 = *path;
120 m_path2 = *path;
121 m_sFilter = path->GetGitPathString();
123 m_rev1 = rev1;
124 m_rev2 = rev2;
127 void CFileDiffDlg::SetDiff(const CTGitPath * path, const CString &hash1, const CString &hash2)
129 if(path!=NULL)
131 m_path1 = *path;
132 m_path2 = *path;
133 m_sFilter = path->GetGitPathString();
136 BYTE_VECTOR logout;
138 if(hash1 == GIT_REV_ZERO)
140 m_rev1.m_CommitHash.Empty();
141 m_rev1.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
143 else
147 m_rev1.GetCommit(hash1);
149 catch (const char *msg)
151 MessageBox(_T("Could not get commit ") + hash1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
155 logout.clear();
157 if(hash2 == GIT_REV_ZERO)
159 m_rev2.m_CommitHash.Empty();
160 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
162 else
166 m_rev2.GetCommit(hash2);
168 catch (const char *msg)
170 MessageBox(_T("Could not get commit ") + hash2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
175 void CFileDiffDlg::SetDiff(const CTGitPath * path, const GitRev &rev1)
177 if(path!=NULL)
179 m_path1 = *path;
180 m_path2 = *path;
181 m_sFilter = path->GetGitPathString();
183 m_rev1 = rev1;
184 m_rev2.m_CommitHash.Empty();
185 m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_PROC_PREVIOUSVERSION));
187 //this->GetDlgItem()->EnableWindow(FALSE);
190 BOOL CFileDiffDlg::OnInitDialog()
192 CResizableStandAloneDialog::OnInitDialog();
193 CString temp;
195 CString sWindowTitle;
196 GetWindowText(sWindowTitle);
197 CString pathText = g_Git.m_CurrentDir;
198 if (!m_path1.IsEmpty())
199 pathText = g_Git.CombinePath(m_path1);
200 CAppUtils::SetWindowTitle(m_hWnd, pathText, sWindowTitle);
202 this->m_ctrRev1Edit.Init();
203 this->m_ctrRev2Edit.Init();
205 m_tooltips.Create(this);
206 m_tooltips.AddTool(IDC_SWITCHLEFTRIGHT, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT);
208 m_cFileList.SetRedraw(false);
209 m_cFileList.DeleteAllItems();
210 DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
211 m_cFileList.SetExtendedStyle(exStyle);
213 m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();
214 m_cFileList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);
216 m_SwitchButton.SetImage((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
217 m_SwitchButton.Invalidate();
219 m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);
220 m_cFilter.SetInfoIcon(IDI_FILTEREDIT);
221 temp.LoadString(IDS_FILEDIFF_FILTERCUE);
222 temp = _T(" ")+temp;
223 m_cFilter.SetCueBanner(temp);
224 if (!m_sFilter.IsEmpty())
225 m_cFilter.SetWindowText(m_sFilter);
227 int c = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
228 while (c>=0)
229 m_cFileList.DeleteColumn(c--);
231 temp.LoadString(IDS_FILEDIFF_FILE);
232 m_cFileList.InsertColumn(0, temp);
233 temp.LoadString(IDS_FILEDIFF_EXT);
234 m_cFileList.InsertColumn(1, temp);
235 temp.LoadString(IDS_FILEDIFF_ACTION);
236 m_cFileList.InsertColumn(2, temp);
238 temp.LoadString(IDS_FILEDIFF_STATADD);
239 m_cFileList.InsertColumn(3, temp);
240 temp.LoadString(IDS_FILEDIFF_STATDEL);
241 m_cFileList.InsertColumn(4, temp);
243 int mincol = 0;
244 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
245 int col;
246 for (col = mincol; col <= maxcol; col++)
248 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);
251 m_cFileList.SetRedraw(true);
253 AddAnchor(IDC_DIFFSTATIC1, TOP_LEFT, TOP_RIGHT);
254 AddAnchor(IDC_SWITCHLEFTRIGHT, TOP_RIGHT);
255 AddAnchor(IDC_FIRSTURL, TOP_LEFT, TOP_RIGHT);
256 AddAnchor(IDC_REV1BTN, TOP_RIGHT);
257 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
258 AddAnchor(IDC_SECONDURL, TOP_LEFT, TOP_RIGHT);
259 AddAnchor(IDC_REV2BTN, TOP_RIGHT);
260 AddAnchor(IDC_FILTER, TOP_LEFT, TOP_RIGHT);
261 AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);
262 AddAnchor(IDC_REV1GROUP,TOP_LEFT,TOP_RIGHT);
263 AddAnchor(IDC_REV2GROUP,TOP_LEFT,TOP_RIGHT);
264 AddAnchor(IDC_REV1EDIT,TOP_LEFT);
265 AddAnchor(IDC_REV2EDIT,TOP_LEFT);
266 AddAnchor(IDC_DIFFOPTION, TOP_RIGHT);
267 AddAnchor(IDC_LOG, TOP_RIGHT);
269 EnableSaveRestore(_T("FileDiffDlg"));
271 m_bIsBare = GitAdminDir::IsBareRepo(g_Git.m_CurrentDir);
273 if(this->m_strRev1.IsEmpty())
274 this->m_ctrRev1Edit.SetWindowText(this->m_rev1.m_CommitHash.ToString());
275 else
277 bool rev1fail = false;
280 rev1fail = !!m_rev1.GetCommit(m_strRev1);
282 catch (const char *msg)
284 rev1fail = true;
285 MessageBox(_T("Could not get commit ") + m_strRev1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
287 if (rev1fail)
289 CString msg;
290 msg.Format(IDS_PROC_REFINVALID, m_strRev1);
291 this->m_FileListText += msg;
294 this->m_ctrRev1Edit.SetWindowText(m_strRev1);
297 if(this->m_strRev2.IsEmpty())
298 this->m_ctrRev2Edit.SetWindowText(this->m_rev2.m_CommitHash.ToString());
299 else
301 bool rev2fail = false;
304 rev2fail = !!m_rev2.GetCommit(m_strRev2);
306 catch (const char *msg)
308 rev2fail = true;
309 MessageBox(_T("Could not get commit ") + m_strRev2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
311 if (rev2fail)
313 CString msg;
314 msg.Format(IDS_PROC_REFINVALID, m_strRev2);
315 this->m_FileListText += msg;
318 this->m_ctrRev2Edit.SetWindowText(m_strRev2);
321 SetURLLabels();
323 InterlockedExchange(&m_bThreadRunning, TRUE);
324 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
326 InterlockedExchange(&m_bThreadRunning, FALSE);
327 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
330 InterlockedExchange(&m_bLoadingRef, TRUE);
331 if (AfxBeginThread(LoadRefThreadEntry, this)==NULL)
333 InterlockedExchange(&m_bLoadingRef, FALSE);
334 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
337 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
338 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
339 this->m_cRev1Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
341 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE)));
342 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG)));
343 this->m_cRev2Btn.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG)));
345 // Start with focus on file list
346 GetDlgItem(IDC_FILELIST)->SetFocus();
348 if(m_rev2.m_CommitHash.IsEmpty())
349 m_SwitchButton.EnableWindow(FALSE);
351 KillTimer(IDT_INPUT);
352 return FALSE;
355 UINT CFileDiffDlg::DiffThreadEntry(LPVOID pVoid)
357 return ((CFileDiffDlg*)pVoid)->DiffThread();
360 UINT CFileDiffDlg::DiffThread()
362 SendMessage(WM_DISABLEBUTTONS);
364 if( m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty())
365 g_Git.RefreshGitIndex();
367 g_Git.GetCommitDiffList(m_rev1.m_CommitHash.ToString(), m_rev2.m_CommitHash.ToString(), m_arFileList, m_bIgnoreSpaceAtEol, m_bIgnoreSpaceChange, m_bIgnoreAllSpace, m_bIgnoreBlankLines);
368 Sort();
370 SendMessage(WM_DIFFFINISHED);
372 InterlockedExchange(&m_bThreadRunning, FALSE);
373 return 0;
376 LRESULT CFileDiffDlg::OnDisableButtons(WPARAM, LPARAM)
378 RefreshCursor();
379 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT)));
380 m_cFileList.DeleteAllItems();
381 m_arFileList.Clear();
382 EnableInputControl(false);
383 return 0;
386 LRESULT CFileDiffDlg::OnDiffFinished(WPARAM, LPARAM)
388 CString sFilterText;
389 m_cFilter.GetWindowText(sFilterText);
390 m_cFileList.SetRedraw(false);
391 Filter(sFilterText);
392 if (!m_arFileList.IsEmpty())
394 // Highlight first entry in file list
395 m_cFileList.SetSelectionMark(0);
396 m_cFileList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
399 int mincol = 0;
400 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
401 int col;
402 for (col = mincol; col <= maxcol; ++col)
404 m_cFileList.SetColumnWidth(col, LVSCW_AUTOSIZE_USEHEADER);
407 m_cFileList.ClearText();
408 if (m_arFileList.IsEmpty())
409 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_COMPAREREV_NODIFF)));
410 m_cFileList.SetRedraw(true);
412 InvalidateRect(NULL);
413 RefreshCursor();
414 EnableInputControl(true);
415 return 0;
418 int CFileDiffDlg::AddEntry(const CTGitPath * fd)
420 int ret = -1;
421 if (fd)
423 int index = m_cFileList.GetItemCount();
425 int icon_idx = 0;
426 if (fd->IsDirectory())
427 icon_idx = m_nIconFolder;
428 else
429 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(fd->GetGitPathString());
431 ret = m_cFileList.InsertItem(index, fd->GetGitPathString(), icon_idx);
432 m_cFileList.SetItemText(index, 1, ((CTGitPath*)fd)->GetFileExtension());
433 m_cFileList.SetItemText(index, 2, ((CTGitPath*)fd)->GetActionName());
434 m_cFileList.SetItemText(index, 3, ((CTGitPath*)fd)->m_StatAdd);
435 m_cFileList.SetItemText(index, 4, ((CTGitPath*)fd)->m_StatDel);
437 return ret;
440 void CFileDiffDlg::EnableInputControl(bool b)
442 this->m_ctrRev1Edit.EnableWindow(b);
443 this->m_ctrRev2Edit.EnableWindow(b);
444 this->m_cRev1Btn.EnableWindow(b);
445 this->m_cRev2Btn.EnableWindow(b);
446 m_cFilter.EnableWindow(b);
447 m_SwitchButton.EnableWindow(b);
448 GetDlgItem(IDC_LOG)->EnableWindow(b && !(m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty()));
451 void CFileDiffDlg::DoDiff(int selIndex, bool blame)
453 CGitDiff diff;
454 CTGitPath* fd2 = m_arFilteredList[selIndex];
455 CTGitPath* fd1 = fd2;
456 if (m_rev1.m_CommitHash.IsEmpty() && g_Git.IsInitRepos())
458 CGitDiff::DiffNull(fd2, GIT_REV_ZERO);
459 return;
461 if (fd2->m_Action & CTGitPath::LOGACTIONS_ADDED)
463 CGitDiff::DiffNull(fd2, m_rev1.m_CommitHash.ToString(), true);
464 return;
466 if (fd2->m_Action & CTGitPath::LOGACTIONS_DELETED)
468 CGitDiff::DiffNull(fd2, m_rev2.m_CommitHash.ToString(), false);
469 return;
471 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
472 fd1 = new CTGitPath(fd2->GetGitOldPathString());
473 diff.Diff(fd2, fd1, this->m_rev1.m_CommitHash.ToString(), this->m_rev2.m_CommitHash.ToString(), blame, FALSE);
474 if (fd1 != fd2)
475 delete fd1;
479 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)
481 *pResult = 0;
482 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
483 int selIndex = pNMLV->iItem;
484 if (selIndex < 0)
485 return;
486 if (selIndex >= (int)m_arFilteredList.size())
487 return;
489 DoDiff(selIndex, m_bBlame);
492 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR *pNMHDR, LRESULT *pResult)
495 LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);
496 if (pGetInfoTip->iItem >= (int)m_arFilteredList.size())
497 return;
499 CString path = m_path1.GetGitPathString() + _T("/") + m_arFilteredList[pGetInfoTip->iItem]->GetGitPathString();
500 if (pGetInfoTip->cchTextMax > path.GetLength())
501 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path, pGetInfoTip->cchTextMax);
503 *pResult = 0;
506 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR *pNMHDR, LRESULT *pResult)
508 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
509 // Take the default processing unless we set this to something else below.
510 *pResult = CDRF_DODEFAULT;
512 // First thing - check the draw stage. If it's the control's prepaint
513 // stage, then tell Windows we want messages for every item.
515 if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
517 *pResult = CDRF_NOTIFYITEMDRAW;
519 else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
521 // This is the prepaint stage for an item. Here's where we set the
522 // item's text color. Our return value will tell Windows to draw the
523 // item itself, but it will use the new color we set here.
525 // Tell Windows to paint the control itself.
526 *pResult = CDRF_DODEFAULT;
528 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
530 if (m_arFilteredList.size() > pLVCD->nmcd.dwItemSpec)
532 CTGitPath * fd = m_arFilteredList[pLVCD->nmcd.dwItemSpec];
533 switch (fd->m_Action)
535 case CTGitPath::LOGACTIONS_ADDED:
536 crText = m_colors.GetColor(CColors::Added);
537 break;
538 case CTGitPath::LOGACTIONS_DELETED:
539 crText = m_colors.GetColor(CColors::Deleted);
540 break;
541 case CTGitPath::LOGACTIONS_MODIFIED:
542 crText = m_colors.GetColor(CColors::Modified);
543 break;
544 default:
545 crText = m_colors.GetColor(CColors::PropertyChanged);
546 break;
549 // Store the color back in the NMLVCUSTOMDRAW struct.
550 pLVCD->clrText = crText;
554 UINT CFileDiffDlg::LoadRefThread()
556 g_Git.GetBranchList(m_Reflist,NULL,CGit::BRANCH_ALL_F);
557 g_Git.GetTagList(m_Reflist);
559 this->PostMessage(MSG_REF_LOADED);
560 InterlockedExchange(&m_bLoadingRef, FALSE);
561 return 0;
564 void CFileDiffDlg::OnContextMenu(CWnd* pWnd, CPoint point)
566 if ((pWnd==0)||(pWnd != &m_cFileList))
567 return;
568 if (m_cFileList.GetSelectedCount() == 0)
569 return;
570 // if the context menu is invoked through the keyboard, we have to use
571 // a calculated position on where to anchor the menu on
572 if ((point.x == -1) && (point.y == -1))
574 CRect rect;
575 m_cFileList.GetItemRect(m_cFileList.GetSelectionMark(), &rect, LVIR_LABEL);
576 m_cFileList.ClientToScreen(&rect);
577 point = rect.CenterPoint();
579 CIconMenu popup;
580 if (popup.CreatePopupMenu())
582 int firstEntry = -1;
583 POSITION firstPos = m_cFileList.GetFirstSelectedItemPosition();
584 if (firstPos)
585 firstEntry = m_cFileList.GetNextSelectedItem(firstPos);
587 CString menuText;
588 popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);
589 popup.AppendMenuIcon(ID_GNUDIFFCOMPARE, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);
590 popup.AppendMenu(MF_SEPARATOR, NULL);
591 if (!m_bIsBare)
593 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev1.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
594 popup.AppendMenuIcon(ID_REVERT1, menuText, IDI_REVERT);
595 menuText.Format(IDS_FILEDIFF_POPREVERTTOREV, m_rev2.m_CommitHash.ToString().Left(g_Git.GetShortHASHLength()));
596 popup.AppendMenuIcon(ID_REVERT2, menuText, IDI_REVERT);
597 popup.AppendMenu(MF_SEPARATOR, NULL);
599 popup.AppendMenuIcon(ID_LOG, IDS_FILEDIFF_LOG, IDI_LOG);
600 if (firstEntry >= 0 && !m_arFilteredList[firstEntry]->IsDirectory())
602 if (!m_bIsBare)
604 popup.AppendMenuIcon(ID_BLAME, IDS_FILEDIFF_POPBLAME, IDI_BLAME);
605 popup.AppendMenu(MF_SEPARATOR, NULL);
607 popup.AppendMenuIcon(ID_EXPORT, IDS_FILEDIFF_POPEXPORT, IDI_EXPORT);
609 else if (firstEntry >= 0)
610 popup.AppendMenuIcon(ID_LOGSUBMODULE, IDS_MENULOGSUBMODULE, IDI_LOG);
611 popup.AppendMenu(MF_SEPARATOR, NULL);
612 popup.AppendMenuIcon(ID_SAVEAS, IDS_FILEDIFF_POPSAVELIST, IDI_SAVEAS);
613 popup.AppendMenuIcon(ID_CLIPBOARD_PATH, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);
614 popup.AppendMenuIcon(ID_CLIPBOARD_ALL, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);
616 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
617 m_bCancelled = false;
618 switch (cmd)
620 case ID_COMPARE:
622 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
623 while (pos)
625 int index = m_cFileList.GetNextSelectedItem(pos);
626 DoDiff(index, false);
629 break;
630 case ID_GNUDIFFCOMPARE:
632 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
633 while (pos)
635 CTGitPath *fd2 = m_arFilteredList[m_cFileList.GetNextSelectedItem(pos)];
636 CTGitPath *fd1 = fd2;
637 if (fd2->m_Action & CTGitPath::LOGACTIONS_REPLACED)
638 fd1 = new CTGitPath(fd2->GetGitOldPathString());
639 CAppUtils::StartShowUnifiedDiff(m_hWnd, *fd2, m_rev2.m_CommitHash.ToString(), *fd1, m_rev1.m_CommitHash.ToString());
640 if (fd1 != fd2)
641 delete fd1;
644 break;
645 case ID_REVERT1:
646 RevertSelectedItemToVersion(m_rev1.m_CommitHash.ToString());
647 break;
648 case ID_REVERT2:
649 RevertSelectedItemToVersion(m_rev2.m_CommitHash.ToString());
650 break;
651 case ID_BLAME:
653 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
654 while (pos)
656 int index = m_cFileList.GetNextSelectedItem(pos);
657 CAppUtils::LaunchTortoiseBlame(m_arFilteredList[index]->GetWinPathString(), m_rev1.m_CommitHash.ToString());
660 break;
661 case ID_LOG:
662 case ID_LOGSUBMODULE:
664 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
665 while (pos)
667 int index = m_cFileList.GetNextSelectedItem(pos);
668 CString cmd = _T("/command:log");
669 if (cmd == ID_LOGSUBMODULE)
670 cmd += _T(" /submodule");
671 cmd += _T(" /path:\"")+m_arFilteredList[index]->GetWinPathString()+_T("\" ");
672 cmd += _T(" /endrev:")+m_rev1.m_CommitHash.ToString();
673 CAppUtils::RunTortoiseGitProc(cmd);
676 break;
677 case ID_SAVEAS:
679 if (m_cFileList.GetSelectedCount() > 0)
681 CString temp;
682 CTGitPath savePath;
683 CString pathSave;
684 if (!CAppUtils::FileOpenSave(pathSave, NULL, IDS_REPOBROWSE_SAVEAS, IDS_TEXTFILEFILTER, false, m_hWnd, _T(".txt")))
686 break;
688 savePath = CTGitPath(pathSave);
690 // now open the selected file for writing
693 CStdioFile file(savePath.GetWinPathString(), CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);
694 if (m_path1.IsEmpty() && m_path2.IsEmpty())
695 temp.Format(IDS_FILEDIFF_CHANGEDLISTINTROROOT, m_rev1.m_CommitHash.ToString(), m_rev2.m_CommitHash.ToString());
696 else
697 temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, m_path1.GetGitPathString(), m_rev1.m_CommitHash.ToString(), m_path2.GetGitPathString(), m_rev2.m_CommitHash.ToString());
698 file.WriteString(temp + _T("\r\n"));
699 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
700 while (pos)
702 int index = m_cFileList.GetNextSelectedItem(pos);
703 CTGitPath* fd = m_arFilteredList[index];
704 file.WriteString(fd->GetGitPathString());
705 file.WriteString(_T("\r\n"));
707 file.Close();
709 catch (CFileException* pE)
711 pE->ReportError();
715 break;
716 case ID_CLIPBOARD_PATH:
718 CopySelectionToClipboard();
720 break;
722 case ID_CLIPBOARD_ALL:
724 CopySelectionToClipboard(TRUE);
726 break;
727 case ID_EXPORT:
729 // export all changed files to a folder
730 CBrowseFolder browseFolder;
731 browseFolder.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
732 if (browseFolder.Show(GetSafeHwnd(), m_strExportDir) == CBrowseFolder::OK)
734 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
735 while (pos)
737 int index = m_cFileList.GetNextSelectedItem(pos);
738 CTGitPath* fd = m_arFilteredList[index];
739 // we cannot export directories or folders
740 if (fd->m_Action == CTGitPath::LOGACTIONS_DELETED || fd->IsDirectory())
741 continue;
742 CAppUtils::CreateMultipleDirectory(m_strExportDir + _T("\\") + fd->GetContainingDirectory().GetWinPathString());
743 CString filename = m_strExportDir + _T("\\") + fd->GetWinPathString();
744 if(m_rev1.m_CommitHash.ToString() == GIT_REV_ZERO)
746 if(!CopyFile(g_Git.CombinePath(fd), filename, false))
748 MessageBox(CFormatMessageWrapper(), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
749 return;
752 else
754 if(g_Git.GetOneFile(m_rev1.m_CommitHash, *fd, filename))
756 CString out;
757 out.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED, fd->GetGitPathString(), m_rev1.m_CommitHash.ToString(), filename);
758 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)
759 return;
766 break;
772 BOOL CFileDiffDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
774 if (pWnd != &m_cFileList)
775 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
776 if (m_bThreadRunning == 0)
778 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
779 SetCursor(hCur);
780 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
782 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
783 SetCursor(hCur);
784 return TRUE;
787 void CFileDiffDlg::OnEnSetfocusFirsturl()
789 GetDlgItem(IDC_FIRSTURL)->HideCaret();
792 void CFileDiffDlg::OnEnSetfocusSecondurl()
794 GetDlgItem(IDC_SECONDURL)->HideCaret();
798 void CFileDiffDlg::OnBnClickedSwitchleftright()
801 if (m_bThreadRunning)
802 return;
804 #if 0
805 CString sFilterString;
806 m_cFilter.GetWindowText(sFilterString);
808 m_cFileList.SetRedraw(false);
809 m_cFileList.DeleteAllItems();
810 for (int i=0; i<(int)m_arFileList.GetCount(); ++i)
812 CTGitPath fd = m_arFileList[i];
813 if (fd.m_Action == CTGitPath::LOGACTIONS_ADDED)
814 fd.m_Action = CTGitPath::LOGACTIONS_DELETED;
815 else if (fd.m_Action == CTGitPath::LOGACTIONS_DELETED)
816 fd.m_Action = CTGitPath::LOGACTIONS_ADDED;
817 std::swap(fd.m_StatAdd, fd.m_StatDel);
818 (CTGitPath&)m_arFileList[i] = fd;
820 Filter(sFilterString);
821 #endif
823 m_cFileList.SetRedraw(true);
824 CTGitPath path = m_path1;
825 m_path1 = m_path2;
826 m_path2 = path;
827 GitRev rev = m_rev1;
828 m_rev1 = m_rev2;
829 m_rev2 = rev;
831 CString str1,str2;
832 this->m_ctrRev1Edit.GetWindowText(str1);
833 this->m_ctrRev2Edit.GetWindowText(str2);
835 this->m_ctrRev1Edit.SetWindowText(str2);
836 this->m_ctrRev2Edit.SetWindowText(str1);
838 SetURLLabels();
839 //KillTimer(IDT_INPUT);
842 void CFileDiffDlg::SetURLLabels(int mask)
845 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
846 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
848 if(mask &0x1)
850 SetDlgItemText(IDC_FIRSTURL, m_rev1.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev1.GetSubject());
851 if (!m_rev1.m_CommitHash.IsEmpty())
852 m_tooltips.AddTool(IDC_FIRSTURL,
853 CLoglistUtils::FormatDateAndTime(m_rev1.GetAuthorDate(), DATE_SHORTDATE) + _T(" ") + m_rev1.GetAuthorName());
857 if(mask &0x2)
859 SetDlgItemText(IDC_SECONDURL,m_rev2.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev2.GetSubject());
860 if (!m_rev2.m_CommitHash.IsEmpty())
861 m_tooltips.AddTool(IDC_SECONDURL,
862 CLoglistUtils::FormatDateAndTime(m_rev2.GetAuthorDate(), DATE_SHORTDATE) + _T(" ") + m_rev2.GetAuthorName());
865 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASE)));
866 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1)));
868 if( (mask&0x3) == 0x3 && !m_rev1.m_CommitHash.IsEmpty() && !m_rev2.m_CommitHash.IsEmpty())
869 if(m_rev2.GetCommitterDate() > m_rev1.GetCommitterDate())
871 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASENEWER)));
873 else if (m_rev2.GetCommitterDate() < m_rev1.GetCommitterDate())
875 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1NEWER)));
879 void CFileDiffDlg::ClearURLabels(int mask)
881 if(mask&0x1)
883 SetDlgItemText(IDC_FIRSTURL, _T(""));
884 m_tooltips.AddTool(IDC_FIRSTURL, _T(""));
887 if(mask&0x2)
889 SetDlgItemText(IDC_SECONDURL, _T(""));
890 m_tooltips.AddTool(IDC_SECONDURL, _T(""));
893 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)
895 m_tooltips.RelayEvent(pMsg);
896 if (pMsg->message == WM_KEYDOWN)
898 switch (pMsg->wParam)
900 case 'A':
902 if (GetFocus() != GetDlgItem(IDC_FILELIST))
903 break;
904 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
906 // select all entries
907 for (int i=0; i<m_cFileList.GetItemCount(); ++i)
909 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
911 return TRUE;
914 break;
915 case 'C':
916 case VK_INSERT:
918 if (GetFocus() != GetDlgItem(IDC_FILELIST))
919 break;
920 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
922 CopySelectionToClipboard();
923 return TRUE;
926 break;
927 case '\r':
929 if (GetFocus() == GetDlgItem(IDC_FILELIST))
931 // Return pressed in file list. Show diff, as for double click
932 int selIndex = m_cFileList.GetSelectionMark();
933 if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))
934 DoDiff(selIndex, m_bBlame);
935 return TRUE;
938 break;
939 case VK_F5:
941 OnTimer(IDT_INPUT);
943 break;
946 return __super::PreTranslateMessage(pMsg);
949 void CFileDiffDlg::OnCancel()
951 if (m_bThreadRunning)
953 m_bCancelled = true;
954 return;
956 __super::OnCancel();
959 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)
961 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
962 if (m_bThreadRunning)
963 return;
965 if (m_nSortedColumn == phdr->iItem)
966 m_bAscending = !m_bAscending;
967 else
968 m_bAscending = TRUE;
969 m_nSortedColumn = phdr->iItem;
970 Sort();
972 CString temp;
973 m_cFileList.SetRedraw(FALSE);
974 m_cFileList.DeleteAllItems();
975 m_cFilter.GetWindowText(temp);
976 Filter(temp);
978 CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();
979 HDITEM HeaderItem = {0};
980 HeaderItem.mask = HDI_FORMAT;
981 for (int i=0; i<pHeader->GetItemCount(); ++i)
983 pHeader->GetItem(i, &HeaderItem);
984 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
985 pHeader->SetItem(i, &HeaderItem);
987 pHeader->GetItem(m_nSortedColumn, &HeaderItem);
988 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);
989 pHeader->SetItem(m_nSortedColumn, &HeaderItem);
991 m_cFileList.SetRedraw(TRUE);
993 *pResult = 0;
996 void CFileDiffDlg::Sort()
998 if(m_arFileList.GetCount() < 2)
1000 return;
1003 std::sort(m_arFileList.m_paths.begin(), m_arFileList.m_paths.end(), &CFileDiffDlg::SortCompare);
1006 bool CFileDiffDlg::SortCompare(const CTGitPath& Data1, const CTGitPath& Data2)
1008 int result = 0;
1009 int d1, d2;
1010 switch (m_nSortedColumn)
1012 case 0: //path column
1013 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
1014 break;
1015 case 1: //extension column
1016 result = Data1.GetFileExtension().Compare(Data2.GetFileExtension());
1017 break;
1018 case 2: //action column
1019 result = Data1.m_Action - Data2.m_Action;
1020 break;
1021 case 3:
1022 d1 = CSorter::A2L(Data1.m_StatAdd);
1023 d2 = CSorter::A2L(Data2.m_StatAdd);
1024 result = d1 - d2;
1025 break;
1026 case 4:
1027 d1 = CSorter::A2L(Data1.m_StatDel);;
1028 d2 = CSorter::A2L(Data2.m_StatDel);
1029 result = d1 - d2;
1030 break;
1031 default:
1032 break;
1034 // sort by path name as second priority
1035 if (m_nSortedColumn != 0 && result == 0)
1036 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
1038 if (!m_bAscending)
1039 result = -result;
1040 return result < 0;
1044 void CFileDiffDlg::OnBnClickedRev1btn()
1046 ClickRevButton(&this->m_cRev1Btn,&this->m_rev1, &this->m_ctrRev1Edit);
1049 void CFileDiffDlg::ClickRevButton(CMenuButton *button, GitRev *rev, CACEdit *edit)
1051 INT_PTR entry=button->GetCurrentEntry();
1052 if(entry == 0) /* Browse Refence*/
1055 CString str = CBrowseRefsDlg::PickRef();
1056 if(str.IsEmpty())
1057 return;
1059 if(FillRevFromString(rev,str))
1060 return;
1062 edit->SetWindowText(str);
1066 if(entry == 1) /*Log*/
1068 CLogDlg dlg;
1069 CString revision;
1070 edit->GetWindowText(revision);
1071 dlg.SetParams(CTGitPath(), CTGitPath(), revision, revision, 0);
1072 dlg.SetSelect(true);
1073 if(dlg.DoModal() == IDOK)
1075 if( dlg.GetSelectedHash().IsEmpty() )
1076 return;
1078 if(FillRevFromString(rev,dlg.GetSelectedHash()))
1079 return;
1081 edit->SetWindowText(dlg.GetSelectedHash());
1084 else
1085 return;
1088 if(entry == 2) /*RefLog*/
1090 CRefLogDlg dlg;
1091 if(dlg.DoModal() == IDOK)
1093 if(FillRevFromString(rev,dlg.m_SelectedHash))
1094 return;
1096 edit->SetWindowText(dlg.m_SelectedHash);
1099 else
1100 return;
1103 SetURLLabels();
1105 InterlockedExchange(&m_bThreadRunning, TRUE);
1106 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1108 InterlockedExchange(&m_bThreadRunning, FALSE);
1109 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1111 KillTimer(IDT_INPUT);
1114 void CFileDiffDlg::OnBnClickedRev2btn()
1116 ClickRevButton(&this->m_cRev2Btn,&this->m_rev2, &this->m_ctrRev2Edit);
1119 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)
1121 if (m_bThreadRunning)
1123 SetTimer(IDT_FILTER, 1000, NULL);
1124 return 0L;
1127 KillTimer(IDT_FILTER);
1129 m_cFileList.SetRedraw(FALSE);
1130 m_arFilteredList.clear();
1131 m_cFileList.DeleteAllItems();
1133 Filter(_T(""));
1135 m_cFileList.SetRedraw(TRUE);
1136 return 0L;
1139 void CFileDiffDlg::OnEnChangeFilter()
1141 SetTimer(IDT_FILTER, 1000, NULL);
1144 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)
1146 if (m_bThreadRunning)
1147 return;
1149 if( nIDEvent == IDT_FILTER)
1151 CString sFilterText;
1152 KillTimer(IDT_FILTER);
1153 m_cFilter.GetWindowText(sFilterText);
1155 m_cFileList.SetRedraw(FALSE);
1156 m_cFileList.DeleteAllItems();
1158 Filter(sFilterText);
1160 m_cFileList.SetRedraw(TRUE);
1162 __super::OnTimer(nIDEvent);
1165 if( nIDEvent == IDT_INPUT)
1167 KillTimer(IDT_INPUT);
1168 TRACE(_T("Input Timer\r\n"));
1170 GitRev gitrev;
1171 CString str;
1172 int mask = 0;
1173 this->m_ctrRev1Edit.GetWindowText(str);
1176 if (!gitrev.GetCommit(str))
1178 m_rev1 = gitrev;
1179 mask |= 0x1;
1182 catch (const char *msg)
1184 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1187 this->m_ctrRev2Edit.GetWindowText(str);
1191 if (!gitrev.GetCommit(str))
1193 m_rev2 = gitrev;
1194 mask |= 0x2;
1197 catch (const char *msg)
1199 CMessageBox::Show(m_hWnd, _T("Could not get commit ") + str + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
1202 this->SetURLLabels(mask);
1204 if(mask == 0x3)
1207 InterlockedExchange(&m_bThreadRunning, TRUE);
1208 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1210 InterlockedExchange(&m_bThreadRunning, FALSE);
1211 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1217 void CFileDiffDlg::Filter(CString sFilterText)
1219 sFilterText.MakeLower();
1221 m_arFilteredList.clear();
1223 for (int i=0;i<m_arFileList.GetCount();i++)
1225 CString sPath = m_arFileList[i].GetGitPathString();
1226 sPath.MakeLower();
1227 if (sPath.Find(sFilterText) >= 0)
1229 m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));
1232 for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)
1234 AddEntry(*it);
1238 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull)
1240 // copy all selected paths to the clipboard
1241 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1242 int index;
1243 CString sTextForClipboard;
1244 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1246 sTextForClipboard += m_cFileList.GetItemText(index, 0);
1247 sTextForClipboard += _T("\t");
1249 if(!isFull)
1251 sTextForClipboard += _T("\r\n");
1254 else
1256 sTextForClipboard += m_cFileList.GetItemText(index, 1);
1257 sTextForClipboard += _T("\t");
1258 sTextForClipboard += m_cFileList.GetItemText(index, 2);
1259 sTextForClipboard += _T("\t");
1260 sTextForClipboard += m_cFileList.GetItemText(index, 3);
1261 sTextForClipboard += _T("\t");
1262 sTextForClipboard += m_cFileList.GetItemText(index, 4);
1263 sTextForClipboard += _T("\r\n");
1266 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);
1270 LRESULT CFileDiffDlg::OnRefLoad(WPARAM /*wParam*/, LPARAM /*lParam*/)
1272 for (size_t i = 0; i < m_Reflist.size(); ++i)
1274 CString str=m_Reflist[i];
1276 if(str.Find(_T("remotes/")) == 0)
1277 str=str.Mid(8);
1279 m_ctrRev1Edit.AddSearchString(str);
1280 m_ctrRev2Edit.AddSearchString(str);
1282 return 0;
1285 BOOL CFileDiffDlg::DestroyWindow()
1287 return CResizableStandAloneDialog::DestroyWindow();
1290 LRESULT CFileDiffDlg::OnEnUpdate(WPARAM /*wParam*/, LPARAM lParam)
1292 if(lParam == IDC_REV1EDIT)
1294 OnTextUpdate(&this->m_ctrRev1Edit);
1295 ClearURLabels(1);
1297 if(lParam == IDC_REV2EDIT)
1299 OnTextUpdate(&this->m_ctrRev2Edit);
1300 ClearURLabels(1<<1);
1302 return 0;
1305 void CFileDiffDlg::OnTextUpdate(CACEdit * /*pEdit*/)
1307 SetTimer(IDT_INPUT, 1000, NULL);
1308 this->m_cFileList.ShowText(_T("Wait For input validate version"));
1311 int CFileDiffDlg::RevertSelectedItemToVersion(CString rev)
1313 if (rev.IsEmpty() || rev == GIT_REV_ZERO)
1314 return 0;
1316 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1317 int index;
1318 int count = 0;
1319 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1321 CString cmd, out;
1322 CTGitPath *fentry = (CTGitPath *)m_arFilteredList[index];
1323 cmd.Format(_T("git.exe checkout %s -- \"%s\""), rev, fentry->GetGitPathString());
1324 if (g_Git.Run(cmd, &out, CP_UTF8))
1326 if (CMessageBox::Show(NULL, out, _T("TortoiseGit"), 2, IDI_WARNING, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON))) == 2)
1327 break;
1329 else
1330 count++;
1333 CString out;
1334 out.Format(IDS_STATUSLIST_FILESREVERTED, count, rev);
1335 CMessageBox::Show(NULL, out, _T("TortoiseGit"), MB_OK);
1336 return 0;
1339 static void AppendMenuChecked(CMenu &menu, UINT nTextID, UINT_PTR nItemID, BOOL checked = FALSE, BOOL enabled = TRUE)
1341 CString text;
1342 text.LoadString(nTextID);
1343 menu.AppendMenu(MF_STRING | (enabled ? MF_ENABLED : MF_DISABLED) | (checked ? MF_CHECKED : MF_UNCHECKED), nItemID, text);
1346 #define DIFFOPTION_IGNORESPACEATEOL 1
1347 #define DIFFOPTION_IGNORESPACECHANGE 2
1348 #define DIFFOPTION_IGNOREALLSPACE 3
1349 #define DIFFOPTION_IGNORBLANKLINES 4
1351 void CFileDiffDlg::OnBnClickedDiffoption()
1353 CMenu popup;
1354 if (popup.CreatePopupMenu())
1356 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORESPACEATEOL, DIFFOPTION_IGNORESPACEATEOL, m_bIgnoreSpaceAtEol);
1357 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORESPACECHANGE, DIFFOPTION_IGNORESPACECHANGE, m_bIgnoreSpaceChange);
1358 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNOREALLSPACE, DIFFOPTION_IGNOREALLSPACE, m_bIgnoreAllSpace);
1359 AppendMenuChecked(popup, IDS_DIFFOPTION_IGNORBLANKLINES, DIFFOPTION_IGNORBLANKLINES, m_bIgnoreBlankLines);
1361 m_tooltips.Pop();
1362 RECT rect;
1363 GetDlgItem(IDC_DIFFOPTION)->GetWindowRect(&rect);
1364 int selection = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, rect.left, rect.bottom, this, 0);
1365 switch (selection)
1367 case DIFFOPTION_IGNORESPACEATEOL:
1368 m_bIgnoreSpaceAtEol = !m_bIgnoreSpaceAtEol;
1369 OnTimer(IDT_INPUT);
1370 break;
1371 case DIFFOPTION_IGNORESPACECHANGE:
1372 m_bIgnoreSpaceChange = !m_bIgnoreSpaceChange;
1373 OnTimer(IDT_INPUT);
1374 break;
1375 case DIFFOPTION_IGNOREALLSPACE:
1376 m_bIgnoreAllSpace = !m_bIgnoreAllSpace;
1377 OnTimer(IDT_INPUT);
1378 break;
1379 case DIFFOPTION_IGNORBLANKLINES:
1380 m_bIgnoreBlankLines = !m_bIgnoreBlankLines;
1381 OnTimer(IDT_INPUT);
1382 break;
1383 default:
1384 break;
1386 UpdateData(FALSE);
1390 void CFileDiffDlg::OnBnClickedLog()
1392 CLogDlg dlg;
1393 dlg.SetRange(m_rev2.m_CommitHash.ToString() + _T("..") + m_rev1.m_CommitHash.ToString());
1394 dlg.DoModal();