1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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.
21 #include "TortoiseProc.h"
22 #include "UnicodeUtils.h"
23 #include "MessageBox.h"
26 #include "SysImageList.h"
28 //#include "GitProperties.h"
29 #include "StringUtils.h"
30 #include "PathUtils.h"
31 #include "BrowseFolder.h"
32 #include ".\filediffdlg.h"
34 #include "LoglistCommonResource.h"
35 #include "LoglistUtils.h"
36 #include "BrowseRefsDlg.h"
38 #include "RefLogDlg.h"
39 #include "GitStatusListCtrl.h"
40 #include "FormatMessageWrapper.h"
46 #define ID_CLIPBOARD_PATH 5
47 #define ID_CLIPBOARD_ALL 6
50 BOOL
CFileDiffDlg::m_bAscending
= FALSE
;
51 int CFileDiffDlg::m_nSortedColumn
= -1;
54 IMPLEMENT_DYNAMIC(CFileDiffDlg
, CResizableStandAloneDialog
)
55 CFileDiffDlg::CFileDiffDlg(CWnd
* pParent
/*=NULL*/)
56 : CResizableStandAloneDialog(CFileDiffDlg::IDD
, pParent
),
64 CFileDiffDlg::~CFileDiffDlg()
68 void CFileDiffDlg::DoDataExchange(CDataExchange
* pDX
)
70 CResizableStandAloneDialog::DoDataExchange(pDX
);
71 DDX_Control(pDX
, IDC_FILELIST
, m_cFileList
);
72 DDX_Control(pDX
, IDC_SWITCHLEFTRIGHT
, m_SwitchButton
);
73 DDX_Control(pDX
, IDC_REV1BTN
, m_cRev1Btn
);
74 DDX_Control(pDX
, IDC_REV2BTN
, m_cRev2Btn
);
75 DDX_Control(pDX
, IDC_FILTER
, m_cFilter
);
76 DDX_Control(pDX
, IDC_REV1EDIT
, m_ctrRev1Edit
);
77 DDX_Control(pDX
, IDC_REV2EDIT
, m_ctrRev2Edit
);
81 BEGIN_MESSAGE_MAP(CFileDiffDlg
, CResizableStandAloneDialog
)
82 ON_NOTIFY(NM_DBLCLK
, IDC_FILELIST
, OnNMDblclkFilelist
)
83 ON_NOTIFY(LVN_GETINFOTIP
, IDC_FILELIST
, OnLvnGetInfoTipFilelist
)
84 ON_NOTIFY(NM_CUSTOMDRAW
, IDC_FILELIST
, OnNMCustomdrawFilelist
)
87 ON_EN_SETFOCUS(IDC_SECONDURL
, &CFileDiffDlg::OnEnSetfocusSecondurl
)
88 ON_EN_SETFOCUS(IDC_FIRSTURL
, &CFileDiffDlg::OnEnSetfocusFirsturl
)
89 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT
, &CFileDiffDlg::OnBnClickedSwitchleftright
)
90 ON_NOTIFY(HDN_ITEMCLICK
, 0, &CFileDiffDlg::OnHdnItemclickFilelist
)
91 ON_BN_CLICKED(IDC_REV1BTN
, &CFileDiffDlg::OnBnClickedRev1btn
)
92 ON_BN_CLICKED(IDC_REV2BTN
, &CFileDiffDlg::OnBnClickedRev2btn
)
93 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED
, OnClickedCancelFilter
)
94 ON_EN_CHANGE(IDC_FILTER
, &CFileDiffDlg::OnEnChangeFilter
)
96 ON_MESSAGE(ENAC_UPDATE
, &CFileDiffDlg::OnEnUpdate
)
97 ON_MESSAGE(MSG_REF_LOADED
, OnRefLoad
)
101 void CFileDiffDlg::SetDiff(CTGitPath
* path
, GitRev rev1
, GitRev rev2
)
107 m_sFilter
= path
->GetGitPathString();
113 void CFileDiffDlg::SetDiff(CTGitPath
* path
, CString
&hash1
, CString
&hash2
)
119 m_sFilter
= path
->GetGitPathString();
124 if(hash1
== GIT_REV_ZERO
)
126 m_rev1
.m_CommitHash
.Empty();
127 m_rev1
.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING
));
131 m_rev1
.GetCommit(hash1
);
136 if(hash2
== GIT_REV_ZERO
)
138 m_rev2
.m_CommitHash
.Empty();
139 m_rev2
.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING
));
143 m_rev2
.GetCommit(hash2
);
147 void CFileDiffDlg::SetDiff(CTGitPath
* path
, GitRev rev1
)
153 m_sFilter
= path
->GetGitPathString();
156 m_rev2
.m_CommitHash
.Empty();
157 m_rev2
.GetSubject() = CString(MAKEINTRESOURCE(IDS_PROC_PREVIOUSVERSION
));
159 //this->GetDlgItem()->EnableWindow(FALSE);
162 BOOL
CFileDiffDlg::OnInitDialog()
164 CResizableStandAloneDialog::OnInitDialog();
167 CString sWindowTitle
;
168 GetWindowText(sWindowTitle
);
169 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
171 this->m_ctrRev1Edit
.Init();
172 this->m_ctrRev2Edit
.Init();
174 m_tooltips
.Create(this);
175 m_tooltips
.AddTool(IDC_SWITCHLEFTRIGHT
, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT
);
177 m_cFileList
.SetRedraw(false);
178 m_cFileList
.DeleteAllItems();
179 DWORD exStyle
= LVS_EX_FULLROWSELECT
| LVS_EX_DOUBLEBUFFER
| LVS_EX_INFOTIP
;
180 m_cFileList
.SetExtendedStyle(exStyle
);
182 m_nIconFolder
= SYS_IMAGE_LIST().GetDirIconIndex();
183 m_cFileList
.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL
);
185 m_SwitchButton
.SetImage((HICON
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
));
186 m_SwitchButton
.Invalidate();
188 m_cFilter
.SetCancelBitmaps(IDI_CANCELNORMAL
, IDI_CANCELPRESSED
);
189 m_cFilter
.SetInfoIcon(IDI_FILTEREDIT
);
190 temp
.LoadString(IDS_FILEDIFF_FILTERCUE
);
192 m_cFilter
.SetCueBanner(temp
);
193 if (!m_sFilter
.IsEmpty())
194 m_cFilter
.SetWindowText(m_sFilter
);
196 int c
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
198 m_cFileList
.DeleteColumn(c
--);
200 temp
.LoadString(IDS_FILEDIFF_FILE
);
201 m_cFileList
.InsertColumn(0, temp
);
202 temp
.LoadString(IDS_FILEDIFF_ACTION
);
203 m_cFileList
.InsertColumn(1, temp
);
205 temp
.LoadString(IDS_FILEDIFF_STATADD
);
206 m_cFileList
.InsertColumn(2, temp
);
207 temp
.LoadString(IDS_FILEDIFF_STATDEL
);
208 m_cFileList
.InsertColumn(3, temp
);
211 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
213 for (col
= mincol
; col
<= maxcol
; col
++)
215 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
218 m_cFileList
.SetRedraw(true);
220 AddAnchor(IDC_DIFFSTATIC1
, TOP_LEFT
, TOP_RIGHT
);
221 AddAnchor(IDC_SWITCHLEFTRIGHT
, TOP_RIGHT
);
222 AddAnchor(IDC_FIRSTURL
, TOP_LEFT
, TOP_RIGHT
);
223 AddAnchor(IDC_REV1BTN
, TOP_RIGHT
);
224 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
225 AddAnchor(IDC_SECONDURL
, TOP_LEFT
, TOP_RIGHT
);
226 AddAnchor(IDC_REV2BTN
, TOP_RIGHT
);
227 AddAnchor(IDC_FILTER
, TOP_LEFT
, TOP_RIGHT
);
228 AddAnchor(IDC_FILELIST
, TOP_LEFT
, BOTTOM_RIGHT
);
229 AddAnchor(IDC_REV1GROUP
,TOP_LEFT
,TOP_RIGHT
);
230 AddAnchor(IDC_REV2GROUP
,TOP_LEFT
,TOP_RIGHT
);
231 AddAnchor(IDC_REV1EDIT
,TOP_LEFT
);
232 AddAnchor(IDC_REV2EDIT
,TOP_LEFT
);
234 EnableSaveRestore(_T("FileDiffDlg"));
236 if(this->m_strRev1
.IsEmpty())
237 this->m_ctrRev1Edit
.SetWindowText(this->m_rev1
.m_CommitHash
.ToString());
240 if(m_rev1
.GetCommit(this->m_strRev1
))
243 msg
.Format(IDS_PROC_REFINVALID
, this->m_strRev1
);
244 this->m_FileListText
+= msg
;
247 this->m_ctrRev1Edit
.SetWindowText(m_strRev1
);
250 if(this->m_strRev2
.IsEmpty())
251 this->m_ctrRev2Edit
.SetWindowText(this->m_rev2
.m_CommitHash
.ToString());
254 if(m_rev2
.GetCommit(this->m_strRev2
))
257 msg
.Format(IDS_PROC_REFINVALID
, this->m_strRev2
);
258 this->m_FileListText
+= msg
;
261 this->m_ctrRev2Edit
.SetWindowText(m_strRev2
);
266 InterlockedExchange(&m_bThreadRunning
, TRUE
);
267 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
269 InterlockedExchange(&m_bThreadRunning
, FALSE
);
270 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
273 InterlockedExchange(&m_bLoadingRef
, TRUE
);
274 if (AfxBeginThread(LoadRefThreadEntry
, this)==NULL
)
276 InterlockedExchange(&m_bLoadingRef
, FALSE
);
277 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
280 this->m_cRev1Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE
)));
281 this->m_cRev1Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG
)));
282 this->m_cRev1Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG
)));
284 this->m_cRev2Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_REFBROWSE
)));
285 this->m_cRev2Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_LOG
)));
286 this->m_cRev2Btn
.AddEntry(CString(MAKEINTRESOURCE(IDS_REFLOG
)));
288 // Start with focus on file list
289 GetDlgItem(IDC_FILELIST
)->SetFocus();
291 if(m_rev2
.m_CommitHash
.IsEmpty())
292 m_SwitchButton
.EnableWindow(FALSE
);
294 KillTimer(IDT_INPUT
);
299 svn_error_t
* CFileDiffDlg::DiffSummarizeCallback(const CTGitPath
& path
,
300 svn_client_diff_summarize_kind_t kind
,
301 bool propchanged
, svn_node_kind_t node
)
307 fd
.propchanged
= propchanged
;
308 m_arFileList
.push_back(fd
);
313 UINT
CFileDiffDlg::DiffThreadEntry(LPVOID pVoid
)
315 return ((CFileDiffDlg
*)pVoid
)->DiffThread();
318 UINT
CFileDiffDlg::DiffThread()
321 m_cFileList
.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT
)));
322 m_cFileList
.DeleteAllItems();
323 m_arFileList
.Clear();
324 EnableInputControl(false);
326 bool bSuccess
= true;
329 // bSuccess = DiffSummarizePeg(m_path1, m_peg, m_rev1, m_rev2, m_depth, m_bIgnoreancestry);
333 // bSuccess = DiffSummarize(m_path1, m_rev1, m_path2, m_rev2, m_depth, m_bIgnoreancestry);
337 // m_cFileList.ShowText(GetLastErrorMessage());
338 // InterlockedExchange(&m_bThreadRunning, FALSE);
343 if( m_rev1
.m_CommitHash
.IsEmpty() || m_rev2
.m_CommitHash
.IsEmpty())
344 g_Git
.RefreshGitIndex();
346 g_Git
.GetCommitDiffList(m_rev1
.m_CommitHash
.ToString(),m_rev2
.m_CommitHash
.ToString(),m_arFileList
);
349 m_cFilter
.GetWindowText(sFilterText
);
350 m_cFileList
.SetRedraw(false);
352 if (m_arFileList
.GetCount()>0)
354 // Highlight first entry in file list
355 m_cFileList
.SetSelectionMark(0);
356 m_cFileList
.SetItemState(0, LVIS_SELECTED
, LVIS_SELECTED
);
360 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
362 for (col
= mincol
; col
<= maxcol
; col
++)
364 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
367 m_cFileList
.ClearText();
368 m_cFileList
.SetRedraw(true);
370 InterlockedExchange(&m_bThreadRunning
, FALSE
);
371 InvalidateRect(NULL
);
373 EnableInputControl(true);
377 int CFileDiffDlg::AddEntry(const CTGitPath
* fd
)
382 int index
= m_cFileList
.GetItemCount();
385 // if (fd->node == svn_node_dir)
386 // icon_idx = m_nIconFolder;
389 icon_idx
= SYS_IMAGE_LIST().GetPathIconIndex(fd
->GetGitPathString());
392 ret
= m_cFileList
.InsertItem(index
, fd
->GetGitPathString(), icon_idx
);
393 m_cFileList
.SetItemText(index
, 1, ((CTGitPath
*)fd
)->GetActionName());
394 m_cFileList
.SetItemText(index
, 2, ((CTGitPath
*)fd
)->m_StatAdd
);
395 m_cFileList
.SetItemText(index
, 3, ((CTGitPath
*)fd
)->m_StatDel
);
400 void CFileDiffDlg::EnableInputControl(bool b
)
402 this->m_ctrRev1Edit
.EnableWindow(b
);
403 this->m_ctrRev2Edit
.EnableWindow(b
);
404 this->m_cRev1Btn
.EnableWindow(b
);
405 this->m_cRev2Btn
.EnableWindow(b
);
406 m_cFilter
.EnableWindow(b
);
407 m_SwitchButton
.EnableWindow(b
);
410 void CFileDiffDlg::DoDiff(int selIndex
, bool blame
)
413 CTGitPath
* fd
= m_arFilteredList
[selIndex
];
414 diff
.Diff(fd
, fd
,this->m_rev1
.m_CommitHash
.ToString(), this->m_rev2
.m_CommitHash
.ToString(), blame
, FALSE
);
418 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
421 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
422 int selIndex
= pNMLV
->iItem
;
425 if (selIndex
>= (int)m_arFilteredList
.size())
428 DoDiff(selIndex
, m_bBlame
);
431 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
434 LPNMLVGETINFOTIP pGetInfoTip
= reinterpret_cast<LPNMLVGETINFOTIP
>(pNMHDR
);
435 if (pGetInfoTip
->iItem
>= (int)m_arFilteredList
.size())
438 CString path
= m_path1
.GetGitPathString() + _T("/") + m_arFilteredList
[pGetInfoTip
->iItem
]->GetGitPathString();
439 if (pGetInfoTip
->cchTextMax
> path
.GetLength())
440 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, path
, pGetInfoTip
->cchTextMax
);
445 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
447 NMLVCUSTOMDRAW
* pLVCD
= reinterpret_cast<NMLVCUSTOMDRAW
*>( pNMHDR
);
448 // Take the default processing unless we set this to something else below.
449 *pResult
= CDRF_DODEFAULT
;
451 // First thing - check the draw stage. If it's the control's prepaint
452 // stage, then tell Windows we want messages for every item.
454 if ( CDDS_PREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
456 *pResult
= CDRF_NOTIFYITEMDRAW
;
458 else if ( CDDS_ITEMPREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
460 // This is the prepaint stage for an item. Here's where we set the
461 // item's text color. Our return value will tell Windows to draw the
462 // item itself, but it will use the new color we set here.
464 // Tell Windows to paint the control itself.
465 *pResult
= CDRF_DODEFAULT
;
467 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
469 if (m_arFilteredList
.size() > pLVCD
->nmcd
.dwItemSpec
)
471 CTGitPath
* fd
= m_arFilteredList
[pLVCD
->nmcd
.dwItemSpec
];
472 switch (fd
->m_Action
)
474 case CTGitPath::LOGACTIONS_ADDED
:
475 crText
= m_colors
.GetColor(CColors::Added
);
477 case CTGitPath::LOGACTIONS_DELETED
:
478 crText
= m_colors
.GetColor(CColors::Deleted
);
480 case CTGitPath::LOGACTIONS_MODIFIED
:
481 crText
= m_colors
.GetColor(CColors::Modified
);
483 //case svn_client_diff_summarize_kind_normal:
485 //if (fd.propchanged)
486 crText
= m_colors
.GetColor(CColors::PropertyChanged
);
490 // Store the color back in the NMLVCUSTOMDRAW struct.
491 pLVCD
->clrText
= crText
;
495 UINT
CFileDiffDlg::LoadRefThread()
497 g_Git
.GetBranchList(m_Reflist
,NULL
,CGit::BRANCH_ALL_F
);
498 g_Git
.GetTagList(m_Reflist
);
500 this->PostMessage(MSG_REF_LOADED
);
501 InterlockedExchange(&m_bLoadingRef
, FALSE
);
505 void CFileDiffDlg::OnContextMenu(CWnd
* pWnd
, CPoint point
)
507 if ((pWnd
==0)||(pWnd
!= &m_cFileList
))
509 if (m_cFileList
.GetSelectedCount() == 0)
511 // if the context menu is invoked through the keyboard, we have to use
512 // a calculated position on where to anchor the menu on
513 if ((point
.x
== -1) && (point
.y
== -1))
516 m_cFileList
.GetItemRect(m_cFileList
.GetSelectionMark(), &rect
, LVIR_LABEL
);
517 m_cFileList
.ClientToScreen(&rect
);
518 point
= rect
.CenterPoint();
521 if (popup
.CreatePopupMenu())
523 popup
.AppendMenuIcon(ID_COMPARE
, IDS_LOG_POPUP_COMPARETWO
, IDI_DIFF
);
524 popup
.AppendMenuIcon(ID_BLAME
, IDS_FILEDIFF_POPBLAME
, IDI_BLAME
);
525 popup
.AppendMenuIcon(ID_LOG
, IDS_FILEDIFF_LOG
, IDI_LOG
);
526 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
527 popup
.AppendMenuIcon(ID_EXPORT
, IDS_FILEDIFF_POPEXPORT
, IDI_EXPORT
);
528 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
529 popup
.AppendMenuIcon(ID_SAVEAS
, IDS_FILEDIFF_POPSAVELIST
, IDI_SAVEAS
);
530 popup
.AppendMenuIcon(ID_CLIPBOARD_PATH
, IDS_STATUSLIST_CONTEXT_COPY
, IDI_COPYCLIP
);
531 popup
.AppendMenuIcon(ID_CLIPBOARD_ALL
, IDS_STATUSLIST_CONTEXT_COPYEXT
, IDI_COPYCLIP
);
533 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, point
.x
, point
.y
, this, 0);
534 m_bCancelled
= false;
539 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
542 int index
= m_cFileList
.GetNextSelectedItem(pos
);
543 DoDiff(index
, false);
549 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
552 int index
= m_cFileList
.GetNextSelectedItem(pos
);
553 CAppUtils::LaunchTortoiseBlame(m_arFilteredList
[index
]->GetWinPathString(), m_rev1
.m_CommitHash
.ToString());
559 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
562 int index
= m_cFileList
.GetNextSelectedItem(pos
);
563 CString cmd
= _T("/command:log");
564 cmd
+= _T(" /path:\"")+m_arFilteredList
[index
]->GetWinPathString()+_T("\" ");
565 cmd
+= _T(" /endrev:")+m_rev1
.m_CommitHash
.ToString();
566 CAppUtils::RunTortoiseProc(cmd
);
572 if (m_cFileList
.GetSelectedCount() > 0)
577 if (!CAppUtils::FileOpenSave(pathSave
, NULL
, IDS_REPOBROWSE_SAVEAS
, IDS_COMMONFILEFILTER
, false, m_hWnd
))
581 savePath
= CTGitPath(pathSave
);
583 // now open the selected file for writing
586 CStdioFile
file(savePath
.GetWinPathString(), CFile::typeBinary
| CFile::modeReadWrite
| CFile::modeCreate
);
587 // temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, (LPCTSTR)m_path1.GetGitPathString(), (LPCTSTR)m_rev1.ToString(), (LPCTSTR)m_path2.GetGitPathString(), (LPCTSTR)m_rev2.ToString());
588 file
.WriteString(temp
+ _T("\n"));
589 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
592 int index
= m_cFileList
.GetNextSelectedItem(pos
);
593 CTGitPath
* fd
= m_arFilteredList
[index
];
594 file
.WriteString(fd
->GetGitPathString());
595 file
.WriteString(_T("\n"));
599 catch (CFileException
* pE
)
606 case ID_CLIPBOARD_PATH
:
608 CopySelectionToClipboard();
612 case ID_CLIPBOARD_ALL
:
614 CopySelectionToClipboard(TRUE
);
619 // export all changed files to a folder
620 CBrowseFolder browseFolder
;
621 browseFolder
.m_style
= BIF_EDITBOX
| BIF_NEWDIALOGSTYLE
| BIF_RETURNFSANCESTORS
| BIF_RETURNONLYFSDIRS
;
622 if (browseFolder
.Show(GetSafeHwnd(), m_strExportDir
) == CBrowseFolder::OK
)
624 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
627 int index
= m_cFileList
.GetNextSelectedItem(pos
);
628 CTGitPath
* fd
= m_arFilteredList
[index
];
629 // we cannot export directories or folders
630 if (fd
->m_Action
== CTGitPath::LOGACTIONS_DELETED
|| fd
->IsDirectory())
632 CAppUtils::CreateMultipleDirectory(m_strExportDir
+ _T("\\") + fd
->GetDirectory().GetWinPathString());
633 CString filename
= m_strExportDir
+ _T("\\") + fd
->GetWinPathString();
634 if(m_rev1
.m_CommitHash
.ToString() == GIT_REV_ZERO
)
636 if(!CopyFile(g_Git
.m_CurrentDir
+ _T("\\") + fd
->GetWinPath(), filename
, false))
638 MessageBox(CFormatMessageWrapper(), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
644 if(g_Git
.GetOneFile(m_rev1
.m_CommitHash
, *fd
, filename
))
647 out
.Format(IDS_STATUSLIST_CHECKOUTFILEFAILED
, fd
->GetGitPathString(), m_rev1
.m_CommitHash
.ToString(), filename
);
648 if (CMessageBox::Show(NULL
, out
, _T("TortoiseGit"), 2, IDI_WARNING
, CString(MAKEINTRESOURCE(IDS_IGNOREBUTTON
)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON
))) == 2)
662 BOOL
CFileDiffDlg::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
664 if (pWnd
!= &m_cFileList
)
665 return CResizableStandAloneDialog::OnSetCursor(pWnd
, nHitTest
, message
);
666 if (m_bThreadRunning
== 0)
668 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_ARROW
));
670 return CResizableStandAloneDialog::OnSetCursor(pWnd
, nHitTest
, message
);
672 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_WAIT
));
677 void CFileDiffDlg::OnEnSetfocusFirsturl()
679 GetDlgItem(IDC_FIRSTURL
)->HideCaret();
682 void CFileDiffDlg::OnEnSetfocusSecondurl()
684 GetDlgItem(IDC_SECONDURL
)->HideCaret();
688 void CFileDiffDlg::OnBnClickedSwitchleftright()
691 if (m_bThreadRunning
)
695 CString sFilterString
;
696 m_cFilter
.GetWindowText(sFilterString
);
698 m_cFileList
.SetRedraw(false);
699 m_cFileList
.DeleteAllItems();
700 for (int i
=0; i
<(int)m_arFileList
.GetCount(); ++i
)
702 CTGitPath fd
= m_arFileList
[i
];
703 if (fd
.m_Action
== CTGitPath::LOGACTIONS_ADDED
)
704 fd
.m_Action
= CTGitPath::LOGACTIONS_DELETED
;
705 else if (fd
.m_Action
== CTGitPath::LOGACTIONS_DELETED
)
706 fd
.m_Action
= CTGitPath::LOGACTIONS_ADDED
;
707 std::swap(fd
.m_StatAdd
, fd
.m_StatDel
);
708 (CTGitPath
&)m_arFileList
[i
] = fd
;
710 Filter(sFilterString
);
713 m_cFileList
.SetRedraw(true);
714 CTGitPath path
= m_path1
;
722 this->m_ctrRev1Edit
.GetWindowText(str1
);
723 this->m_ctrRev2Edit
.GetWindowText(str2
);
725 this->m_ctrRev1Edit
.SetWindowText(str2
);
726 this->m_ctrRev2Edit
.SetWindowText(str1
);
729 //KillTimer(IDT_INPUT);
732 void CFileDiffDlg::SetURLLabels(int mask
)
735 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
736 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
740 SetDlgItemText(IDC_FIRSTURL
, m_rev1
.m_CommitHash
.ToString().Left(8)+_T(": ")+m_rev1
.GetSubject());
741 m_tooltips
.AddTool(IDC_FIRSTURL
,
742 CLoglistUtils::FormatDateAndTime(m_rev1
.GetAuthorDate(), DATE_SHORTDATE
, false) + _T(" ") + m_rev1
.GetAuthorName());
748 SetDlgItemText(IDC_SECONDURL
,m_rev2
.m_CommitHash
.ToString().Left(8)+_T(": ")+m_rev2
.GetSubject());
750 m_tooltips
.AddTool(IDC_SECONDURL
,
751 CLoglistUtils::FormatDateAndTime(m_rev2
.GetAuthorDate(), DATE_SHORTDATE
, false) + _T(" ") + m_rev2
.GetAuthorName());
754 this->GetDlgItem(IDC_REV2GROUP
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASE
)));
755 this->GetDlgItem(IDC_REV1GROUP
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1
)));
757 if( (mask
&0x3) == 0x3)
758 if(m_rev2
.GetCommitterDate() > m_rev1
.GetCommitterDate())
760 this->GetDlgItem(IDC_REV2GROUP
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION2BASENEWER
)));
764 this->GetDlgItem(IDC_REV1GROUP
)->SetWindowText(CString(MAKEINTRESOURCE(IDS_PROC_FILEDIFF_VERSION1NEWER
)));
768 void CFileDiffDlg::ClearURLabels(int mask
)
772 SetDlgItemText(IDC_FIRSTURL
, _T(""));
773 m_tooltips
.AddTool(IDC_FIRSTURL
, _T(""));
778 SetDlgItemText(IDC_SECONDURL
, _T(""));
779 m_tooltips
.AddTool(IDC_SECONDURL
, _T(""));
782 BOOL
CFileDiffDlg::PreTranslateMessage(MSG
* pMsg
)
784 m_tooltips
.RelayEvent(pMsg
);
785 if (pMsg
->message
== WM_KEYDOWN
)
787 switch (pMsg
->wParam
)
791 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
793 // select all entries
794 for (int i
=0; i
<m_cFileList
.GetItemCount(); ++i
)
796 m_cFileList
.SetItemState(i
, LVIS_SELECTED
, LVIS_SELECTED
);
805 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
807 CopySelectionToClipboard();
814 if (GetFocus() == GetDlgItem(IDC_FILELIST
))
816 // Return pressed in file list. Show diff, as for double click
817 int selIndex
= m_cFileList
.GetSelectionMark();
818 if ((selIndex
>= 0) && (selIndex
< (int)m_arFileList
.GetCount()))
819 DoDiff(selIndex
, m_bBlame
);
826 return __super::PreTranslateMessage(pMsg
);
829 void CFileDiffDlg::OnCancel()
831 if (m_bThreadRunning
)
839 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
841 LPNMHEADER phdr
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
842 if (m_bThreadRunning
)
845 if (m_nSortedColumn
== phdr
->iItem
)
846 m_bAscending
= !m_bAscending
;
849 m_nSortedColumn
= phdr
->iItem
;
853 m_cFileList
.SetRedraw(FALSE
);
854 m_cFileList
.DeleteAllItems();
855 m_cFilter
.GetWindowText(temp
);
858 CHeaderCtrl
* pHeader
= m_cFileList
.GetHeaderCtrl();
859 HDITEM HeaderItem
= {0};
860 HeaderItem
.mask
= HDI_FORMAT
;
861 for (int i
=0; i
<pHeader
->GetItemCount(); ++i
)
863 pHeader
->GetItem(i
, &HeaderItem
);
864 HeaderItem
.fmt
&= ~(HDF_SORTDOWN
| HDF_SORTUP
);
865 pHeader
->SetItem(i
, &HeaderItem
);
867 pHeader
->GetItem(m_nSortedColumn
, &HeaderItem
);
868 HeaderItem
.fmt
|= (m_bAscending
? HDF_SORTUP
: HDF_SORTDOWN
);
869 pHeader
->SetItem(m_nSortedColumn
, &HeaderItem
);
871 m_cFileList
.SetRedraw(TRUE
);
876 void CFileDiffDlg::Sort()
878 if(m_arFileList
.GetCount() < 2)
883 std::sort(m_arFileList
.m_paths
.begin(), m_arFileList
.m_paths
.end(), &CFileDiffDlg::SortCompare
);
886 bool CFileDiffDlg::SortCompare(const CTGitPath
& Data1
, const CTGitPath
& Data2
)
890 switch (m_nSortedColumn
)
892 case 0: //path column
893 result
= Data1
.GetWinPathString().Compare(Data2
.GetWinPathString());
895 case 1: //action column
896 result
= Data1
.m_Action
- Data2
.m_Action
;
899 d1
= CSorter::A2L(Data1
.m_StatAdd
);
900 d2
= CSorter::A2L(Data2
.m_StatAdd
);
904 d1
= CSorter::A2L(Data1
.m_StatDel
);;
905 d2
= CSorter::A2L(Data2
.m_StatDel
);
918 void CFileDiffDlg::OnBnClickedRev1btn()
920 ClickRevButton(&this->m_cRev1Btn
,&this->m_rev1
, &this->m_ctrRev1Edit
);
923 void CFileDiffDlg::ClickRevButton(CMenuButton
*button
, GitRev
*rev
, CACEdit
*edit
)
925 int entry
=button
->GetCurrentEntry();
926 if(entry
== 0) /* Browse Refence*/
929 CString str
= CBrowseRefsDlg::PickRef();
933 if(FillRevFromString(rev
,str
))
936 edit
->SetWindowText(str
);
940 if(entry
== 1) /*Log*/
944 if(dlg
.DoModal() == IDOK
)
946 if( dlg
.GetSelectedHash().IsEmpty() )
949 if(FillRevFromString(rev
,dlg
.GetSelectedHash()))
952 edit
->SetWindowText(dlg
.GetSelectedHash());
959 if(entry
== 2) /*RefLog*/
962 if(dlg
.DoModal() == IDOK
)
964 if(FillRevFromString(rev
,dlg
.m_SelectedHash
))
967 edit
->SetWindowText(dlg
.m_SelectedHash
);
976 InterlockedExchange(&m_bThreadRunning
, TRUE
);
977 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
979 InterlockedExchange(&m_bThreadRunning
, FALSE
);
980 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
982 KillTimer(IDT_INPUT
);
985 void CFileDiffDlg::OnBnClickedRev2btn()
987 ClickRevButton(&this->m_cRev2Btn
,&this->m_rev2
, &this->m_ctrRev2Edit
);
990 LRESULT
CFileDiffDlg::OnClickedCancelFilter(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
992 if (m_bThreadRunning
)
994 SetTimer(IDT_FILTER
, 1000, NULL
);
998 KillTimer(IDT_FILTER
);
1000 m_cFileList
.SetRedraw(FALSE
);
1001 m_arFilteredList
.clear();
1002 m_cFileList
.DeleteAllItems();
1006 m_cFileList
.SetRedraw(TRUE
);
1010 void CFileDiffDlg::OnEnChangeFilter()
1012 SetTimer(IDT_FILTER
, 1000, NULL
);
1015 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent
)
1017 if (m_bThreadRunning
)
1020 if( nIDEvent
== IDT_FILTER
)
1022 CString sFilterText
;
1023 KillTimer(IDT_FILTER
);
1024 m_cFilter
.GetWindowText(sFilterText
);
1026 m_cFileList
.SetRedraw(FALSE
);
1027 m_cFileList
.DeleteAllItems();
1029 Filter(sFilterText
);
1031 m_cFileList
.SetRedraw(TRUE
);
1033 __super::OnTimer(nIDEvent
);
1036 if( nIDEvent
== IDT_INPUT
)
1038 KillTimer(IDT_INPUT
);
1039 TRACE(_T("Input Timer\r\n"));
1044 this->m_ctrRev1Edit
.GetWindowText(str
);
1045 if( !gitrev
.GetCommit(str
) )
1047 this->m_rev1
=gitrev
;
1051 this->m_ctrRev2Edit
.GetWindowText(str
);
1053 if( !gitrev
.GetCommit(str
) )
1055 this->m_rev2
=gitrev
;
1059 this->SetURLLabels(mask
);
1064 InterlockedExchange(&m_bThreadRunning
, TRUE
);
1065 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
1067 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1068 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1074 void CFileDiffDlg::Filter(CString sFilterText
)
1076 sFilterText
.MakeLower();
1078 m_arFilteredList
.clear();
1080 for (int i
=0;i
<m_arFileList
.GetCount();i
++)
1082 CString sPath
= m_arFileList
[i
].GetGitPathString();
1084 if (sPath
.Find(sFilterText
) >= 0)
1086 m_arFilteredList
.push_back((CTGitPath
*)&(m_arFileList
[i
]));
1089 for (std::vector
<CTGitPath
*>::const_iterator it
= m_arFilteredList
.begin(); it
!= m_arFilteredList
.end(); ++it
)
1095 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull
)
1097 // copy all selected paths to the clipboard
1098 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
1100 CString sTextForClipboard
;
1101 while ((index
= m_cFileList
.GetNextSelectedItem(pos
)) >= 0)
1103 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 0);
1104 sTextForClipboard
+= _T("\t");
1108 sTextForClipboard
+= _T("\r\n");
1113 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 1);
1114 sTextForClipboard
+= _T("\t");
1115 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 2);
1116 sTextForClipboard
+= _T("\t");
1117 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 3);
1118 sTextForClipboard
+= _T("\r\n");
1121 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard
);
1125 LRESULT
CFileDiffDlg::OnRefLoad(WPARAM wParam
, LPARAM lParam
)
1127 UNREFERENCED_PARAMETER(wParam
);
1128 UNREFERENCED_PARAMETER(lParam
);
1129 for(int i
=0;i
<m_Reflist
.size();i
++)
1131 CString str
=m_Reflist
[i
];
1133 if(str
.Find(_T("remotes/")) == 0)
1136 m_ctrRev1Edit
.AddSearchString(str
);
1137 m_ctrRev2Edit
.AddSearchString(str
);
1142 BOOL
CFileDiffDlg::DestroyWindow()
1144 return CResizableStandAloneDialog::DestroyWindow();
1147 LRESULT
CFileDiffDlg::OnEnUpdate(WPARAM
/*wParam*/, LPARAM lParam
)
1149 if(lParam
== IDC_REV1EDIT
)
1151 OnTextUpdate(&this->m_ctrRev1Edit
);
1154 if(lParam
== IDC_REV2EDIT
)
1156 OnTextUpdate(&this->m_ctrRev2Edit
);
1157 ClearURLabels(1<<1);
1162 void CFileDiffDlg::OnTextUpdate(CACEdit
* /*pEdit*/)
1164 SetTimer(IDT_INPUT
, 1000, NULL
);
1165 this->m_cFileList
.ShowText(_T("Wait For input validate version"));