1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - 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 "ProgressDlg.h"
27 #include "SysImageList.h"
29 //#include "GitProperties.h"
30 #include "StringUtils.h"
31 #include "PathUtils.h"
32 #include "BrowseFolder.h"
33 #include "RevisionDlg.h"
34 #include ".\filediffdlg.h"
36 #include "CommonResource.h"
37 #include "BrowseRefsDlg.h"
39 #include "RefLogDlg.h"
40 #include "GitStatusListCtrl.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()
66 DestroyIcon(m_hSwitchIcon
);
69 void CFileDiffDlg::DoDataExchange(CDataExchange
* pDX
)
71 CResizableStandAloneDialog::DoDataExchange(pDX
);
72 DDX_Control(pDX
, IDC_FILELIST
, m_cFileList
);
73 DDX_Control(pDX
, IDC_SWITCHLEFTRIGHT
, m_SwitchButton
);
74 DDX_Control(pDX
, IDC_REV1BTN
, m_cRev1Btn
);
75 DDX_Control(pDX
, IDC_REV2BTN
, m_cRev2Btn
);
76 DDX_Control(pDX
, IDC_FILTER
, m_cFilter
);
77 DDX_Control(pDX
, IDC_REV1EDIT
, m_ctrRev1Edit
);
78 DDX_Control(pDX
, IDC_REV2EDIT
, m_ctrRev2Edit
);
82 BEGIN_MESSAGE_MAP(CFileDiffDlg
, CResizableStandAloneDialog
)
83 ON_NOTIFY(NM_DBLCLK
, IDC_FILELIST
, OnNMDblclkFilelist
)
84 ON_NOTIFY(LVN_GETINFOTIP
, IDC_FILELIST
, OnLvnGetInfoTipFilelist
)
85 ON_NOTIFY(NM_CUSTOMDRAW
, IDC_FILELIST
, OnNMCustomdrawFilelist
)
88 ON_EN_SETFOCUS(IDC_SECONDURL
, &CFileDiffDlg::OnEnSetfocusSecondurl
)
89 ON_EN_SETFOCUS(IDC_FIRSTURL
, &CFileDiffDlg::OnEnSetfocusFirsturl
)
90 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT
, &CFileDiffDlg::OnBnClickedSwitchleftright
)
91 ON_NOTIFY(HDN_ITEMCLICK
, 0, &CFileDiffDlg::OnHdnItemclickFilelist
)
92 ON_BN_CLICKED(IDC_REV1BTN
, &CFileDiffDlg::OnBnClickedRev1btn
)
93 ON_BN_CLICKED(IDC_REV2BTN
, &CFileDiffDlg::OnBnClickedRev2btn
)
94 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED
, OnClickedCancelFilter
)
95 ON_EN_CHANGE(IDC_FILTER
, &CFileDiffDlg::OnEnChangeFilter
)
97 ON_MESSAGE(ENAC_UPDATE
, &CFileDiffDlg::OnEnUpdate
)
98 ON_MESSAGE(MSG_REF_LOADED
, OnRefLoad
)
102 void CFileDiffDlg::SetDiff(CTGitPath
* path
, GitRev rev1
, GitRev rev2
)
113 void CFileDiffDlg::SetDiff(CTGitPath
* path
, CString
&hash1
, CString
&hash2
)
123 if(hash1
== GIT_REV_ZERO
)
125 m_rev1
.m_CommitHash
.Empty();
126 m_rev1
.GetSubject()=_T("Working Copy");
130 m_rev1
.GetCommit(hash1
);
135 if(hash2
== GIT_REV_ZERO
)
137 m_rev2
.m_CommitHash
.Empty();
138 m_rev2
.GetSubject()=_T("Working Copy");
142 m_rev2
.GetCommit(hash2
);
146 void CFileDiffDlg::SetDiff(CTGitPath
* path
, GitRev rev1
)
154 m_rev2
.m_CommitHash
.Empty();
155 m_rev2
.GetSubject() = _T("Previous Version");
157 //this->GetDlgItem()->EnableWindow(FALSE);
160 BOOL
CFileDiffDlg::OnInitDialog()
162 CResizableStandAloneDialog::OnInitDialog();
165 this->m_ctrRev1Edit
.Init();
166 this->m_ctrRev2Edit
.Init();
168 m_tooltips
.Create(this);
169 m_tooltips
.AddTool(IDC_SWITCHLEFTRIGHT
, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT
);
171 m_cFileList
.SetRedraw(false);
172 m_cFileList
.DeleteAllItems();
173 DWORD exStyle
= LVS_EX_FULLROWSELECT
| LVS_EX_DOUBLEBUFFER
| LVS_EX_INFOTIP
;
174 m_cFileList
.SetExtendedStyle(exStyle
);
176 m_nIconFolder
= SYS_IMAGE_LIST().GetDirIconIndex();
177 m_cFileList
.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL
);
179 m_hSwitchIcon
= (HICON
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
180 m_SwitchButton
.SetIcon(m_hSwitchIcon
);
182 m_cFilter
.SetCancelBitmaps(IDI_CANCELNORMAL
, IDI_CANCELPRESSED
);
183 m_cFilter
.SetInfoIcon(IDI_FILTEREDIT
);
184 temp
.LoadString(IDS_FILEDIFF_FILTERCUE
);
186 m_cFilter
.SetCueBanner(temp
);
188 int c
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
190 m_cFileList
.DeleteColumn(c
--);
192 temp
.LoadString(IDS_FILEDIFF_FILE
);
193 m_cFileList
.InsertColumn(0, temp
);
194 temp
.LoadString(IDS_FILEDIFF_ACTION
);
195 m_cFileList
.InsertColumn(1, temp
);
197 temp
.LoadString(IDS_FILEDIFF_STATADD
);
198 m_cFileList
.InsertColumn(2, temp
);
199 temp
.LoadString(IDS_FILEDIFF_STATDEL
);
200 m_cFileList
.InsertColumn(3, temp
);
203 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
205 for (col
= mincol
; col
<= maxcol
; col
++)
207 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
210 m_cFileList
.SetRedraw(true);
212 AddAnchor(IDC_DIFFSTATIC1
, TOP_LEFT
, TOP_RIGHT
);
213 AddAnchor(IDC_SWITCHLEFTRIGHT
, TOP_RIGHT
);
214 AddAnchor(IDC_FIRSTURL
, TOP_LEFT
, TOP_RIGHT
);
215 AddAnchor(IDC_REV1BTN
, TOP_RIGHT
);
216 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
217 AddAnchor(IDC_SECONDURL
, TOP_LEFT
, TOP_RIGHT
);
218 AddAnchor(IDC_REV2BTN
, TOP_RIGHT
);
219 AddAnchor(IDC_FILTER
, TOP_LEFT
, TOP_RIGHT
);
220 AddAnchor(IDC_FILELIST
, TOP_LEFT
, BOTTOM_RIGHT
);
221 AddAnchor(IDC_REV1GROUP
,TOP_LEFT
,TOP_RIGHT
);
222 AddAnchor(IDC_REV2GROUP
,TOP_LEFT
,TOP_RIGHT
);
223 AddAnchor(IDC_REV1EDIT
,TOP_LEFT
);
224 AddAnchor(IDC_REV2EDIT
,TOP_LEFT
);
226 EnableSaveRestore(_T("FileDiffDlg"));
228 if(this->m_strRev1
.IsEmpty())
229 this->m_ctrRev1Edit
.SetWindowText(this->m_rev1
.m_CommitHash
.ToString());
232 if(m_rev1
.GetCommit(this->m_strRev1
))
233 this->m_FileListText
+=this->m_strRev1
+ _T(" is wrong");
235 this->m_ctrRev1Edit
.SetWindowText(m_strRev1
);
238 if(this->m_strRev2
.IsEmpty())
239 this->m_ctrRev2Edit
.SetWindowText(this->m_rev2
.m_CommitHash
.ToString());
242 if(m_rev2
.GetCommit(this->m_strRev2
))
243 this->m_FileListText
+=this->m_strRev2
+ _T(" is wrong");
245 this->m_ctrRev2Edit
.SetWindowText(m_strRev2
);
250 InterlockedExchange(&m_bThreadRunning
, TRUE
);
251 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
253 InterlockedExchange(&m_bThreadRunning
, FALSE
);
254 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
257 InterlockedExchange(&m_bLoadingRef
, TRUE
);
258 if (AfxBeginThread(LoadRefThreadEntry
, this)==NULL
)
260 InterlockedExchange(&m_bLoadingRef
, FALSE
);
261 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
264 this->m_cRev1Btn
.AddEntry(_T("RefBrowse"));
265 this->m_cRev1Btn
.AddEntry(_T("Log"));
266 this->m_cRev1Btn
.AddEntry(_T("RefLog"));
268 this->m_cRev2Btn
.AddEntry(_T("RefBrowse"));
269 this->m_cRev2Btn
.AddEntry(_T("Log"));
270 this->m_cRev2Btn
.AddEntry(_T("RefLog"));
272 // Start with focus on file list
273 GetDlgItem(IDC_FILELIST
)->SetFocus();
275 if(m_rev2
.m_CommitHash
.IsEmpty())
276 m_SwitchButton
.EnableWindow(FALSE
);
278 KillTimer(IDT_INPUT
);
283 svn_error_t
* CFileDiffDlg::DiffSummarizeCallback(const CTGitPath
& path
,
284 svn_client_diff_summarize_kind_t kind
,
285 bool propchanged
, svn_node_kind_t node
)
291 fd
.propchanged
= propchanged
;
292 m_arFileList
.push_back(fd
);
297 UINT
CFileDiffDlg::DiffThreadEntry(LPVOID pVoid
)
299 return ((CFileDiffDlg
*)pVoid
)->DiffThread();
302 UINT
CFileDiffDlg::DiffThread()
305 m_cFileList
.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT
)));
306 m_cFileList
.DeleteAllItems();
307 m_arFileList
.Clear();
308 EnableInputControl(false);
310 bool bSuccess
= true;
313 // bSuccess = DiffSummarizePeg(m_path1, m_peg, m_rev1, m_rev2, m_depth, m_bIgnoreancestry);
317 // bSuccess = DiffSummarize(m_path1, m_rev1, m_path2, m_rev2, m_depth, m_bIgnoreancestry);
321 // m_cFileList.ShowText(GetLastErrorMessage());
322 // InterlockedExchange(&m_bThreadRunning, FALSE);
327 if( m_rev1
.m_CommitHash
.IsEmpty() || m_rev2
.m_CommitHash
.IsEmpty())
328 g_Git
.RefreshGitIndex();
330 g_Git
.GetCommitDiffList(m_rev1
.m_CommitHash
.ToString(),m_rev2
.m_CommitHash
.ToString(),m_arFileList
);
333 m_cFilter
.GetWindowText(sFilterText
);
334 m_cFileList
.SetRedraw(false);
336 if (m_arFileList
.GetCount()>0)
338 // Highlight first entry in file list
339 m_cFileList
.SetSelectionMark(0);
340 m_cFileList
.SetItemState(0, LVIS_SELECTED
, LVIS_SELECTED
);
344 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
346 for (col
= mincol
; col
<= maxcol
; col
++)
348 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
351 m_cFileList
.ClearText();
352 m_cFileList
.SetRedraw(true);
354 InterlockedExchange(&m_bThreadRunning
, FALSE
);
355 InvalidateRect(NULL
);
357 EnableInputControl(true);
361 int CFileDiffDlg::AddEntry(const CTGitPath
* fd
)
366 int index
= m_cFileList
.GetItemCount();
369 // if (fd->node == svn_node_dir)
370 // icon_idx = m_nIconFolder;
373 icon_idx
= SYS_IMAGE_LIST().GetPathIconIndex(fd
->GetGitPathString());
376 ret
= m_cFileList
.InsertItem(index
, fd
->GetGitPathString(), icon_idx
);
377 m_cFileList
.SetItemText(index
, 1, ((CTGitPath
*)fd
)->GetActionName());
378 m_cFileList
.SetItemText(index
, 2, ((CTGitPath
*)fd
)->m_StatAdd
);
379 m_cFileList
.SetItemText(index
, 3, ((CTGitPath
*)fd
)->m_StatDel
);
384 void CFileDiffDlg::EnableInputControl(bool b
)
386 this->m_ctrRev1Edit
.EnableWindow(b
);
387 this->m_ctrRev2Edit
.EnableWindow(b
);
388 this->m_cRev1Btn
.EnableWindow(b
);
389 this->m_cRev2Btn
.EnableWindow(b
);
390 m_cFilter
.EnableWindow(b
);
391 m_SwitchButton
.EnableWindow(b
);
394 void CFileDiffDlg::DoDiff(int selIndex
, bool blame
)
397 CTGitPath
* fd
= m_arFilteredList
[selIndex
];
398 diff
.Diff(fd
, fd
,this->m_rev1
.m_CommitHash
.ToString(), this->m_rev2
.m_CommitHash
.ToString(), blame
, FALSE
);
401 CFileDiffDlg::CTGitPath
* fd
= m_arFilteredList
[selIndex
];
403 CTGitPath url1
= CTGitPath(m_path1
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString());
404 CTGitPath url2
= m_bDoPegDiff
? url1
: CTGitPath(m_path2
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString());
406 if (fd
.kind
== svn_client_diff_summarize_kind_deleted
)
408 if (!PathIsURL(url1
))
409 url1
= CTGitPath(GetURLFromPath(m_path1
) + _T("/") + fd
.path
.GetGitPathString());
410 if (!PathIsURL(url2
))
411 url2
= m_bDoPegDiff
? url1
: CTGitPath(GetURLFromPath(m_path2
) + _T("/") + fd
.path
.GetGitPathString());
418 if (fd
.node
== svn_node_dir
)
421 CTGitPath tempfile
= CTempFiles::Instance().GetTempFilePath(false, m_path1
, m_rev1
);
423 CProgressDlg progDlg
;
424 progDlg
.SetTitle(IDS_PROGRESSWAIT
);
425 progDlg
.SetAnimation(IDR_DOWNLOAD
);
426 progDlg
.ShowModeless(this);
427 progDlg
.FormatPathLine(1, IDS_PROGRESSGETFILE
, (LPCTSTR
)m_path1
.GetUIPathString());
428 progDlg
.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT
, (LPCTSTR
)m_rev1
.ToString());
430 if ((fd
.kind
!= svn_client_diff_summarize_kind_added
)&&(!blame
)&&(!Cat(url1
, m_bDoPegDiff
? m_peg
: m_rev1
, m_rev1
, tempfile
)))
432 if ((!m_bDoPegDiff
)||(!Cat(url1
, m_rev1
, m_rev1
, tempfile
)))
434 CMessageBox::Show(NULL
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
438 else if ((fd
.kind
!= svn_client_diff_summarize_kind_added
)&&(blame
)&&(!m_blamer
.BlameToFile(url1
, 1, m_rev1
, m_bDoPegDiff
? m_peg
: m_rev1
, tempfile
, _T(""), TRUE
, TRUE
)))
440 if ((!m_bDoPegDiff
)||(!m_blamer
.BlameToFile(url1
, 1, m_rev1
, m_rev1
, tempfile
, _T(""), TRUE
, TRUE
)))
442 CMessageBox::Show(NULL
, m_blamer
.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
446 SetFileAttributes(tempfile
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
447 progDlg
.SetProgress(1, 2);
448 progDlg
.FormatPathLine(1, IDS_PROGRESSGETFILE
, (LPCTSTR
)url2
.GetUIPathString());
449 progDlg
.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT
, (LPCTSTR
)m_rev2
.ToString());
450 CTGitPath tempfile2
= CTempFiles::Instance().GetTempFilePath(false, url2
, m_rev2
);
451 if ((fd
.kind
!= svn_client_diff_summarize_kind_deleted
)&&(!blame
)&&(!Cat(url2
, m_bDoPegDiff
? m_peg
: m_rev2
, m_rev2
, tempfile2
)))
453 if ((!m_bDoPegDiff
)||(!Cat(url2
, m_rev2
, m_rev2
, tempfile2
)))
455 CMessageBox::Show(NULL
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
459 else if ((fd
.kind
!= svn_client_diff_summarize_kind_deleted
)&&(blame
)&&(!m_blamer
.BlameToFile(url2
, 1, m_bDoPegDiff
? m_peg
: m_rev2
, m_rev2
, tempfile2
, _T(""), TRUE
, TRUE
)))
461 if ((!m_bDoPegDiff
)||(!m_blamer
.BlameToFile(url2
, 1, m_rev2
, m_rev2
, tempfile2
, _T(""), TRUE
, TRUE
)))
463 CMessageBox::Show(NULL
, m_blamer
.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
467 SetFileAttributes(tempfile2
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
468 progDlg
.SetProgress(2,2);
471 CString rev1name
, rev2name
;
474 rev1name
.Format(_T("%s Revision %ld"), (LPCTSTR
)fd
.path
.GetGitPathString(), (LONG
)m_rev1
);
475 rev2name
.Format(_T("%s Revision %ld"), (LPCTSTR
)fd
.path
.GetGitPathString(), (LONG
)m_rev2
);
479 rev1name
= m_path1
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString();
480 rev2name
= m_path2
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString();
482 CAppUtils::DiffFlags flags
;
483 flags
.AlternativeTool(!!(GetAsyncKeyState(VK_SHIFT
) & 0x8000));
485 CAppUtils::StartExtDiff(
486 tempfile
, tempfile2
, rev1name
, rev2name
, flags
);
491 void CFileDiffDlg::DiffProps(int selIndex
)
493 CFileDiffDlg::CTGitPath
* fd
= m_arFilteredList
[selIndex
];
495 CTGitPath url1
= CTGitPath(m_path1
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString());
496 CTGitPath url2
= m_bDoPegDiff
? url1
: CTGitPath(m_path2
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString());
498 GitProperties
propsurl1(url1
, m_rev1
, false);
499 GitProperties
propsurl2(url2
, m_rev2
, false);
501 // collect the properties of both revisions in a set
502 std::set
<stdstring
> properties
;
503 for (int wcindex
= 0; wcindex
< propsurl1
.GetCount(); ++wcindex
)
505 stdstring urlname
= propsurl1
.GetItemName(wcindex
);
506 if ( properties
.find(urlname
) == properties
.end() )
508 properties
.insert(urlname
);
511 for (int wcindex
= 0; wcindex
< propsurl2
.GetCount(); ++wcindex
)
513 stdstring urlname
= propsurl2
.GetItemName(wcindex
);
514 if ( properties
.find(urlname
) == properties
.end() )
516 properties
.insert(urlname
);
520 // iterate over all properties and diff the properties
521 for (std::set
<stdstring
>::iterator iter
= properties
.begin(), end
= properties
.end(); iter
!= end
; ++iter
)
523 stdstring url1name
= *iter
;
525 stdstring url1value
= _T(""); // CUnicodeUtils::StdGetUnicode((char *)propsurl1.GetItemValue(wcindex).c_str());
526 for (int url1index
= 0; url1index
< propsurl1
.GetCount(); ++url1index
)
528 if (propsurl1
.GetItemName(url1index
).compare(url1name
)==0)
530 url1value
= CString((char *)propsurl1
.GetItemValue(url1index
).c_str());
534 stdstring url2value
= _T("");
535 for (int url2index
= 0; url2index
< propsurl2
.GetCount(); ++url2index
)
537 if (propsurl2
.GetItemName(url2index
).compare(url1name
)==0)
539 url2value
= CString((char *)propsurl2
.GetItemValue(url2index
).c_str());
543 if (url2value
.compare(url1value
)!=0)
545 // write both property values to temporary files
546 CTGitPath url1propfile
= CTempFiles::Instance().GetTempFilePath(false);
547 CTGitPath url2propfile
= CTempFiles::Instance().GetTempFilePath(false);
549 _tfopen_s(&pFile
, url1propfile
.GetWinPath(), _T("wb"));
552 fputs(CUnicodeUtils::StdGetUTF8(url1value
).c_str(), pFile
);
555 _tfopen_s(&pFile
, url2propfile
.GetWinPath(), _T("wb"));
558 fputs(CUnicodeUtils::StdGetUTF8(url2value
).c_str(), pFile
);
566 SetFileAttributes(url1propfile
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
567 SetFileAttributes(url2propfile
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
569 if (m_rev1
.IsWorking())
570 n1
.Format(IDS_DIFF_WCNAME
, url1name
.c_str());
572 n1
.Format(IDS_DIFF_BASENAME
, url1name
.c_str());
573 if (m_rev1
.IsHead() || m_rev1
.IsNumber())
577 n1
.Format(_T("%s : %s Revision %ld"), url1name
.c_str(), (LPCTSTR
)fd
.path
.GetGitPathString(), (LONG
)m_rev1
);
581 CString sTemp
= url1name
.c_str();
583 n1
= sTemp
+ m_path1
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString();
586 if (m_rev2
.IsWorking())
587 n2
.Format(IDS_DIFF_WCNAME
, url1name
.c_str());
589 n2
.Format(IDS_DIFF_BASENAME
, url1name
.c_str());
590 if (m_rev2
.IsHead() || m_rev2
.IsNumber())
594 n2
.Format(_T("%s : %s Revision %ld"), url1name
.c_str(), (LPCTSTR
)fd
.path
.GetGitPathString(), (LONG
)m_rev2
);
598 CString sTemp
= url1name
.c_str();
600 n2
= sTemp
+ m_path2
.GetGitPathString() + _T("/") + fd
.path
.GetGitPathString();
603 CAppUtils::StartExtDiffProps(url1propfile
, url2propfile
, n1
, n2
, TRUE
);
608 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
611 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
612 int selIndex
= pNMLV
->iItem
;
615 if (selIndex
>= (int)m_arFilteredList
.size())
618 DoDiff(selIndex
, m_bBlame
);
621 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
624 LPNMLVGETINFOTIP pGetInfoTip
= reinterpret_cast<LPNMLVGETINFOTIP
>(pNMHDR
);
625 if (pGetInfoTip
->iItem
>= (int)m_arFilteredList
.size())
628 CString path
= m_path1
.GetGitPathString() + _T("/") + m_arFilteredList
[pGetInfoTip
->iItem
]->GetGitPathString();
629 if (pGetInfoTip
->cchTextMax
> path
.GetLength())
630 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, path
, pGetInfoTip
->cchTextMax
);
635 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
637 NMLVCUSTOMDRAW
* pLVCD
= reinterpret_cast<NMLVCUSTOMDRAW
*>( pNMHDR
);
638 // Take the default processing unless we set this to something else below.
639 *pResult
= CDRF_DODEFAULT
;
641 // First thing - check the draw stage. If it's the control's prepaint
642 // stage, then tell Windows we want messages for every item.
644 if ( CDDS_PREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
646 *pResult
= CDRF_NOTIFYITEMDRAW
;
648 else if ( CDDS_ITEMPREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
650 // This is the prepaint stage for an item. Here's where we set the
651 // item's text color. Our return value will tell Windows to draw the
652 // item itself, but it will use the new color we set here.
654 // Tell Windows to paint the control itself.
655 *pResult
= CDRF_DODEFAULT
;
657 COLORREF crText
= GetSysColor(COLOR_WINDOWTEXT
);
659 if (m_arFilteredList
.size() > pLVCD
->nmcd
.dwItemSpec
)
661 CTGitPath
* fd
= m_arFilteredList
[pLVCD
->nmcd
.dwItemSpec
];
662 switch (fd
->m_Action
)
664 case CTGitPath::LOGACTIONS_ADDED
:
665 crText
= m_colors
.GetColor(CColors::Added
);
667 case CTGitPath::LOGACTIONS_DELETED
:
668 crText
= m_colors
.GetColor(CColors::Deleted
);
670 case CTGitPath::LOGACTIONS_MODIFIED
:
671 crText
= m_colors
.GetColor(CColors::Modified
);
673 //case svn_client_diff_summarize_kind_normal:
675 //if (fd.propchanged)
676 crText
= m_colors
.GetColor(CColors::PropertyChanged
);
680 // Store the color back in the NMLVCUSTOMDRAW struct.
681 pLVCD
->clrText
= crText
;
685 UINT
CFileDiffDlg::LoadRefThread()
687 g_Git
.GetBranchList(m_Reflist
,NULL
,CGit::BRANCH_ALL_F
);
688 g_Git
.GetTagList(m_Reflist
);
690 this->PostMessage(MSG_REF_LOADED
);
691 InterlockedExchange(&m_bLoadingRef
, FALSE
);
695 void CFileDiffDlg::OnContextMenu(CWnd
* pWnd
, CPoint point
)
697 if ((pWnd
==0)||(pWnd
!= &m_cFileList
))
699 if (m_cFileList
.GetSelectedCount() == 0)
701 // if the context menu is invoked through the keyboard, we have to use
702 // a calculated position on where to anchor the menu on
703 if ((point
.x
== -1) && (point
.y
== -1))
706 m_cFileList
.GetItemRect(m_cFileList
.GetSelectionMark(), &rect
, LVIR_LABEL
);
707 m_cFileList
.ClientToScreen(&rect
);
708 point
= rect
.CenterPoint();
711 if (popup
.CreatePopupMenu())
713 popup
.AppendMenuIcon(ID_COMPARE
, IDS_LOG_POPUP_COMPARETWO
, IDI_DIFF
);
714 popup
.AppendMenuIcon(ID_BLAME
, IDS_FILEDIFF_POPBLAME
, IDI_BLAME
);
715 popup
.AppendMenuIcon(ID_LOG
, IDS_FILEDIFF_LOG
, IDI_LOG
);
716 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
717 popup
.AppendMenuIcon(ID_EXPORT
, IDS_FILEDIFF_POPEXPORT
, IDI_EXPORT
);
718 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
719 popup
.AppendMenuIcon(ID_SAVEAS
, IDS_FILEDIFF_POPSAVELIST
, IDI_SAVEAS
);
720 popup
.AppendMenuIcon(ID_CLIPBOARD_PATH
, IDS_STATUSLIST_CONTEXT_COPY
, IDI_COPYCLIP
);
721 popup
.AppendMenuIcon(ID_CLIPBOARD_ALL
, IDS_STATUSLIST_CONTEXT_COPYEXT
, IDI_COPYCLIP
);
723 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, point
.x
, point
.y
, this, 0);
724 m_bCancelled
= false;
729 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
732 int index
= m_cFileList
.GetNextSelectedItem(pos
);
733 DoDiff(index
, false);
739 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
742 int index
= m_cFileList
.GetNextSelectedItem(pos
);
743 CAppUtils::LaunchTortoiseBlame(m_arFilteredList
[index
]->GetWinPathString(), m_rev1
.m_CommitHash
.ToString());
749 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
752 int index
= m_cFileList
.GetNextSelectedItem(pos
);
754 cmd
= CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe");
755 cmd
+= _T(" /command:log");
756 cmd
+= _T(" /path:\"")+m_arFilteredList
[index
]->GetWinPathString()+_T("\" ");
757 cmd
+= _T(" /endrev:")+m_rev1
.m_CommitHash
.ToString();
758 CAppUtils::LaunchApplication(cmd
,IDS_ERR_PROC
,false);
764 if (m_cFileList
.GetSelectedCount() > 0)
769 if (!CAppUtils::FileOpenSave(pathSave
, NULL
, IDS_REPOBROWSE_SAVEAS
, IDS_COMMONFILEFILTER
, false, m_hWnd
))
773 savePath
= CTGitPath(pathSave
);
775 // now open the selected file for writing
778 CStdioFile
file(savePath
.GetWinPathString(), CFile::typeBinary
| CFile::modeReadWrite
| CFile::modeCreate
);
779 // temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, (LPCTSTR)m_path1.GetGitPathString(), (LPCTSTR)m_rev1.ToString(), (LPCTSTR)m_path2.GetGitPathString(), (LPCTSTR)m_rev2.ToString());
780 file
.WriteString(temp
+ _T("\n"));
781 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
784 int index
= m_cFileList
.GetNextSelectedItem(pos
);
785 CTGitPath
* fd
= m_arFilteredList
[index
];
786 file
.WriteString(fd
->GetGitPathString());
787 file
.WriteString(_T("\n"));
791 catch (CFileException
* pE
)
798 case ID_CLIPBOARD_PATH
:
800 CopySelectionToClipboard();
804 case ID_CLIPBOARD_ALL
:
806 CopySelectionToClipboard(TRUE
);
811 // export all changed files to a folder
812 CBrowseFolder browseFolder
;
813 browseFolder
.m_style
= BIF_EDITBOX
| BIF_NEWDIALOGSTYLE
| BIF_RETURNFSANCESTORS
| BIF_RETURNONLYFSDIRS
;
814 if (browseFolder
.Show(GetSafeHwnd(), m_strExportDir
) == CBrowseFolder::OK
)
816 m_arSelectedFileList
.RemoveAll();
817 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
820 int index
= m_cFileList
.GetNextSelectedItem(pos
);
821 CTGitPath
* fd
= m_arFilteredList
[index
];
823 m_arSelectedFileList
.Add(fd
);
825 // we cannot export directories or folders
826 if (fd
->m_Action
== CTGitPath::LOGACTIONS_DELETED
|| fd
->IsDirectory())
828 CAppUtils::CreateMultipleDirectory(m_strExportDir
+ _T("\\") + fd
->GetDirectory().GetWinPathString());
829 CString filename
= m_strExportDir
+ _T("\\") + fd
->GetWinPathString();
830 if(m_rev1
.m_CommitHash
.ToString() == GIT_REV_ZERO
)
832 if(!CopyFile(g_Git
.m_CurrentDir
+ _T("\\") + fd
->GetWinPath(), filename
, false))
834 LPVOID lpMsgBuf
=NULL
;
835 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM
,
836 NULL
,GetLastError(),MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
839 CMessageBox::Show(NULL
,(TCHAR
*)lpMsgBuf
, _T("TortoiseGit"), MB_OK
|MB_ICONERROR
);
846 if(g_Git
.GetOneFile(m_rev1
.m_CommitHash
, *fd
, filename
))
849 out
.Format(_T("Fail checkout one file %s;%s"), m_rev1
.m_CommitHash
.ToString(), fd
->GetWinPath());
850 CMessageBox::Show(NULL
, out
, _T("TortoiseGit"), MB_OK
);
856 m_pProgDlg
= new CProgressDlg();
857 InterlockedExchange(&m_bThreadRunning
, TRUE
);
858 if (AfxBeginThread(ExportThreadEntry
, this)==NULL
)
860 InterlockedExchange(&m_bThreadRunning
, FALSE
);
861 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
873 UINT
CFileDiffDlg::ExportThreadEntry(LPVOID pVoid
)
875 return ((CFileDiffDlg
*)pVoid
)->ExportThread();
878 UINT
CFileDiffDlg::ExportThread()
882 // if (m_pProgDlg == NULL)
885 // SetAndClearProgressInfo(m_pProgDlg, false);
886 m_pProgDlg
->SetTitle(IDS_PROGRESSWAIT
);
887 m_pProgDlg
->SetAnimation(AfxGetResourceHandle(), IDR_DOWNLOAD
);
888 m_pProgDlg
->ShowModeless(this);
889 for (INT_PTR i
=0; (i
<m_arSelectedFileList
.GetCount())&&(!m_pProgDlg
->HasUserCancelled()); ++i
)
891 CTGitPath
* fd
= m_arSelectedFileList
[i
];
892 // CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
893 // CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
894 // if ((fd.node == svn_node_dir)&&(fd.kind != svn_client_diff_summarize_kind_added))
896 // just create the directory
897 // CreateDirectoryEx(NULL, m_strExportDir+_T("\\")+CPathUtils::PathUnescape(fd.path.GetWinPathString()), NULL);
902 m_pProgDlg
->FormatPathLine(1, IDS_PROGRESSGETFILE
, (LPCTSTR
)url1
.GetGitPathString());
904 CTGitPath savepath
= CTGitPath(m_strExportDir
);
905 savepath
.AppendPathString(_T("\\") + CPathUtils::PathUnescape(fd
.path
.GetWinPathString()));
906 CPathUtils::MakeSureDirectoryPathExists(fd
.node
== svn_node_file
? savepath
.GetContainingDirectory().GetWinPath() : savepath
.GetDirectory().GetWinPath());
907 if (fd
.node
== svn_node_dir
)
909 // exporting a folder requires calling Git::Export() so we also export all
910 // children of that added folder.
911 if ((fd
.kind
== svn_client_diff_summarize_kind_added
)&&(!Export(url2
, savepath
, m_bDoPegDiff
? m_peg
: m_rev2
, m_rev2
, true, true)))
913 if ((!m_bDoPegDiff
)||(!Export(url2
, savepath
, m_rev2
, m_rev2
, true, true)))
917 CMessageBox::Show(NULL
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
918 InterlockedExchange(&m_bThreadRunning
, FALSE
);
926 // exporting a file requires calling Git::Cat(), since Git::Export() only works
928 if ((fd
.kind
!= svn_client_diff_summarize_kind_deleted
)&&(!Cat(url2
, m_bDoPegDiff
? m_peg
: m_rev2
, m_rev2
, savepath
)))
930 if ((!m_bDoPegDiff
)||(!Cat(url2
, m_rev2
, m_rev2
, savepath
)))
934 CMessageBox::Show(NULL
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
935 InterlockedExchange(&m_bThreadRunning
, FALSE
);
942 m_pProgDlg
->SetProgress (count
, static_cast<DWORD
>(m_arSelectedFileList
.GetCount()));
945 SetAndClearProgressInfo(NULL
, false);
948 InterlockedExchange(&m_bThreadRunning
, FALSE
);
954 BOOL
CFileDiffDlg::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
956 if (pWnd
!= &m_cFileList
)
957 return CResizableStandAloneDialog::OnSetCursor(pWnd
, nHitTest
, message
);
958 if (m_bThreadRunning
== 0)
960 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_ARROW
));
962 return CResizableStandAloneDialog::OnSetCursor(pWnd
, nHitTest
, message
);
964 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_WAIT
));
969 void CFileDiffDlg::OnEnSetfocusFirsturl()
971 GetDlgItem(IDC_FIRSTURL
)->HideCaret();
974 void CFileDiffDlg::OnEnSetfocusSecondurl()
976 GetDlgItem(IDC_SECONDURL
)->HideCaret();
980 void CFileDiffDlg::OnBnClickedSwitchleftright()
983 if (m_bThreadRunning
)
987 CString sFilterString
;
988 m_cFilter
.GetWindowText(sFilterString
);
990 m_cFileList
.SetRedraw(false);
991 m_cFileList
.DeleteAllItems();
992 for (int i
=0; i
<(int)m_arFileList
.GetCount(); ++i
)
994 CTGitPath fd
= m_arFileList
[i
];
995 if (fd
.m_Action
== CTGitPath::LOGACTIONS_ADDED
)
996 fd
.m_Action
= CTGitPath::LOGACTIONS_DELETED
;
997 else if (fd
.m_Action
== CTGitPath::LOGACTIONS_DELETED
)
998 fd
.m_Action
= CTGitPath::LOGACTIONS_ADDED
;
999 std::swap(fd
.m_StatAdd
, fd
.m_StatDel
);
1000 (CTGitPath
&)m_arFileList
[i
] = fd
;
1002 Filter(sFilterString
);
1005 m_cFileList
.SetRedraw(true);
1006 CTGitPath path
= m_path1
;
1009 GitRev rev
= m_rev1
;
1014 this->m_ctrRev1Edit
.GetWindowText(str1
);
1015 this->m_ctrRev2Edit
.GetWindowText(str2
);
1017 this->m_ctrRev1Edit
.SetWindowText(str2
);
1018 this->m_ctrRev2Edit
.SetWindowText(str1
);
1021 //KillTimer(IDT_INPUT);
1024 void CFileDiffDlg::SetURLLabels(int mask
)
1027 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
1028 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
1032 SetDlgItemText(IDC_FIRSTURL
, m_rev1
.m_CommitHash
.ToString().Left(8)+_T(": ")+m_rev1
.GetSubject());
1033 m_tooltips
.AddTool(IDC_FIRSTURL
,
1034 CAppUtils::FormatDateAndTime( m_rev1
.GetAuthorDate(), DATE_SHORTDATE
, false )+_T(" ")+m_rev1
.GetAuthorName());
1040 SetDlgItemText(IDC_SECONDURL
,m_rev2
.m_CommitHash
.ToString().Left(8)+_T(": ")+m_rev2
.GetSubject());
1042 m_tooltips
.AddTool(IDC_SECONDURL
,
1043 CAppUtils::FormatDateAndTime( m_rev2
.GetAuthorDate(), DATE_SHORTDATE
, false )+_T(" ")+m_rev2
.GetAuthorName());
1046 this->GetDlgItem(IDC_REV2GROUP
)->SetWindowText(_T("Version 2 (Base)"));
1047 this->GetDlgItem(IDC_REV1GROUP
)->SetWindowText(_T("Version 1"));
1049 if( (mask
&0x3) == 0x3)
1050 if(m_rev2
.GetCommitterDate() > m_rev1
.GetCommitterDate())
1052 this->GetDlgItem(IDC_REV2GROUP
)->SetWindowText(_T("Version 2 (Base) (Commit Date New)"));
1056 this->GetDlgItem(IDC_REV1GROUP
)->SetWindowText(_T("Version 1 (Commit Data New)"));
1060 void CFileDiffDlg::ClearURLabels(int mask
)
1064 SetDlgItemText(IDC_FIRSTURL
, _T(""));
1065 m_tooltips
.AddTool(IDC_FIRSTURL
, _T(""));
1070 SetDlgItemText(IDC_SECONDURL
, _T(""));
1071 m_tooltips
.AddTool(IDC_SECONDURL
, _T(""));
1074 BOOL
CFileDiffDlg::PreTranslateMessage(MSG
* pMsg
)
1076 m_tooltips
.RelayEvent(pMsg
);
1077 if (pMsg
->message
== WM_KEYDOWN
)
1079 switch (pMsg
->wParam
)
1083 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
1085 // select all entries
1086 for (int i
=0; i
<m_cFileList
.GetItemCount(); ++i
)
1088 m_cFileList
.SetItemState(i
, LVIS_SELECTED
, LVIS_SELECTED
);
1097 if (GetAsyncKeyState(VK_CONTROL
)&0x8000)
1099 CopySelectionToClipboard();
1106 if (GetFocus() == GetDlgItem(IDC_FILELIST
))
1108 // Return pressed in file list. Show diff, as for double click
1109 int selIndex
= m_cFileList
.GetSelectionMark();
1110 if ((selIndex
>= 0) && (selIndex
< (int)m_arFileList
.GetCount()))
1111 DoDiff(selIndex
, m_bBlame
);
1118 return __super::PreTranslateMessage(pMsg
);
1121 void CFileDiffDlg::OnCancel()
1123 if (m_bThreadRunning
)
1125 m_bCancelled
= true;
1128 __super::OnCancel();
1131 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
1133 LPNMHEADER phdr
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
1134 if (m_bThreadRunning
)
1137 if (m_nSortedColumn
== phdr
->iItem
)
1138 m_bAscending
= !m_bAscending
;
1140 m_bAscending
= TRUE
;
1141 m_nSortedColumn
= phdr
->iItem
;
1142 m_arSelectedFileList
.RemoveAll();
1146 m_cFileList
.SetRedraw(FALSE
);
1147 m_cFileList
.DeleteAllItems();
1148 m_cFilter
.GetWindowText(temp
);
1151 CHeaderCtrl
* pHeader
= m_cFileList
.GetHeaderCtrl();
1152 HDITEM HeaderItem
= {0};
1153 HeaderItem
.mask
= HDI_FORMAT
;
1154 for (int i
=0; i
<pHeader
->GetItemCount(); ++i
)
1156 pHeader
->GetItem(i
, &HeaderItem
);
1157 HeaderItem
.fmt
&= ~(HDF_SORTDOWN
| HDF_SORTUP
);
1158 pHeader
->SetItem(i
, &HeaderItem
);
1160 pHeader
->GetItem(m_nSortedColumn
, &HeaderItem
);
1161 HeaderItem
.fmt
|= (m_bAscending
? HDF_SORTUP
: HDF_SORTDOWN
);
1162 pHeader
->SetItem(m_nSortedColumn
, &HeaderItem
);
1164 m_cFileList
.SetRedraw(TRUE
);
1169 void CFileDiffDlg::Sort()
1171 if(m_arFileList
.GetCount() < 2)
1176 std::sort(m_arFileList
.m_paths
.begin(), m_arFileList
.m_paths
.end(), &CFileDiffDlg::SortCompare
);
1179 bool CFileDiffDlg::SortCompare(const CTGitPath
& Data1
, const CTGitPath
& Data2
)
1183 switch (m_nSortedColumn
)
1185 case 0: //path column
1186 result
= Data1
.GetWinPathString().Compare(Data2
.GetWinPathString());
1188 case 1: //action column
1189 result
= Data1
.m_Action
- Data2
.m_Action
;
1192 d1
= CSorter::A2L(Data1
.m_StatAdd
);
1193 d2
= CSorter::A2L(Data2
.m_StatAdd
);
1197 d1
= CSorter::A2L(Data1
.m_StatDel
);;
1198 d2
= CSorter::A2L(Data2
.m_StatDel
);
1211 void CFileDiffDlg::OnBnClickedRev1btn()
1213 ClickRevButton(&this->m_cRev1Btn
,&this->m_rev1
, &this->m_ctrRev1Edit
);
1216 void CFileDiffDlg::ClickRevButton(CMenuButton
*button
, GitRev
*rev
, CACEdit
*edit
)
1218 int entry
=button
->GetCurrentEntry();
1219 if(entry
== 0) /* Browse Refence*/
1222 CString str
= CBrowseRefsDlg::PickRef();
1226 if(FillRevFromString(rev
,str
))
1229 edit
->SetWindowText(str
);
1233 if(entry
== 1) /*Log*/
1236 dlg
.SetSelect(true);
1237 if(dlg
.DoModal() == IDOK
)
1239 if( dlg
.GetSelectedHash().IsEmpty() )
1242 if(FillRevFromString(rev
,dlg
.GetSelectedHash()))
1245 edit
->SetWindowText(dlg
.GetSelectedHash());
1252 if(entry
== 2) /*RefLog*/
1255 if(dlg
.DoModal() == IDOK
)
1257 if(FillRevFromString(rev
,dlg
.m_SelectedHash
))
1260 edit
->SetWindowText(dlg
.m_SelectedHash
);
1269 InterlockedExchange(&m_bThreadRunning
, TRUE
);
1270 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
1272 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1273 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1275 KillTimer(IDT_INPUT
);
1278 void CFileDiffDlg::OnBnClickedRev2btn()
1280 ClickRevButton(&this->m_cRev2Btn
,&this->m_rev2
, &this->m_ctrRev2Edit
);
1282 if (m_bThreadRunning
)
1283 return; // do nothing as long as the thread is still running
1285 // show a dialog where the user can enter a revision
1286 CRevisionDlg
dlg(this);
1287 dlg
.AllowWCRevs(false);
1288 *((GitRev
*)&dlg
) = m_rev2
;
1290 if (dlg
.DoModal() == IDOK
)
1293 m_cRev2Btn
.SetWindowText(m_rev2
.ToString());
1294 m_cFileList
.DeleteAllItems();
1295 // start a new thread to re-fetch the diff
1296 InterlockedExchange(&m_bThreadRunning
, TRUE
);
1297 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
1299 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1300 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1306 LRESULT
CFileDiffDlg::OnClickedCancelFilter(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1308 if (m_bThreadRunning
)
1310 SetTimer(IDT_FILTER
, 1000, NULL
);
1314 KillTimer(IDT_FILTER
);
1316 m_cFileList
.SetRedraw(FALSE
);
1317 m_arFilteredList
.clear();
1318 m_cFileList
.DeleteAllItems();
1322 m_cFileList
.SetRedraw(TRUE
);
1326 void CFileDiffDlg::OnEnChangeFilter()
1328 SetTimer(IDT_FILTER
, 1000, NULL
);
1331 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent
)
1333 if (m_bThreadRunning
)
1336 if( nIDEvent
== IDT_FILTER
)
1338 CString sFilterText
;
1339 KillTimer(IDT_FILTER
);
1340 m_cFilter
.GetWindowText(sFilterText
);
1342 m_cFileList
.SetRedraw(FALSE
);
1343 m_cFileList
.DeleteAllItems();
1345 Filter(sFilterText
);
1347 m_cFileList
.SetRedraw(TRUE
);
1349 __super::OnTimer(nIDEvent
);
1352 if( nIDEvent
== IDT_INPUT
)
1354 KillTimer(IDT_INPUT
);
1355 TRACE(_T("Input Timer\r\n"));
1360 this->m_ctrRev1Edit
.GetWindowText(str
);
1361 if( !gitrev
.GetCommit(str
) )
1363 this->m_rev1
=gitrev
;
1367 this->m_ctrRev2Edit
.GetWindowText(str
);
1369 if( !gitrev
.GetCommit(str
) )
1371 this->m_rev2
=gitrev
;
1375 this->SetURLLabels(mask
);
1380 InterlockedExchange(&m_bThreadRunning
, TRUE
);
1381 if (AfxBeginThread(DiffThreadEntry
, this)==NULL
)
1383 InterlockedExchange(&m_bThreadRunning
, FALSE
);
1384 CMessageBox::Show(NULL
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
1390 void CFileDiffDlg::Filter(CString sFilterText
)
1392 sFilterText
.MakeLower();
1394 m_arFilteredList
.clear();
1396 for (int i
=0;i
<m_arFileList
.GetCount();i
++)
1398 CString sPath
= m_arFileList
[i
].GetGitPathString();
1400 if (sPath
.Find(sFilterText
) >= 0)
1402 m_arFilteredList
.push_back((CTGitPath
*)&(m_arFileList
[i
]));
1405 for (std::vector
<CTGitPath
*>::const_iterator it
= m_arFilteredList
.begin(); it
!= m_arFilteredList
.end(); ++it
)
1411 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull
)
1413 // copy all selected paths to the clipboard
1414 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
1416 CString sTextForClipboard
;
1417 while ((index
= m_cFileList
.GetNextSelectedItem(pos
)) >= 0)
1419 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 0);
1420 sTextForClipboard
+= _T("\t");
1424 sTextForClipboard
+= _T("\r\n");
1428 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 1);
1429 sTextForClipboard
+= _T("\t");
1430 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 2);
1431 sTextForClipboard
+= _T("\t");
1432 sTextForClipboard
+= m_cFileList
.GetItemText(index
, 3);
1433 sTextForClipboard
+= _T("\r\n");
1436 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard
);
1440 LRESULT
CFileDiffDlg::OnRefLoad(WPARAM wParam
, LPARAM lParam
)
1442 UNREFERENCED_PARAMETER(wParam
);
1443 UNREFERENCED_PARAMETER(lParam
);
1444 for(int i
=0;i
<m_Reflist
.size();i
++)
1446 CString str
=m_Reflist
[i
];
1448 if(str
.Find(_T("remotes/")) == 0)
1451 m_ctrRev1Edit
.AddSearchString(str
);
1452 m_ctrRev2Edit
.AddSearchString(str
);
1457 BOOL
CFileDiffDlg::DestroyWindow()
1459 return CResizableStandAloneDialog::DestroyWindow();
1462 LRESULT
CFileDiffDlg::OnEnUpdate(WPARAM
/*wParam*/, LPARAM lParam
)
1464 if(lParam
== IDC_REV1EDIT
)
1466 OnTextUpdate(&this->m_ctrRev1Edit
);
1469 if(lParam
== IDC_REV2EDIT
)
1471 OnTextUpdate(&this->m_ctrRev2Edit
);
1472 ClearURLabels(1<<1);
1477 void CFileDiffDlg::OnTextUpdate(CACEdit
* /*pEdit*/)
1479 SetTimer(IDT_INPUT
, 1000, NULL
);
1480 this->m_cFileList
.ShowText(_T("Wait For input validate version"));