dropped unused TSVN settings
[TortoiseGit.git] / src / TortoiseProc / FileDiffDlg.cpp
blob06c7b30b74602f15d518053ec40ce7d5b80a7a78
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.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "UnicodeUtils.h"
23 #include "MessageBox.h"
24 #include "AppUtils.h"
25 #include "TempFile.h"
26 #include "ProgressDlg.h"
27 #include "SysImageList.h"
28 #include "IconMenu.h"
29 //#include "GitProperties.h"
30 #include "StringUtils.h"
31 #include "PathUtils.h"
32 #include "BrowseFolder.h"
33 #include ".\filediffdlg.h"
34 #include "gitdiff.h"
35 #include "CommonResource.h"
36 #include "BrowseRefsDlg.h"
37 #include "LogDlg.h"
38 #include "RefLogDlg.h"
39 #include "GitStatusListCtrl.h"
41 #define ID_COMPARE 1
42 #define ID_BLAME 2
43 #define ID_SAVEAS 3
44 #define ID_EXPORT 4
45 #define ID_CLIPBOARD_PATH 5
46 #define ID_CLIPBOARD_ALL 6
47 #define ID_LOG 7
49 BOOL CFileDiffDlg::m_bAscending = FALSE;
50 int CFileDiffDlg::m_nSortedColumn = -1;
53 IMPLEMENT_DYNAMIC(CFileDiffDlg, CResizableStandAloneDialog)
54 CFileDiffDlg::CFileDiffDlg(CWnd* pParent /*=NULL*/)
55 : CResizableStandAloneDialog(CFileDiffDlg::IDD, pParent),
56 m_bBlame(false),
57 m_pProgDlg(NULL),
58 m_bCancelled(false)
60 m_bLoadingRef=FALSE;
63 CFileDiffDlg::~CFileDiffDlg()
67 void CFileDiffDlg::DoDataExchange(CDataExchange* pDX)
69 CResizableStandAloneDialog::DoDataExchange(pDX);
70 DDX_Control(pDX, IDC_FILELIST, m_cFileList);
71 DDX_Control(pDX, IDC_SWITCHLEFTRIGHT, m_SwitchButton);
72 DDX_Control(pDX, IDC_REV1BTN, m_cRev1Btn);
73 DDX_Control(pDX, IDC_REV2BTN, m_cRev2Btn);
74 DDX_Control(pDX, IDC_FILTER, m_cFilter);
75 DDX_Control(pDX, IDC_REV1EDIT, m_ctrRev1Edit);
76 DDX_Control(pDX, IDC_REV2EDIT, m_ctrRev2Edit);
80 BEGIN_MESSAGE_MAP(CFileDiffDlg, CResizableStandAloneDialog)
81 ON_NOTIFY(NM_DBLCLK, IDC_FILELIST, OnNMDblclkFilelist)
82 ON_NOTIFY(LVN_GETINFOTIP, IDC_FILELIST, OnLvnGetInfoTipFilelist)
83 ON_NOTIFY(NM_CUSTOMDRAW, IDC_FILELIST, OnNMCustomdrawFilelist)
84 ON_WM_CONTEXTMENU()
85 ON_WM_SETCURSOR()
86 ON_EN_SETFOCUS(IDC_SECONDURL, &CFileDiffDlg::OnEnSetfocusSecondurl)
87 ON_EN_SETFOCUS(IDC_FIRSTURL, &CFileDiffDlg::OnEnSetfocusFirsturl)
88 ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT, &CFileDiffDlg::OnBnClickedSwitchleftright)
89 ON_NOTIFY(HDN_ITEMCLICK, 0, &CFileDiffDlg::OnHdnItemclickFilelist)
90 ON_BN_CLICKED(IDC_REV1BTN, &CFileDiffDlg::OnBnClickedRev1btn)
91 ON_BN_CLICKED(IDC_REV2BTN, &CFileDiffDlg::OnBnClickedRev2btn)
92 ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)
93 ON_EN_CHANGE(IDC_FILTER, &CFileDiffDlg::OnEnChangeFilter)
94 ON_WM_TIMER()
95 ON_MESSAGE(ENAC_UPDATE, &CFileDiffDlg::OnEnUpdate)
96 ON_MESSAGE(MSG_REF_LOADED, OnRefLoad)
97 END_MESSAGE_MAP()
100 void CFileDiffDlg::SetDiff(CTGitPath * path, GitRev rev1, GitRev rev2)
102 if(path!=NULL)
104 m_path1 = *path;
105 m_path2 = *path;
106 m_sFilter = path->GetGitPathString();
108 m_rev1 = rev1;
109 m_rev2 = rev2;
112 void CFileDiffDlg::SetDiff(CTGitPath * path, CString &hash1, CString &hash2)
114 if(path!=NULL)
116 m_path1 = *path;
117 m_path2 = *path;
118 m_sFilter = path->GetGitPathString();
121 BYTE_VECTOR logout;
123 if(hash1 == GIT_REV_ZERO)
125 m_rev1.m_CommitHash.Empty();
126 m_rev1.GetSubject()=_T("Working Copy");
128 else
130 m_rev1.GetCommit(hash1);
133 logout.clear();
135 if(hash2 == GIT_REV_ZERO)
137 m_rev2.m_CommitHash.Empty();
138 m_rev2.GetSubject()=_T("Working Copy");
140 else
142 m_rev2.GetCommit(hash2);
146 void CFileDiffDlg::SetDiff(CTGitPath * path, GitRev rev1)
148 if(path!=NULL)
150 m_path1 = *path;
151 m_path2 = *path;
152 m_sFilter = path->GetGitPathString();
154 m_rev1 = rev1;
155 m_rev2.m_CommitHash.Empty();
156 m_rev2.GetSubject() = _T("Previous Version");
158 //this->GetDlgItem()->EnableWindow(FALSE);
161 BOOL CFileDiffDlg::OnInitDialog()
163 CResizableStandAloneDialog::OnInitDialog();
164 CString temp;
166 CString sWindowTitle;
167 GetWindowText(sWindowTitle);
168 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
170 this->m_ctrRev1Edit.Init();
171 this->m_ctrRev2Edit.Init();
173 m_tooltips.Create(this);
174 m_tooltips.AddTool(IDC_SWITCHLEFTRIGHT, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT);
176 m_cFileList.SetRedraw(false);
177 m_cFileList.DeleteAllItems();
178 DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
179 m_cFileList.SetExtendedStyle(exStyle);
181 m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();
182 m_cFileList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);
184 m_SwitchButton.SetImage((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR));
185 m_SwitchButton.Invalidate();
187 m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);
188 m_cFilter.SetInfoIcon(IDI_FILTEREDIT);
189 temp.LoadString(IDS_FILEDIFF_FILTERCUE);
190 temp = _T(" ")+temp;
191 m_cFilter.SetCueBanner(temp);
192 if (!m_sFilter.IsEmpty())
193 m_cFilter.SetWindowText(m_sFilter);
195 int c = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
196 while (c>=0)
197 m_cFileList.DeleteColumn(c--);
199 temp.LoadString(IDS_FILEDIFF_FILE);
200 m_cFileList.InsertColumn(0, temp);
201 temp.LoadString(IDS_FILEDIFF_ACTION);
202 m_cFileList.InsertColumn(1, temp);
204 temp.LoadString(IDS_FILEDIFF_STATADD);
205 m_cFileList.InsertColumn(2, temp);
206 temp.LoadString(IDS_FILEDIFF_STATDEL);
207 m_cFileList.InsertColumn(3, temp);
209 int mincol = 0;
210 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
211 int col;
212 for (col = mincol; col <= maxcol; col++)
214 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);
217 m_cFileList.SetRedraw(true);
219 AddAnchor(IDC_DIFFSTATIC1, TOP_LEFT, TOP_RIGHT);
220 AddAnchor(IDC_SWITCHLEFTRIGHT, TOP_RIGHT);
221 AddAnchor(IDC_FIRSTURL, TOP_LEFT, TOP_RIGHT);
222 AddAnchor(IDC_REV1BTN, TOP_RIGHT);
223 //AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);
224 AddAnchor(IDC_SECONDURL, TOP_LEFT, TOP_RIGHT);
225 AddAnchor(IDC_REV2BTN, TOP_RIGHT);
226 AddAnchor(IDC_FILTER, TOP_LEFT, TOP_RIGHT);
227 AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);
228 AddAnchor(IDC_REV1GROUP,TOP_LEFT,TOP_RIGHT);
229 AddAnchor(IDC_REV2GROUP,TOP_LEFT,TOP_RIGHT);
230 AddAnchor(IDC_REV1EDIT,TOP_LEFT);
231 AddAnchor(IDC_REV2EDIT,TOP_LEFT);
233 EnableSaveRestore(_T("FileDiffDlg"));
235 if(this->m_strRev1.IsEmpty())
236 this->m_ctrRev1Edit.SetWindowText(this->m_rev1.m_CommitHash.ToString());
237 else
239 if(m_rev1.GetCommit(this->m_strRev1))
240 this->m_FileListText+=this->m_strRev1 + _T(" is wrong");
242 this->m_ctrRev1Edit.SetWindowText(m_strRev1);
245 if(this->m_strRev2.IsEmpty())
246 this->m_ctrRev2Edit.SetWindowText(this->m_rev2.m_CommitHash.ToString());
247 else
249 if(m_rev2.GetCommit(this->m_strRev2))
250 this->m_FileListText+=this->m_strRev2 + _T(" is wrong");
252 this->m_ctrRev2Edit.SetWindowText(m_strRev2);
255 SetURLLabels();
257 InterlockedExchange(&m_bThreadRunning, TRUE);
258 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
260 InterlockedExchange(&m_bThreadRunning, FALSE);
261 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
264 InterlockedExchange(&m_bLoadingRef, TRUE);
265 if (AfxBeginThread(LoadRefThreadEntry, this)==NULL)
267 InterlockedExchange(&m_bLoadingRef, FALSE);
268 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
271 this->m_cRev1Btn.AddEntry(_T("RefBrowse"));
272 this->m_cRev1Btn.AddEntry(_T("Log"));
273 this->m_cRev1Btn.AddEntry(_T("RefLog"));
275 this->m_cRev2Btn.AddEntry(_T("RefBrowse"));
276 this->m_cRev2Btn.AddEntry(_T("Log"));
277 this->m_cRev2Btn.AddEntry(_T("RefLog"));
279 // Start with focus on file list
280 GetDlgItem(IDC_FILELIST)->SetFocus();
282 if(m_rev2.m_CommitHash.IsEmpty())
283 m_SwitchButton.EnableWindow(FALSE);
285 KillTimer(IDT_INPUT);
286 return FALSE;
289 #if 0
290 svn_error_t* CFileDiffDlg::DiffSummarizeCallback(const CTGitPath& path,
291 svn_client_diff_summarize_kind_t kind,
292 bool propchanged, svn_node_kind_t node)
294 CTGitPath* fd;
295 fd.path = path;
296 fd.kind = kind;
297 fd.node = node;
298 fd.propchanged = propchanged;
299 m_arFileList.push_back(fd);
300 return Git_NO_ERROR;
302 #endif
304 UINT CFileDiffDlg::DiffThreadEntry(LPVOID pVoid)
306 return ((CFileDiffDlg*)pVoid)->DiffThread();
309 UINT CFileDiffDlg::DiffThread()
311 RefreshCursor();
312 m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT)));
313 m_cFileList.DeleteAllItems();
314 m_arFileList.Clear();
315 EnableInputControl(false);
316 #if 0
317 bool bSuccess = true;
318 if (m_bDoPegDiff)
320 // bSuccess = DiffSummarizePeg(m_path1, m_peg, m_rev1, m_rev2, m_depth, m_bIgnoreancestry);
322 else
324 // bSuccess = DiffSummarize(m_path1, m_rev1, m_path2, m_rev2, m_depth, m_bIgnoreancestry);
326 // if (!bSuccess)
327 // {
328 // m_cFileList.ShowText(GetLastErrorMessage());
329 // InterlockedExchange(&m_bThreadRunning, FALSE);
330 // return 0;
331 // }
332 #endif
334 if( m_rev1.m_CommitHash.IsEmpty() || m_rev2.m_CommitHash.IsEmpty())
335 g_Git.RefreshGitIndex();
337 g_Git.GetCommitDiffList(m_rev1.m_CommitHash.ToString(),m_rev2.m_CommitHash.ToString(),m_arFileList);
339 CString sFilterText;
340 m_cFilter.GetWindowText(sFilterText);
341 m_cFileList.SetRedraw(false);
342 Filter(sFilterText);
343 if (m_arFileList.GetCount()>0)
345 // Highlight first entry in file list
346 m_cFileList.SetSelectionMark(0);
347 m_cFileList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
350 int mincol = 0;
351 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
352 int col;
353 for (col = mincol; col <= maxcol; col++)
355 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);
358 m_cFileList.ClearText();
359 m_cFileList.SetRedraw(true);
361 InterlockedExchange(&m_bThreadRunning, FALSE);
362 InvalidateRect(NULL);
363 RefreshCursor();
364 EnableInputControl(true);
365 return 0;
368 int CFileDiffDlg::AddEntry(const CTGitPath * fd)
370 int ret = -1;
371 if (fd)
373 int index = m_cFileList.GetItemCount();
375 int icon_idx = 0;
376 // if (fd->node == svn_node_dir)
377 // icon_idx = m_nIconFolder;
378 // else
380 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(fd->GetGitPathString());
383 ret = m_cFileList.InsertItem(index, fd->GetGitPathString(), icon_idx);
384 m_cFileList.SetItemText(index, 1, ((CTGitPath*)fd)->GetActionName());
385 m_cFileList.SetItemText(index, 2, ((CTGitPath*)fd)->m_StatAdd);
386 m_cFileList.SetItemText(index, 3, ((CTGitPath*)fd)->m_StatDel);
388 return ret;
391 void CFileDiffDlg::EnableInputControl(bool b)
393 this->m_ctrRev1Edit.EnableWindow(b);
394 this->m_ctrRev2Edit.EnableWindow(b);
395 this->m_cRev1Btn.EnableWindow(b);
396 this->m_cRev2Btn.EnableWindow(b);
397 m_cFilter.EnableWindow(b);
398 m_SwitchButton.EnableWindow(b);
401 void CFileDiffDlg::DoDiff(int selIndex, bool blame)
403 CGitDiff diff;
404 CTGitPath* fd = m_arFilteredList[selIndex];
405 diff.Diff(fd, fd,this->m_rev1.m_CommitHash.ToString(), this->m_rev2.m_CommitHash.ToString(), blame, FALSE);
407 #if 0
408 CFileDiffDlg::CTGitPath* fd = m_arFilteredList[selIndex];
410 CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
411 CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
413 if (fd.kind == svn_client_diff_summarize_kind_deleted)
415 if (!PathIsURL(url1))
416 url1 = CTGitPath(GetURLFromPath(m_path1) + _T("/") + fd.path.GetGitPathString());
417 if (!PathIsURL(url2))
418 url2 = m_bDoPegDiff ? url1 : CTGitPath(GetURLFromPath(m_path2) + _T("/") + fd.path.GetGitPathString());
421 if (fd.propchanged)
423 DiffProps(selIndex);
425 if (fd.node == svn_node_dir)
426 return;
428 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path1, m_rev1);
429 CString sTemp;
430 CProgressDlg progDlg;
431 progDlg.SetTitle(IDS_PROGRESSWAIT);
432 progDlg.SetAnimation(IDR_DOWNLOAD);
433 progDlg.ShowModeless(this);
434 progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)m_path1.GetUIPathString());
435 progDlg.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT, (LPCTSTR)m_rev1.ToString());
437 if ((fd.kind != svn_client_diff_summarize_kind_added)&&(!blame)&&(!Cat(url1, m_bDoPegDiff ? m_peg : m_rev1, m_rev1, tempfile)))
439 if ((!m_bDoPegDiff)||(!Cat(url1, m_rev1, m_rev1, tempfile)))
441 CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
442 return;
445 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)))
447 if ((!m_bDoPegDiff)||(!m_blamer.BlameToFile(url1, 1, m_rev1, m_rev1, tempfile, _T(""), TRUE, TRUE)))
449 CMessageBox::Show(NULL, m_blamer.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
450 return;
453 SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
454 progDlg.SetProgress(1, 2);
455 progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)url2.GetUIPathString());
456 progDlg.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT, (LPCTSTR)m_rev2.ToString());
457 CTGitPath tempfile2 = CTempFiles::Instance().GetTempFilePath(false, url2, m_rev2);
458 if ((fd.kind != svn_client_diff_summarize_kind_deleted)&&(!blame)&&(!Cat(url2, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, tempfile2)))
460 if ((!m_bDoPegDiff)||(!Cat(url2, m_rev2, m_rev2, tempfile2)))
462 CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
463 return;
466 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)))
468 if ((!m_bDoPegDiff)||(!m_blamer.BlameToFile(url2, 1, m_rev2, m_rev2, tempfile2, _T(""), TRUE, TRUE)))
470 CMessageBox::Show(NULL, m_blamer.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
471 return;
474 SetFileAttributes(tempfile2.GetWinPath(), FILE_ATTRIBUTE_READONLY);
475 progDlg.SetProgress(2,2);
476 progDlg.Stop();
478 CString rev1name, rev2name;
479 if (m_bDoPegDiff)
481 rev1name.Format(_T("%s Revision %ld"), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev1);
482 rev2name.Format(_T("%s Revision %ld"), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev2);
484 else
486 rev1name = m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString();
487 rev2name = m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString();
489 CAppUtils::DiffFlags flags;
490 flags.AlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
491 flags.Blame(blame);
492 CAppUtils::StartExtDiff(
493 tempfile, tempfile2, rev1name, rev2name, flags);
494 #endif
497 #if 0
498 void CFileDiffDlg::DiffProps(int selIndex)
500 CFileDiffDlg::CTGitPath* fd = m_arFilteredList[selIndex];
502 CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
503 CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
505 GitProperties propsurl1(url1, m_rev1, false);
506 GitProperties propsurl2(url2, m_rev2, false);
508 // collect the properties of both revisions in a set
509 std::set<stdstring> properties;
510 for (int wcindex = 0; wcindex < propsurl1.GetCount(); ++wcindex)
512 stdstring urlname = propsurl1.GetItemName(wcindex);
513 if ( properties.find(urlname) == properties.end() )
515 properties.insert(urlname);
518 for (int wcindex = 0; wcindex < propsurl2.GetCount(); ++wcindex)
520 stdstring urlname = propsurl2.GetItemName(wcindex);
521 if ( properties.find(urlname) == properties.end() )
523 properties.insert(urlname);
527 // iterate over all properties and diff the properties
528 for (std::set<stdstring>::iterator iter = properties.begin(), end = properties.end(); iter != end; ++iter)
530 stdstring url1name = *iter;
532 stdstring url1value = _T(""); // CUnicodeUtils::StdGetUnicode((char *)propsurl1.GetItemValue(wcindex).c_str());
533 for (int url1index = 0; url1index < propsurl1.GetCount(); ++url1index)
535 if (propsurl1.GetItemName(url1index).compare(url1name)==0)
537 url1value = CString((char *)propsurl1.GetItemValue(url1index).c_str());
541 stdstring url2value = _T("");
542 for (int url2index = 0; url2index < propsurl2.GetCount(); ++url2index)
544 if (propsurl2.GetItemName(url2index).compare(url1name)==0)
546 url2value = CString((char *)propsurl2.GetItemValue(url2index).c_str());
550 if (url2value.compare(url1value)!=0)
552 // write both property values to temporary files
553 CTGitPath url1propfile = CTempFiles::Instance().GetTempFilePath(false);
554 CTGitPath url2propfile = CTempFiles::Instance().GetTempFilePath(false);
555 FILE * pFile;
556 _tfopen_s(&pFile, url1propfile.GetWinPath(), _T("wb"));
557 if (pFile)
559 fputs(CUnicodeUtils::StdGetUTF8(url1value).c_str(), pFile);
560 fclose(pFile);
561 FILE * pFile;
562 _tfopen_s(&pFile, url2propfile.GetWinPath(), _T("wb"));
563 if (pFile)
565 fputs(CUnicodeUtils::StdGetUTF8(url2value).c_str(), pFile);
566 fclose(pFile);
568 else
569 return;
571 else
572 return;
573 SetFileAttributes(url1propfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
574 SetFileAttributes(url2propfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
575 CString n1, n2;
576 if (m_rev1.IsWorking())
577 n1.Format(IDS_DIFF_WCNAME, url1name.c_str());
578 if (m_rev1.IsBase())
579 n1.Format(IDS_DIFF_BASENAME, url1name.c_str());
580 if (m_rev1.IsHead() || m_rev1.IsNumber())
582 if (m_bDoPegDiff)
584 n1.Format(_T("%s : %s Revision %ld"), url1name.c_str(), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev1);
586 else
588 CString sTemp = url1name.c_str();
589 sTemp += _T(" : ");
590 n1 = sTemp + m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString();
593 if (m_rev2.IsWorking())
594 n2.Format(IDS_DIFF_WCNAME, url1name.c_str());
595 if (m_rev2.IsBase())
596 n2.Format(IDS_DIFF_BASENAME, url1name.c_str());
597 if (m_rev2.IsHead() || m_rev2.IsNumber())
599 if (m_bDoPegDiff)
601 n2.Format(_T("%s : %s Revision %ld"), url1name.c_str(), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev2);
603 else
605 CString sTemp = url1name.c_str();
606 sTemp += _T(" : ");
607 n2 = sTemp + m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString();
610 CAppUtils::StartExtDiffProps(url1propfile, url2propfile, n1, n2, TRUE);
614 #endif
615 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)
617 *pResult = 0;
618 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
619 int selIndex = pNMLV->iItem;
620 if (selIndex < 0)
621 return;
622 if (selIndex >= (int)m_arFilteredList.size())
623 return;
625 DoDiff(selIndex, m_bBlame);
628 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR *pNMHDR, LRESULT *pResult)
631 LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);
632 if (pGetInfoTip->iItem >= (int)m_arFilteredList.size())
633 return;
635 CString path = m_path1.GetGitPathString() + _T("/") + m_arFilteredList[pGetInfoTip->iItem]->GetGitPathString();
636 if (pGetInfoTip->cchTextMax > path.GetLength())
637 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path, pGetInfoTip->cchTextMax);
639 *pResult = 0;
642 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR *pNMHDR, LRESULT *pResult)
644 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
645 // Take the default processing unless we set this to something else below.
646 *pResult = CDRF_DODEFAULT;
648 // First thing - check the draw stage. If it's the control's prepaint
649 // stage, then tell Windows we want messages for every item.
651 if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
653 *pResult = CDRF_NOTIFYITEMDRAW;
655 else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
657 // This is the prepaint stage for an item. Here's where we set the
658 // item's text color. Our return value will tell Windows to draw the
659 // item itself, but it will use the new color we set here.
661 // Tell Windows to paint the control itself.
662 *pResult = CDRF_DODEFAULT;
664 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
666 if (m_arFilteredList.size() > pLVCD->nmcd.dwItemSpec)
668 CTGitPath * fd = m_arFilteredList[pLVCD->nmcd.dwItemSpec];
669 switch (fd->m_Action)
671 case CTGitPath::LOGACTIONS_ADDED:
672 crText = m_colors.GetColor(CColors::Added);
673 break;
674 case CTGitPath::LOGACTIONS_DELETED:
675 crText = m_colors.GetColor(CColors::Deleted);
676 break;
677 case CTGitPath::LOGACTIONS_MODIFIED:
678 crText = m_colors.GetColor(CColors::Modified);
679 break;
680 //case svn_client_diff_summarize_kind_normal:
681 default:
682 //if (fd.propchanged)
683 crText = m_colors.GetColor(CColors::PropertyChanged);
684 break;
687 // Store the color back in the NMLVCUSTOMDRAW struct.
688 pLVCD->clrText = crText;
692 UINT CFileDiffDlg::LoadRefThread()
694 g_Git.GetBranchList(m_Reflist,NULL,CGit::BRANCH_ALL_F);
695 g_Git.GetTagList(m_Reflist);
697 this->PostMessage(MSG_REF_LOADED);
698 InterlockedExchange(&m_bLoadingRef, FALSE);
699 return 0;
702 void CFileDiffDlg::OnContextMenu(CWnd* pWnd, CPoint point)
704 if ((pWnd==0)||(pWnd != &m_cFileList))
705 return;
706 if (m_cFileList.GetSelectedCount() == 0)
707 return;
708 // if the context menu is invoked through the keyboard, we have to use
709 // a calculated position on where to anchor the menu on
710 if ((point.x == -1) && (point.y == -1))
712 CRect rect;
713 m_cFileList.GetItemRect(m_cFileList.GetSelectionMark(), &rect, LVIR_LABEL);
714 m_cFileList.ClientToScreen(&rect);
715 point = rect.CenterPoint();
717 CIconMenu popup;
718 if (popup.CreatePopupMenu())
720 popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARETWO, IDI_DIFF);
721 popup.AppendMenuIcon(ID_BLAME, IDS_FILEDIFF_POPBLAME, IDI_BLAME);
722 popup.AppendMenuIcon(ID_LOG, IDS_FILEDIFF_LOG, IDI_LOG);
723 popup.AppendMenu(MF_SEPARATOR, NULL);
724 popup.AppendMenuIcon(ID_EXPORT, IDS_FILEDIFF_POPEXPORT, IDI_EXPORT);
725 popup.AppendMenu(MF_SEPARATOR, NULL);
726 popup.AppendMenuIcon(ID_SAVEAS, IDS_FILEDIFF_POPSAVELIST, IDI_SAVEAS);
727 popup.AppendMenuIcon(ID_CLIPBOARD_PATH, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);
728 popup.AppendMenuIcon(ID_CLIPBOARD_ALL, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);
730 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
731 m_bCancelled = false;
732 switch (cmd)
734 case ID_COMPARE:
736 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
737 while (pos)
739 int index = m_cFileList.GetNextSelectedItem(pos);
740 DoDiff(index, false);
743 break;
744 case ID_BLAME:
746 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
747 while (pos)
749 int index = m_cFileList.GetNextSelectedItem(pos);
750 CAppUtils::LaunchTortoiseBlame(m_arFilteredList[index]->GetWinPathString(), m_rev1.m_CommitHash.ToString());
753 break;
754 case ID_LOG:
756 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
757 while (pos)
759 int index = m_cFileList.GetNextSelectedItem(pos);
760 CString cmd;
761 cmd = CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe");
762 cmd += _T(" /command:log");
763 cmd += _T(" /path:\"")+m_arFilteredList[index]->GetWinPathString()+_T("\" ");
764 cmd += _T(" /endrev:")+m_rev1.m_CommitHash.ToString();
765 CAppUtils::LaunchApplication(cmd,IDS_ERR_PROC,false);
768 break;
769 case ID_SAVEAS:
771 if (m_cFileList.GetSelectedCount() > 0)
773 CString temp;
774 CTGitPath savePath;
775 CString pathSave;
776 if (!CAppUtils::FileOpenSave(pathSave, NULL, IDS_REPOBROWSE_SAVEAS, IDS_COMMONFILEFILTER, false, m_hWnd))
778 break;
780 savePath = CTGitPath(pathSave);
782 // now open the selected file for writing
785 CStdioFile file(savePath.GetWinPathString(), CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);
786 // temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, (LPCTSTR)m_path1.GetGitPathString(), (LPCTSTR)m_rev1.ToString(), (LPCTSTR)m_path2.GetGitPathString(), (LPCTSTR)m_rev2.ToString());
787 file.WriteString(temp + _T("\n"));
788 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
789 while (pos)
791 int index = m_cFileList.GetNextSelectedItem(pos);
792 CTGitPath* fd = m_arFilteredList[index];
793 file.WriteString(fd->GetGitPathString());
794 file.WriteString(_T("\n"));
796 file.Close();
798 catch (CFileException* pE)
800 pE->ReportError();
804 break;
805 case ID_CLIPBOARD_PATH:
807 CopySelectionToClipboard();
809 break;
811 case ID_CLIPBOARD_ALL:
813 CopySelectionToClipboard(TRUE);
815 break;
816 case ID_EXPORT:
818 // export all changed files to a folder
819 CBrowseFolder browseFolder;
820 browseFolder.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
821 if (browseFolder.Show(GetSafeHwnd(), m_strExportDir) == CBrowseFolder::OK)
823 m_arSelectedFileList.RemoveAll();
824 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
825 while (pos)
827 int index = m_cFileList.GetNextSelectedItem(pos);
828 CTGitPath* fd = m_arFilteredList[index];
829 #if 0
830 m_arSelectedFileList.Add(fd);
831 #endif
832 // we cannot export directories or folders
833 if (fd->m_Action == CTGitPath::LOGACTIONS_DELETED || fd->IsDirectory())
834 continue;
835 CAppUtils::CreateMultipleDirectory(m_strExportDir + _T("\\") + fd->GetDirectory().GetWinPathString());
836 CString filename = m_strExportDir + _T("\\") + fd->GetWinPathString();
837 if(m_rev1.m_CommitHash.ToString() == GIT_REV_ZERO)
839 if(!CopyFile(g_Git.m_CurrentDir + _T("\\") + fd->GetWinPath(), filename, false))
841 LPVOID lpMsgBuf=NULL;
842 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
843 NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
844 (LPTSTR)&lpMsgBuf,
845 0, NULL);
846 CMessageBox::Show(NULL,(TCHAR *)lpMsgBuf, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
847 LocalFree(lpMsgBuf);
848 return;
851 else
853 if(g_Git.GetOneFile(m_rev1.m_CommitHash, *fd, filename))
855 CString out;
856 out.Format(_T("Fail checkout one file %s;%s"), m_rev1.m_CommitHash.ToString(), fd->GetWinPath());
857 CMessageBox::Show(NULL, out, _T("TortoiseGit"), MB_OK);
858 return;
862 #if 0
863 m_pProgDlg = new CProgressDlg();
864 InterlockedExchange(&m_bThreadRunning, TRUE);
865 if (AfxBeginThread(ExportThreadEntry, this)==NULL)
867 InterlockedExchange(&m_bThreadRunning, FALSE);
868 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
870 #endif
874 break;
880 UINT CFileDiffDlg::ExportThreadEntry(LPVOID pVoid)
882 return ((CFileDiffDlg*)pVoid)->ExportThread();
885 UINT CFileDiffDlg::ExportThread()
887 #if 0
888 RefreshCursor();
889 // if (m_pProgDlg == NULL)
890 // return 1;
891 long count = 0;
892 // SetAndClearProgressInfo(m_pProgDlg, false);
893 m_pProgDlg->SetTitle(IDS_PROGRESSWAIT);
894 m_pProgDlg->SetAnimation(AfxGetResourceHandle(), IDR_DOWNLOAD);
895 m_pProgDlg->ShowModeless(this);
896 for (INT_PTR i=0; (i<m_arSelectedFileList.GetCount())&&(!m_pProgDlg->HasUserCancelled()); ++i)
898 CTGitPath* fd = m_arSelectedFileList[i];
899 // CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
900 // CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());
901 // if ((fd.node == svn_node_dir)&&(fd.kind != svn_client_diff_summarize_kind_added))
902 // {
903 // just create the directory
904 // CreateDirectoryEx(NULL, m_strExportDir+_T("\\")+CPathUtils::PathUnescape(fd.path.GetWinPathString()), NULL);
905 // continue;
906 // }
908 CString sTemp;
909 m_pProgDlg->FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)url1.GetGitPathString());
911 CTGitPath savepath = CTGitPath(m_strExportDir);
912 savepath.AppendPathString(_T("\\") + CPathUtils::PathUnescape(fd.path.GetWinPathString()));
913 CPathUtils::MakeSureDirectoryPathExists(fd.node == svn_node_file ? savepath.GetContainingDirectory().GetWinPath() : savepath.GetDirectory().GetWinPath());
914 if (fd.node == svn_node_dir)
916 // exporting a folder requires calling Git::Export() so we also export all
917 // children of that added folder.
918 if ((fd.kind == svn_client_diff_summarize_kind_added)&&(!Export(url2, savepath, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, true, true)))
920 if ((!m_bDoPegDiff)||(!Export(url2, savepath, m_rev2, m_rev2, true, true)))
922 delete m_pProgDlg;
923 m_pProgDlg = NULL;
924 CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
925 InterlockedExchange(&m_bThreadRunning, FALSE);
926 RefreshCursor();
927 return 1;
931 else
933 // exporting a file requires calling Git::Cat(), since Git::Export() only works
934 // with folders.
935 if ((fd.kind != svn_client_diff_summarize_kind_deleted)&&(!Cat(url2, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, savepath)))
937 if ((!m_bDoPegDiff)||(!Cat(url2, m_rev2, m_rev2, savepath)))
939 delete m_pProgDlg;
940 m_pProgDlg = NULL;
941 CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
942 InterlockedExchange(&m_bThreadRunning, FALSE);
943 RefreshCursor();
944 return 1;
948 count++;
949 m_pProgDlg->SetProgress (count, static_cast<DWORD>(m_arSelectedFileList.GetCount()));
951 m_pProgDlg->Stop();
952 SetAndClearProgressInfo(NULL, false);
953 delete m_pProgDlg;
954 m_pProgDlg = NULL;
955 InterlockedExchange(&m_bThreadRunning, FALSE);
956 RefreshCursor();
957 #endif
958 return 0;
961 BOOL CFileDiffDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
963 if (pWnd != &m_cFileList)
964 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
965 if (m_bThreadRunning == 0)
967 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
968 SetCursor(hCur);
969 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);
971 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
972 SetCursor(hCur);
973 return TRUE;
976 void CFileDiffDlg::OnEnSetfocusFirsturl()
978 GetDlgItem(IDC_FIRSTURL)->HideCaret();
981 void CFileDiffDlg::OnEnSetfocusSecondurl()
983 GetDlgItem(IDC_SECONDURL)->HideCaret();
987 void CFileDiffDlg::OnBnClickedSwitchleftright()
990 if (m_bThreadRunning)
991 return;
993 #if 0
994 CString sFilterString;
995 m_cFilter.GetWindowText(sFilterString);
997 m_cFileList.SetRedraw(false);
998 m_cFileList.DeleteAllItems();
999 for (int i=0; i<(int)m_arFileList.GetCount(); ++i)
1001 CTGitPath fd = m_arFileList[i];
1002 if (fd.m_Action == CTGitPath::LOGACTIONS_ADDED)
1003 fd.m_Action = CTGitPath::LOGACTIONS_DELETED;
1004 else if (fd.m_Action == CTGitPath::LOGACTIONS_DELETED)
1005 fd.m_Action = CTGitPath::LOGACTIONS_ADDED;
1006 std::swap(fd.m_StatAdd, fd.m_StatDel);
1007 (CTGitPath&)m_arFileList[i] = fd;
1009 Filter(sFilterString);
1010 #endif
1012 m_cFileList.SetRedraw(true);
1013 CTGitPath path = m_path1;
1014 m_path1 = m_path2;
1015 m_path2 = path;
1016 GitRev rev = m_rev1;
1017 m_rev1 = m_rev2;
1018 m_rev2 = rev;
1020 CString str1,str2;
1021 this->m_ctrRev1Edit.GetWindowText(str1);
1022 this->m_ctrRev2Edit.GetWindowText(str2);
1024 this->m_ctrRev1Edit.SetWindowText(str2);
1025 this->m_ctrRev2Edit.SetWindowText(str1);
1027 SetURLLabels();
1028 //KillTimer(IDT_INPUT);
1031 void CFileDiffDlg::SetURLLabels(int mask)
1034 // m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.ToString().Left(6));
1035 // m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.ToString().Left(6));
1037 if(mask &0x1)
1039 SetDlgItemText(IDC_FIRSTURL, m_rev1.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev1.GetSubject());
1040 m_tooltips.AddTool(IDC_FIRSTURL,
1041 CAppUtils::FormatDateAndTime( m_rev1.GetAuthorDate(), DATE_SHORTDATE, false )+_T(" ")+m_rev1.GetAuthorName());
1045 if(mask &0x2)
1047 SetDlgItemText(IDC_SECONDURL,m_rev2.m_CommitHash.ToString().Left(8)+_T(": ")+m_rev2.GetSubject());
1049 m_tooltips.AddTool(IDC_SECONDURL,
1050 CAppUtils::FormatDateAndTime( m_rev2.GetAuthorDate(), DATE_SHORTDATE, false )+_T(" ")+m_rev2.GetAuthorName());
1053 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(_T("Version 2 (Base)"));
1054 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(_T("Version 1"));
1056 if( (mask&0x3) == 0x3)
1057 if(m_rev2.GetCommitterDate() > m_rev1.GetCommitterDate())
1059 this->GetDlgItem(IDC_REV2GROUP)->SetWindowText(_T("Version 2 (Base) (Commit Date New)"));
1061 else
1063 this->GetDlgItem(IDC_REV1GROUP)->SetWindowText(_T("Version 1 (Commit Data New)"));
1067 void CFileDiffDlg::ClearURLabels(int mask)
1069 if(mask&0x1)
1071 SetDlgItemText(IDC_FIRSTURL, _T(""));
1072 m_tooltips.AddTool(IDC_FIRSTURL, _T(""));
1075 if(mask&0x2)
1077 SetDlgItemText(IDC_SECONDURL, _T(""));
1078 m_tooltips.AddTool(IDC_SECONDURL, _T(""));
1081 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)
1083 m_tooltips.RelayEvent(pMsg);
1084 if (pMsg->message == WM_KEYDOWN)
1086 switch (pMsg->wParam)
1088 case 'A':
1090 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
1092 // select all entries
1093 for (int i=0; i<m_cFileList.GetItemCount(); ++i)
1095 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
1097 return TRUE;
1100 break;
1101 case 'C':
1102 case VK_INSERT:
1104 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
1106 CopySelectionToClipboard();
1107 return TRUE;
1110 break;
1111 case '\r':
1113 if (GetFocus() == GetDlgItem(IDC_FILELIST))
1115 // Return pressed in file list. Show diff, as for double click
1116 int selIndex = m_cFileList.GetSelectionMark();
1117 if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))
1118 DoDiff(selIndex, m_bBlame);
1119 return TRUE;
1122 break;
1125 return __super::PreTranslateMessage(pMsg);
1128 void CFileDiffDlg::OnCancel()
1130 if (m_bThreadRunning)
1132 m_bCancelled = true;
1133 return;
1135 __super::OnCancel();
1138 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)
1140 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
1141 if (m_bThreadRunning)
1142 return;
1144 if (m_nSortedColumn == phdr->iItem)
1145 m_bAscending = !m_bAscending;
1146 else
1147 m_bAscending = TRUE;
1148 m_nSortedColumn = phdr->iItem;
1149 m_arSelectedFileList.RemoveAll();
1150 Sort();
1152 CString temp;
1153 m_cFileList.SetRedraw(FALSE);
1154 m_cFileList.DeleteAllItems();
1155 m_cFilter.GetWindowText(temp);
1156 Filter(temp);
1158 CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();
1159 HDITEM HeaderItem = {0};
1160 HeaderItem.mask = HDI_FORMAT;
1161 for (int i=0; i<pHeader->GetItemCount(); ++i)
1163 pHeader->GetItem(i, &HeaderItem);
1164 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
1165 pHeader->SetItem(i, &HeaderItem);
1167 pHeader->GetItem(m_nSortedColumn, &HeaderItem);
1168 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);
1169 pHeader->SetItem(m_nSortedColumn, &HeaderItem);
1171 m_cFileList.SetRedraw(TRUE);
1173 *pResult = 0;
1176 void CFileDiffDlg::Sort()
1178 if(m_arFileList.GetCount() < 2)
1180 return;
1183 std::sort(m_arFileList.m_paths.begin(), m_arFileList.m_paths.end(), &CFileDiffDlg::SortCompare);
1186 bool CFileDiffDlg::SortCompare(const CTGitPath& Data1, const CTGitPath& Data2)
1188 int result = 0;
1189 int d1, d2;
1190 switch (m_nSortedColumn)
1192 case 0: //path column
1193 result = Data1.GetWinPathString().Compare(Data2.GetWinPathString());
1194 break;
1195 case 1: //action column
1196 result = Data1.m_Action - Data2.m_Action;
1197 break;
1198 case 2:
1199 d1 = CSorter::A2L(Data1.m_StatAdd);
1200 d2 = CSorter::A2L(Data2.m_StatAdd);
1201 result = d1 - d2;
1202 break;
1203 case 3:
1204 d1 = CSorter::A2L(Data1.m_StatDel);;
1205 d2 = CSorter::A2L(Data2.m_StatDel);
1206 result = d1 - d2;
1207 break;
1208 default:
1209 break;
1212 if (!m_bAscending)
1213 result = -result;
1214 return result < 0;
1218 void CFileDiffDlg::OnBnClickedRev1btn()
1220 ClickRevButton(&this->m_cRev1Btn,&this->m_rev1, &this->m_ctrRev1Edit);
1223 void CFileDiffDlg::ClickRevButton(CMenuButton *button, GitRev *rev, CACEdit *edit)
1225 int entry=button->GetCurrentEntry();
1226 if(entry == 0) /* Browse Refence*/
1229 CString str = CBrowseRefsDlg::PickRef();
1230 if(str.IsEmpty())
1231 return;
1233 if(FillRevFromString(rev,str))
1234 return;
1236 edit->SetWindowText(str);
1240 if(entry == 1) /*Log*/
1242 CLogDlg dlg;
1243 dlg.SetSelect(true);
1244 if(dlg.DoModal() == IDOK)
1246 if( dlg.GetSelectedHash().IsEmpty() )
1247 return;
1249 if(FillRevFromString(rev,dlg.GetSelectedHash()))
1250 return;
1252 edit->SetWindowText(dlg.GetSelectedHash());
1255 else
1256 return;
1259 if(entry == 2) /*RefLog*/
1261 CRefLogDlg dlg;
1262 if(dlg.DoModal() == IDOK)
1264 if(FillRevFromString(rev,dlg.m_SelectedHash))
1265 return;
1267 edit->SetWindowText(dlg.m_SelectedHash);
1270 else
1271 return;
1274 SetURLLabels();
1276 InterlockedExchange(&m_bThreadRunning, TRUE);
1277 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1279 InterlockedExchange(&m_bThreadRunning, FALSE);
1280 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1282 KillTimer(IDT_INPUT);
1285 void CFileDiffDlg::OnBnClickedRev2btn()
1287 ClickRevButton(&this->m_cRev2Btn,&this->m_rev2, &this->m_ctrRev2Edit);
1290 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)
1292 if (m_bThreadRunning)
1294 SetTimer(IDT_FILTER, 1000, NULL);
1295 return 0L;
1298 KillTimer(IDT_FILTER);
1300 m_cFileList.SetRedraw(FALSE);
1301 m_arFilteredList.clear();
1302 m_cFileList.DeleteAllItems();
1304 Filter(_T(""));
1306 m_cFileList.SetRedraw(TRUE);
1307 return 0L;
1310 void CFileDiffDlg::OnEnChangeFilter()
1312 SetTimer(IDT_FILTER, 1000, NULL);
1315 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)
1317 if (m_bThreadRunning)
1318 return;
1320 if( nIDEvent == IDT_FILTER)
1322 CString sFilterText;
1323 KillTimer(IDT_FILTER);
1324 m_cFilter.GetWindowText(sFilterText);
1326 m_cFileList.SetRedraw(FALSE);
1327 m_cFileList.DeleteAllItems();
1329 Filter(sFilterText);
1331 m_cFileList.SetRedraw(TRUE);
1333 __super::OnTimer(nIDEvent);
1336 if( nIDEvent == IDT_INPUT)
1338 KillTimer(IDT_INPUT);
1339 TRACE(_T("Input Timer\r\n"));
1341 GitRev gitrev;
1342 CString str;
1343 int mask = 0;
1344 this->m_ctrRev1Edit.GetWindowText(str);
1345 if( !gitrev.GetCommit(str) )
1347 this->m_rev1=gitrev;
1348 mask |= 0x1;
1351 this->m_ctrRev2Edit.GetWindowText(str);
1353 if( !gitrev.GetCommit(str) )
1355 this->m_rev2=gitrev;
1356 mask |= 0x2;
1359 this->SetURLLabels(mask);
1361 if(mask == 0x3)
1364 InterlockedExchange(&m_bThreadRunning, TRUE);
1365 if (AfxBeginThread(DiffThreadEntry, this)==NULL)
1367 InterlockedExchange(&m_bThreadRunning, FALSE);
1368 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
1374 void CFileDiffDlg::Filter(CString sFilterText)
1376 sFilterText.MakeLower();
1378 m_arFilteredList.clear();
1380 for (int i=0;i<m_arFileList.GetCount();i++)
1382 CString sPath = m_arFileList[i].GetGitPathString();
1383 sPath.MakeLower();
1384 if (sPath.Find(sFilterText) >= 0)
1386 m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));
1389 for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)
1391 AddEntry(*it);
1395 void CFileDiffDlg::CopySelectionToClipboard(BOOL isFull)
1397 // copy all selected paths to the clipboard
1398 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
1399 int index;
1400 CString sTextForClipboard;
1401 while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)
1403 sTextForClipboard += m_cFileList.GetItemText(index, 0);
1404 sTextForClipboard += _T("\t");
1406 if(!isFull)
1408 sTextForClipboard += _T("\r\n");
1411 else
1413 sTextForClipboard += m_cFileList.GetItemText(index, 1);
1414 sTextForClipboard += _T("\t");
1415 sTextForClipboard += m_cFileList.GetItemText(index, 2);
1416 sTextForClipboard += _T("\t");
1417 sTextForClipboard += m_cFileList.GetItemText(index, 3);
1418 sTextForClipboard += _T("\r\n");
1421 CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);
1425 LRESULT CFileDiffDlg::OnRefLoad(WPARAM wParam, LPARAM lParam)
1427 UNREFERENCED_PARAMETER(wParam);
1428 UNREFERENCED_PARAMETER(lParam);
1429 for(int i=0;i<m_Reflist.size();i++)
1431 CString str=m_Reflist[i];
1433 if(str.Find(_T("remotes/")) == 0)
1434 str=str.Mid(8);
1436 m_ctrRev1Edit.AddSearchString(str);
1437 m_ctrRev2Edit.AddSearchString(str);
1439 return 0;
1442 BOOL CFileDiffDlg::DestroyWindow()
1444 return CResizableStandAloneDialog::DestroyWindow();
1447 LRESULT CFileDiffDlg::OnEnUpdate(WPARAM /*wParam*/, LPARAM lParam)
1449 if(lParam == IDC_REV1EDIT)
1451 OnTextUpdate(&this->m_ctrRev1Edit);
1452 ClearURLabels(1);
1454 if(lParam == IDC_REV2EDIT)
1456 OnTextUpdate(&this->m_ctrRev2Edit);
1457 ClearURLabels(1<<1);
1459 return 0;
1462 void CFileDiffDlg::OnTextUpdate(CACEdit * /*pEdit*/)
1464 SetTimer(IDT_INPUT, 1000, NULL);
1465 this->m_cFileList.ShowText(_T("Wait For input validate version"));