OSDN Git Service

Finish compare working copy item at log dialog
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / FileDiffDlg.cpp
1 // TortoiseGit - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseGit\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "UnicodeUtils.h"\r
22 #include "MessageBox.h"\r
23 #include "AppUtils.h"\r
24 #include "TempFile.h"\r
25 #include "ProgressDlg.h"\r
26 #include "SysImageList.h"\r
27 //#include "GitProperties.h"\r
28 #include "StringUtils.h"\r
29 #include "PathUtils.h"\r
30 #include "BrowseFolder.h"\r
31 #include "RevisionDlg.h"\r
32 #include ".\filediffdlg.h"\r
33 #include "gitdiff.h"\r
34 #include "CommonResource.h"\r
35 \r
36 #define ID_COMPARE 1\r
37 #define ID_BLAME 2\r
38 #define ID_SAVEAS 3\r
39 #define ID_EXPORT 4\r
40 #define ID_CLIPBOARD 5\r
41 \r
42 BOOL    CFileDiffDlg::m_bAscending = FALSE;\r
43 int             CFileDiffDlg::m_nSortedColumn = -1;\r
44 \r
45 \r
46 IMPLEMENT_DYNAMIC(CFileDiffDlg, CResizableStandAloneDialog)\r
47 CFileDiffDlg::CFileDiffDlg(CWnd* pParent /*=NULL*/)\r
48         : CResizableStandAloneDialog(CFileDiffDlg::IDD, pParent),\r
49         m_bBlame(false),\r
50         m_pProgDlg(NULL),\r
51         m_bCancelled(false)\r
52 {\r
53 }\r
54 \r
55 CFileDiffDlg::~CFileDiffDlg()\r
56 {\r
57         DestroyIcon(m_hSwitchIcon);\r
58 }\r
59 \r
60 void CFileDiffDlg::DoDataExchange(CDataExchange* pDX)\r
61 {\r
62         CResizableStandAloneDialog::DoDataExchange(pDX);\r
63         DDX_Control(pDX, IDC_FILELIST, m_cFileList);\r
64         DDX_Control(pDX, IDC_SWITCHLEFTRIGHT, m_SwitchButton);\r
65         DDX_Control(pDX, IDC_REV1BTN, m_cRev1Btn);\r
66         DDX_Control(pDX, IDC_REV2BTN, m_cRev2Btn);\r
67         DDX_Control(pDX, IDC_FILTER, m_cFilter);\r
68 }\r
69 \r
70 \r
71 BEGIN_MESSAGE_MAP(CFileDiffDlg, CResizableStandAloneDialog)\r
72         ON_NOTIFY(NM_DBLCLK, IDC_FILELIST, OnNMDblclkFilelist)\r
73         ON_NOTIFY(LVN_GETINFOTIP, IDC_FILELIST, OnLvnGetInfoTipFilelist)\r
74         ON_NOTIFY(NM_CUSTOMDRAW, IDC_FILELIST, OnNMCustomdrawFilelist)\r
75         ON_WM_CONTEXTMENU()\r
76         ON_WM_SETCURSOR()\r
77         ON_EN_SETFOCUS(IDC_SECONDURL, &CFileDiffDlg::OnEnSetfocusSecondurl)\r
78         ON_EN_SETFOCUS(IDC_FIRSTURL, &CFileDiffDlg::OnEnSetfocusFirsturl)\r
79         ON_BN_CLICKED(IDC_SWITCHLEFTRIGHT, &CFileDiffDlg::OnBnClickedSwitchleftright)\r
80         ON_NOTIFY(HDN_ITEMCLICK, 0, &CFileDiffDlg::OnHdnItemclickFilelist)\r
81         ON_BN_CLICKED(IDC_REV1BTN, &CFileDiffDlg::OnBnClickedRev1btn)\r
82         ON_BN_CLICKED(IDC_REV2BTN, &CFileDiffDlg::OnBnClickedRev2btn)\r
83         ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)\r
84         ON_EN_CHANGE(IDC_FILTER, &CFileDiffDlg::OnEnChangeFilter)\r
85         ON_WM_TIMER()\r
86 END_MESSAGE_MAP()\r
87 \r
88 \r
89 void CFileDiffDlg::SetDiff(CTGitPath * path, GitRev rev1, GitRev rev2)\r
90 {\r
91         if(path!=NULL)\r
92         {\r
93                 m_path1 = *path;\r
94                 m_path2 = *path;\r
95         }\r
96         m_rev1 = rev1;\r
97         m_rev2 = rev2;\r
98         \r
99 }\r
100 void CFileDiffDlg::SetDiff(CTGitPath * path, CString &hash1, CString &hash2)\r
101 {\r
102         if(path!=NULL)\r
103         {\r
104                 m_path1 = *path;\r
105                 m_path2 = *path;\r
106         }\r
107         \r
108         BYTE_VECTOR logout;\r
109 \r
110         if(hash1 == GIT_REV_ZERO)\r
111         {\r
112                 m_rev1.m_CommitHash=GIT_REV_ZERO;\r
113                 m_rev1.m_Subject=_T("Working Copy");\r
114         }else\r
115         {\r
116                 g_Git.GetLog(logout,hash1,path,1,0);\r
117                 m_rev1.ParserFromLog(logout);\r
118         }\r
119 \r
120         logout.clear();\r
121 \r
122         if(hash2 == GIT_REV_ZERO)\r
123         {\r
124                 m_rev2.m_CommitHash = GIT_REV_ZERO;\r
125                 m_rev2.m_Subject=_T("Working Copy");\r
126         }else\r
127         {\r
128                 g_Git.GetLog(logout,hash2,path,1,0);\r
129                 m_rev2.ParserFromLog(logout);\r
130         }\r
131 }\r
132 void CFileDiffDlg::SetDiff(CTGitPath * path, GitRev rev1)\r
133 {\r
134         if(path!=NULL)\r
135         {\r
136                 m_path1 = *path;\r
137                 m_path2 = *path;\r
138         }\r
139         m_rev1 = rev1;\r
140         m_rev2.m_CommitHash = _T("");\r
141         m_rev2.m_Subject = _T("Previou Version");\r
142 \r
143         //this->GetDlgItem()->EnableWindow(FALSE);\r
144         \r
145         \r
146 }\r
147 \r
148 BOOL CFileDiffDlg::OnInitDialog()\r
149 {\r
150         CResizableStandAloneDialog::OnInitDialog();\r
151         CString temp;\r
152 \r
153         m_tooltips.Create(this);\r
154         m_tooltips.AddTool(IDC_SWITCHLEFTRIGHT, IDS_FILEDIFF_SWITCHLEFTRIGHT_TT);\r
155 \r
156         m_cFileList.SetRedraw(false);\r
157         m_cFileList.DeleteAllItems();\r
158         DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;\r
159         m_cFileList.SetExtendedStyle(exStyle);\r
160 \r
161         m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();\r
162         m_cFileList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);\r
163 \r
164         m_hSwitchIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_SWITCHLEFTRIGHT), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);\r
165         m_SwitchButton.SetIcon(m_hSwitchIcon);\r
166 \r
167         m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);\r
168         m_cFilter.SetInfoIcon(IDI_FILTEREDIT);\r
169         temp.LoadString(IDS_FILEDIFF_FILTERCUE);\r
170         temp = _T("   ")+temp;\r
171         m_cFilter.SetCueBanner(temp);\r
172 \r
173         int c = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;\r
174         while (c>=0)\r
175                 m_cFileList.DeleteColumn(c--);\r
176 \r
177         \r
178         temp.LoadString(IDS_FILEDIFF_FILE);\r
179         m_cFileList.InsertColumn(0, temp);\r
180         temp.LoadString(IDS_FILEDIFF_ACTION);\r
181         m_cFileList.InsertColumn(1, temp);\r
182 \r
183         temp.LoadString(IDS_FILEDIFF_STATADD);\r
184         m_cFileList.InsertColumn(2, temp);\r
185         temp.LoadString(IDS_FILEDIFF_STATDEL);\r
186         m_cFileList.InsertColumn(3, temp);\r
187         \r
188         int mincol = 0;\r
189         int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;\r
190         int col;\r
191         for (col = mincol; col <= maxcol; col++)\r
192         {\r
193                 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);\r
194         }\r
195         \r
196         m_cFileList.SetRedraw(true);\r
197         \r
198         AddAnchor(IDC_DIFFSTATIC1, TOP_LEFT, TOP_RIGHT);\r
199         AddAnchor(IDC_SWITCHLEFTRIGHT, TOP_RIGHT);\r
200         AddAnchor(IDC_FIRSTURL, TOP_LEFT, TOP_RIGHT);\r
201         AddAnchor(IDC_REV1BTN, TOP_RIGHT);\r
202         AddAnchor(IDC_DIFFSTATIC2, TOP_LEFT, TOP_RIGHT);\r
203         AddAnchor(IDC_SECONDURL, TOP_LEFT, TOP_RIGHT);\r
204         AddAnchor(IDC_REV2BTN, TOP_RIGHT);\r
205         AddAnchor(IDC_FILTER, TOP_LEFT, TOP_RIGHT);\r
206         AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);\r
207         \r
208         SetURLLabels();\r
209 \r
210         EnableSaveRestore(_T("FileDiffDlg"));\r
211 \r
212         InterlockedExchange(&m_bThreadRunning, TRUE);\r
213         if (AfxBeginThread(DiffThreadEntry, this)==NULL)\r
214         {\r
215                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
216                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
217         }\r
218 \r
219         // Start with focus on file list\r
220         GetDlgItem(IDC_FILELIST)->SetFocus();\r
221 \r
222         if(m_rev2.m_CommitHash.IsEmpty())\r
223                 m_SwitchButton.EnableWindow(FALSE);\r
224         return FALSE;\r
225 }\r
226 \r
227 #if 0\r
228 svn_error_t* CFileDiffDlg::DiffSummarizeCallback(const CTGitPath& path, \r
229                                                                                                  svn_client_diff_summarize_kind_t kind, \r
230                                                                                                  bool propchanged, svn_node_kind_t node)\r
231 {\r
232         CTGitPath* fd;\r
233         fd.path = path;\r
234         fd.kind = kind;\r
235         fd.node = node;\r
236         fd.propchanged = propchanged;\r
237         m_arFileList.push_back(fd);\r
238         return Git_NO_ERROR;\r
239 }\r
240 #endif\r
241 \r
242 UINT CFileDiffDlg::DiffThreadEntry(LPVOID pVoid)\r
243 {\r
244         return ((CFileDiffDlg*)pVoid)->DiffThread();\r
245 }\r
246 \r
247 UINT CFileDiffDlg::DiffThread()\r
248 {\r
249         bool bSuccess = true;\r
250         RefreshCursor();\r
251         m_cFileList.ShowText(CString(MAKEINTRESOURCE(IDS_FILEDIFF_WAIT)));\r
252         m_arFileList.Clear();\r
253 #if 0\r
254         if (m_bDoPegDiff)\r
255         {\r
256 //              bSuccess = DiffSummarizePeg(m_path1, m_peg, m_rev1, m_rev2, m_depth, m_bIgnoreancestry);\r
257         }\r
258         else\r
259         {\r
260 //              bSuccess = DiffSummarize(m_path1, m_rev1, m_path2, m_rev2, m_depth, m_bIgnoreancestry);\r
261         }\r
262 //      if (!bSuccess)\r
263 //      {\r
264 //              m_cFileList.ShowText(GetLastErrorMessage());\r
265 //              InterlockedExchange(&m_bThreadRunning, FALSE);\r
266 //              return 0;\r
267 //      }\r
268 #endif\r
269 \r
270         g_Git.GetCommitDiffList(m_rev1.m_CommitHash,m_rev2.m_CommitHash,m_arFileList);\r
271                 \r
272         CString sFilterText;\r
273         m_cFilter.GetWindowText(sFilterText);\r
274         m_cFileList.SetRedraw(false);\r
275         Filter(sFilterText);\r
276         if (m_arFileList.GetCount()>0)\r
277         {\r
278                 // Highlight first entry in file list\r
279                 m_cFileList.SetSelectionMark(0);\r
280                 m_cFileList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
281         }\r
282 \r
283         int mincol = 0;\r
284         int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;\r
285         int col;\r
286         for (col = mincol; col <= maxcol; col++)\r
287         {\r
288                 m_cFileList.SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER);\r
289         }\r
290 \r
291         m_cFileList.ClearText();\r
292         m_cFileList.SetRedraw(true);\r
293 \r
294         InterlockedExchange(&m_bThreadRunning, FALSE);\r
295         InvalidateRect(NULL);\r
296         RefreshCursor();\r
297         return 0;\r
298 }\r
299 \r
300 int CFileDiffDlg::AddEntry(const CTGitPath * fd)\r
301 {\r
302         int ret = -1;\r
303         if (fd)\r
304         {\r
305                 int index = m_cFileList.GetItemCount();\r
306 \r
307                 int icon_idx = 0;\r
308 //              if (fd->node == svn_node_dir)\r
309 //                              icon_idx = m_nIconFolder;\r
310 //              else\r
311                 {\r
312                         icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(fd->GetGitPathString());\r
313                 }\r
314 \r
315                 ret = m_cFileList.InsertItem(index, fd->GetGitPathString(), icon_idx);\r
316                 m_cFileList.SetItemText(index, 1, ((CTGitPath*)fd)->GetActionName());\r
317                 m_cFileList.SetItemText(index, 2, ((CTGitPath*)fd)->m_StatAdd);\r
318                 m_cFileList.SetItemText(index, 3, ((CTGitPath*)fd)->m_StatDel);\r
319         }\r
320         return ret;\r
321 }\r
322 \r
323 void CFileDiffDlg::DoDiff(int selIndex, bool blame)\r
324 {\r
325 \r
326         CGitDiff diff;\r
327         CTGitPath* fd = m_arFilteredList[selIndex];\r
328         diff.Diff(fd, fd,this->m_rev1.m_CommitHash, this->m_rev2.m_CommitHash, blame, FALSE);\r
329 \r
330 #if 0\r
331         CFileDiffDlg::CTGitPath* fd = m_arFilteredList[selIndex];\r
332 \r
333         CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
334         CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
335 \r
336         if (fd.kind == svn_client_diff_summarize_kind_deleted)\r
337         {\r
338                 if (!PathIsURL(url1))\r
339                         url1 = CTGitPath(GetURLFromPath(m_path1) + _T("/") + fd.path.GetGitPathString());\r
340                 if (!PathIsURL(url2))\r
341                         url2 = m_bDoPegDiff ? url1 : CTGitPath(GetURLFromPath(m_path2) + _T("/") + fd.path.GetGitPathString());\r
342         }\r
343 \r
344         if (fd.propchanged)\r
345         {\r
346                 DiffProps(selIndex);\r
347         }\r
348         if (fd.node == svn_node_dir)\r
349                 return;\r
350 \r
351         CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path1, m_rev1);\r
352         CString sTemp;\r
353         CProgressDlg progDlg;\r
354         progDlg.SetTitle(IDS_PROGRESSWAIT);\r
355         progDlg.SetAnimation(IDR_DOWNLOAD);\r
356         progDlg.ShowModeless(this);\r
357         progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)m_path1.GetUIPathString());\r
358         progDlg.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT, (LPCTSTR)m_rev1.ToString());\r
359 \r
360         if ((fd.kind != svn_client_diff_summarize_kind_added)&&(!blame)&&(!Cat(url1, m_bDoPegDiff ? m_peg : m_rev1, m_rev1, tempfile)))\r
361         {\r
362                 if ((!m_bDoPegDiff)||(!Cat(url1, m_rev1, m_rev1, tempfile)))\r
363                 {\r
364                         CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
365                         return;\r
366                 }\r
367         }\r
368         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)))\r
369         {\r
370                 if ((!m_bDoPegDiff)||(!m_blamer.BlameToFile(url1, 1, m_rev1, m_rev1, tempfile, _T(""), TRUE, TRUE)))\r
371                 {\r
372                         CMessageBox::Show(NULL, m_blamer.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
373                         return;\r
374                 }\r
375         }\r
376         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
377         progDlg.SetProgress(1, 2);\r
378         progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)url2.GetUIPathString());\r
379         progDlg.FormatNonPathLine(2, IDS_PROGRESSREVISIONTEXT, (LPCTSTR)m_rev2.ToString());\r
380         CTGitPath tempfile2 = CTempFiles::Instance().GetTempFilePath(false, url2, m_rev2);\r
381         if ((fd.kind != svn_client_diff_summarize_kind_deleted)&&(!blame)&&(!Cat(url2, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, tempfile2)))\r
382         {\r
383                 if ((!m_bDoPegDiff)||(!Cat(url2, m_rev2, m_rev2, tempfile2)))\r
384                 {\r
385                         CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
386                         return;\r
387                 }\r
388         }\r
389         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)))\r
390         {\r
391                 if ((!m_bDoPegDiff)||(!m_blamer.BlameToFile(url2, 1, m_rev2, m_rev2, tempfile2, _T(""), TRUE, TRUE)))\r
392                 {\r
393                         CMessageBox::Show(NULL, m_blamer.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
394                         return;\r
395                 }\r
396         }\r
397         SetFileAttributes(tempfile2.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
398         progDlg.SetProgress(2,2);\r
399         progDlg.Stop();\r
400 \r
401         CString rev1name, rev2name;\r
402         if (m_bDoPegDiff)\r
403         {\r
404                 rev1name.Format(_T("%s Revision %ld"), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev1);\r
405                 rev2name.Format(_T("%s Revision %ld"), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev2);\r
406         }\r
407         else\r
408         {\r
409                 rev1name = m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString();\r
410                 rev2name = m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString();\r
411         }\r
412         CAppUtils::DiffFlags flags;\r
413         flags.AlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
414         flags.Blame(blame);\r
415         CAppUtils::StartExtDiff(\r
416                 tempfile, tempfile2, rev1name, rev2name, flags);\r
417 #endif\r
418 }\r
419 \r
420 #if 0\r
421 void CFileDiffDlg::DiffProps(int selIndex)\r
422 {\r
423         CFileDiffDlg::CTGitPath* fd = m_arFilteredList[selIndex];\r
424 \r
425         CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
426         CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
427 \r
428         GitProperties propsurl1(url1, m_rev1, false);\r
429         GitProperties propsurl2(url2, m_rev2, false);\r
430         \r
431         // collect the properties of both revisions in a set\r
432         std::set<stdstring> properties;\r
433         for (int wcindex = 0; wcindex < propsurl1.GetCount(); ++wcindex)\r
434         {\r
435                 stdstring urlname = propsurl1.GetItemName(wcindex);\r
436                 if ( properties.find(urlname) == properties.end() )\r
437                 {\r
438                         properties.insert(urlname);\r
439                 }\r
440         }\r
441         for (int wcindex = 0; wcindex < propsurl2.GetCount(); ++wcindex)\r
442         {\r
443                 stdstring urlname = propsurl2.GetItemName(wcindex);\r
444                 if ( properties.find(urlname) == properties.end() )\r
445                 {\r
446                         properties.insert(urlname);\r
447                 }\r
448         }\r
449 \r
450         // iterate over all properties and diff the properties\r
451         for (std::set<stdstring>::iterator iter = properties.begin(), end = properties.end(); iter != end; ++iter)\r
452         {\r
453                 stdstring url1name = *iter;\r
454                 \r
455                 stdstring url1value = _T(""); // CUnicodeUtils::StdGetUnicode((char *)propsurl1.GetItemValue(wcindex).c_str());\r
456                 for (int url1index = 0; url1index < propsurl1.GetCount(); ++url1index)\r
457                 {\r
458                         if (propsurl1.GetItemName(url1index).compare(url1name)==0)\r
459                         {\r
460                                 url1value = CString((char *)propsurl1.GetItemValue(url1index).c_str());\r
461                         }\r
462                 }               \r
463                 \r
464                 stdstring url2value = _T("");\r
465                 for (int url2index = 0; url2index < propsurl2.GetCount(); ++url2index)\r
466                 {\r
467                         if (propsurl2.GetItemName(url2index).compare(url1name)==0)\r
468                         {\r
469                                 url2value = CString((char *)propsurl2.GetItemValue(url2index).c_str());\r
470                         }\r
471                 }\r
472 \r
473                 if (url2value.compare(url1value)!=0)\r
474                 {\r
475                         // write both property values to temporary files\r
476                         CTGitPath url1propfile = CTempFiles::Instance().GetTempFilePath(false);\r
477                         CTGitPath url2propfile = CTempFiles::Instance().GetTempFilePath(false);\r
478                         FILE * pFile;\r
479                         _tfopen_s(&pFile, url1propfile.GetWinPath(), _T("wb"));\r
480                         if (pFile)\r
481                         {\r
482                                 fputs(CUnicodeUtils::StdGetUTF8(url1value).c_str(), pFile);\r
483                                 fclose(pFile);\r
484                                 FILE * pFile;\r
485                                 _tfopen_s(&pFile, url2propfile.GetWinPath(), _T("wb"));\r
486                                 if (pFile)\r
487                                 {\r
488                                         fputs(CUnicodeUtils::StdGetUTF8(url2value).c_str(), pFile);\r
489                                         fclose(pFile);\r
490                                 }\r
491                                 else\r
492                                         return;\r
493                         }\r
494                         else\r
495                                 return;\r
496                         SetFileAttributes(url1propfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
497                         SetFileAttributes(url2propfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
498                         CString n1, n2;\r
499                         if (m_rev1.IsWorking())\r
500                                 n1.Format(IDS_DIFF_WCNAME, url1name.c_str());\r
501                         if (m_rev1.IsBase())\r
502                                 n1.Format(IDS_DIFF_BASENAME, url1name.c_str());\r
503                         if (m_rev1.IsHead() || m_rev1.IsNumber())\r
504                         {\r
505                                 if (m_bDoPegDiff)\r
506                                 {\r
507                                         n1.Format(_T("%s : %s Revision %ld"), url1name.c_str(), (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev1);\r
508                                 }\r
509                                 else\r
510                                 {\r
511                                         CString sTemp = url1name.c_str();\r
512                                         sTemp += _T(" : ");\r
513                                         n1 = sTemp + m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString();\r
514                                 }\r
515                         }\r
516                         if (m_rev2.IsWorking())\r
517                                 n2.Format(IDS_DIFF_WCNAME, url1name.c_str());\r
518                         if (m_rev2.IsBase())\r
519                                 n2.Format(IDS_DIFF_BASENAME, url1name.c_str());\r
520                         if (m_rev2.IsHead() || m_rev2.IsNumber())\r
521                         {\r
522                                 if (m_bDoPegDiff)\r
523                                 {\r
524                                         n2.Format(_T("%s : %s Revision %ld"), url1name.c_str(),  (LPCTSTR)fd.path.GetGitPathString(), (LONG)m_rev2);\r
525                                 }\r
526                                 else\r
527                                 {\r
528                                         CString sTemp = url1name.c_str();\r
529                                         sTemp += _T(" : ");\r
530                                         n2 = sTemp + m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString();\r
531                                 }\r
532                         }\r
533                         CAppUtils::StartExtDiffProps(url1propfile, url2propfile, n1, n2, TRUE);\r
534                 }\r
535         }\r
536 }\r
537 #endif\r
538 void CFileDiffDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)\r
539 {\r
540         *pResult = 0;\r
541         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
542         int selIndex = pNMLV->iItem;\r
543         if (selIndex < 0)\r
544                 return;\r
545         if (selIndex >= (int)m_arFilteredList.size())\r
546                 return; \r
547         \r
548         DoDiff(selIndex, m_bBlame);\r
549 }\r
550 \r
551 void CFileDiffDlg::OnLvnGetInfoTipFilelist(NMHDR *pNMHDR, LRESULT *pResult)\r
552 {\r
553 \r
554         LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);\r
555         if (pGetInfoTip->iItem >= (int)m_arFilteredList.size())\r
556                 return;\r
557 \r
558         CString path = m_path1.GetGitPathString() + _T("/") + m_arFilteredList[pGetInfoTip->iItem]->GetGitPathString();\r
559         if (pGetInfoTip->cchTextMax > path.GetLength())\r
560                         _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path, pGetInfoTip->cchTextMax);\r
561 \r
562         *pResult = 0;\r
563 }\r
564 \r
565 void CFileDiffDlg::OnNMCustomdrawFilelist(NMHDR *pNMHDR, LRESULT *pResult)\r
566 {\r
567         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
568         // Take the default processing unless we set this to something else below.\r
569         *pResult = CDRF_DODEFAULT;\r
570 \r
571         // First thing - check the draw stage. If it's the control's prepaint\r
572         // stage, then tell Windows we want messages for every item.\r
573 \r
574         if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )\r
575         {\r
576                 *pResult = CDRF_NOTIFYITEMDRAW;\r
577         }\r
578         else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )\r
579         {\r
580                 // This is the prepaint stage for an item. Here's where we set the\r
581                 // item's text color. Our return value will tell Windows to draw the\r
582                 // item itself, but it will use the new color we set here.\r
583 \r
584                 // Tell Windows to paint the control itself.\r
585                 *pResult = CDRF_DODEFAULT;\r
586 \r
587                 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
588 \r
589                 if (m_arFilteredList.size() > pLVCD->nmcd.dwItemSpec)\r
590                 {\r
591                         CTGitPath * fd = m_arFilteredList[pLVCD->nmcd.dwItemSpec];\r
592                         switch (fd->m_Action)\r
593                         {\r
594                         case CTGitPath::LOGACTIONS_ADDED:\r
595                                 crText = m_colors.GetColor(CColors::Added);\r
596                                 break;\r
597                         case CTGitPath::LOGACTIONS_DELETED:\r
598                                 crText = m_colors.GetColor(CColors::Deleted);\r
599                                 break;\r
600                         case CTGitPath::LOGACTIONS_MODIFIED:\r
601                                 crText = m_colors.GetColor(CColors::Modified);\r
602                                 break;\r
603                         //case svn_client_diff_summarize_kind_normal:\r
604                         default:\r
605                         //if (fd.propchanged)\r
606                                 crText = m_colors.GetColor(CColors::PropertyChanged);\r
607                                 break;\r
608                         }\r
609                 }\r
610                 // Store the color back in the NMLVCUSTOMDRAW struct.\r
611                 pLVCD->clrText = crText;\r
612         }\r
613 }\r
614 \r
615 void CFileDiffDlg::OnContextMenu(CWnd* pWnd, CPoint point)\r
616 {\r
617         if ((pWnd==0)||(pWnd != &m_cFileList))\r
618                 return;\r
619         if (m_cFileList.GetSelectedCount() == 0)\r
620                 return;\r
621         // if the context menu is invoked through the keyboard, we have to use\r
622         // a calculated position on where to anchor the menu on\r
623         if ((point.x == -1) && (point.y == -1))\r
624         {\r
625                 CRect rect;\r
626                 m_cFileList.GetItemRect(m_cFileList.GetSelectionMark(), &rect, LVIR_LABEL);\r
627                 m_cFileList.ClientToScreen(&rect);\r
628                 point = rect.CenterPoint();\r
629         }\r
630         CMenu popup;\r
631         if (popup.CreatePopupMenu())\r
632         {\r
633                 CString temp;\r
634                 temp.LoadString(IDS_LOG_POPUP_COMPARETWO);\r
635                 popup.AppendMenu(MF_STRING | MF_ENABLED, ID_COMPARE, temp);\r
636                 temp.LoadString(IDS_FILEDIFF_POPBLAME);\r
637                 //popup.AppendMenu(MF_STRING | MF_ENABLED, ID_BLAME, temp);\r
638                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
639                 temp.LoadString(IDS_FILEDIFF_POPSAVELIST);\r
640                 popup.AppendMenu(MF_STRING | MF_ENABLED, ID_SAVEAS, temp);\r
641                 temp.LoadString(IDS_FILEDIFF_POPCLIPBOARD);\r
642                 popup.AppendMenu(MF_STRING | MF_ENABLED, ID_CLIPBOARD, temp);\r
643                 temp.LoadString(IDS_FILEDIFF_POPEXPORT);\r
644                 //popup.AppendMenu(MF_STRING | MF_ENABLED, ID_EXPORT, temp);\r
645                 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
646                 m_bCancelled = false;\r
647                 switch (cmd)\r
648                 {\r
649                 case ID_COMPARE:\r
650                         {\r
651                                 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
652                                 while (pos)\r
653                                 {\r
654                                         int index = m_cFileList.GetNextSelectedItem(pos);\r
655                                         DoDiff(index, false);\r
656                                 }                                       \r
657                         }\r
658                         break;\r
659                 case ID_BLAME:\r
660                         {\r
661                                 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
662                                 while (pos)\r
663                                 {\r
664                                         int index = m_cFileList.GetNextSelectedItem(pos);\r
665                                         DoDiff(index, true);\r
666                                 }                                       \r
667                         }\r
668                         break;\r
669                 case ID_SAVEAS:\r
670                         {\r
671                                 if (m_cFileList.GetSelectedCount() > 0)\r
672                                 {\r
673                                         CString temp;\r
674                                         CTGitPath savePath;\r
675                                         CString pathSave;\r
676                                         if (!CAppUtils::FileOpenSave(pathSave, NULL, IDS_REPOBROWSE_SAVEAS, IDS_COMMONFILEFILTER, false, m_hWnd))\r
677                                         {\r
678                                                 break;\r
679                                         }\r
680                                         savePath = CTGitPath(pathSave);\r
681 \r
682                                         // now open the selected file for writing\r
683                                         try\r
684                                         {\r
685                                                 CStdioFile file(savePath.GetWinPathString(), CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);\r
686 //                                              temp.Format(IDS_FILEDIFF_CHANGEDLISTINTRO, (LPCTSTR)m_path1.GetGitPathString(), (LPCTSTR)m_rev1.ToString(), (LPCTSTR)m_path2.GetGitPathString(), (LPCTSTR)m_rev2.ToString());\r
687                                                 file.WriteString(temp + _T("\n"));\r
688                                                 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
689                                                 while (pos)\r
690                                                 {\r
691                                                         int index = m_cFileList.GetNextSelectedItem(pos);\r
692                                                         CTGitPath* fd = m_arFilteredList[index];\r
693                                                         file.WriteString(fd->GetGitPathString());\r
694                                                         file.WriteString(_T("\n"));\r
695                                                 }\r
696                                                 file.Close();\r
697                                         } \r
698                                         catch (CFileException* pE)\r
699                                         {\r
700                                                 pE->ReportError();\r
701                                         }\r
702                                 }\r
703                         }\r
704                         break;\r
705                 case ID_CLIPBOARD:\r
706                         {\r
707                                 CopySelectionToClipboard();\r
708                         }\r
709                         break;\r
710                 case ID_EXPORT:\r
711                         {\r
712 #if 0 //this funcation seem no useful\r
713                                 // export all changed files to a folder\r
714                                 CBrowseFolder browseFolder;\r
715                                 browseFolder.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
716                                 if (browseFolder.Show(GetSafeHwnd(), m_strExportDir) == CBrowseFolder::OK) \r
717                                 {\r
718                                         m_arSelectedFileList.RemoveAll();\r
719                                         POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
720                                         while (pos)\r
721                                         {\r
722                                                 int index = m_cFileList.GetNextSelectedItem(pos);\r
723                                                 CTGitPath* fd = m_arFilteredList[index];\r
724                                                 m_arSelectedFileList.Add(fd);\r
725                                         }\r
726                                         m_pProgDlg = new CProgressDlg();\r
727                                         InterlockedExchange(&m_bThreadRunning, TRUE);\r
728                                         if (AfxBeginThread(ExportThreadEntry, this)==NULL)\r
729                                         {\r
730                                                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
731                                                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
732                                         }\r
733                                 }\r
734 #endif;                         \r
735                         }\r
736 \r
737                         break;\r
738 \r
739                 }\r
740         }\r
741 }\r
742 \r
743 UINT CFileDiffDlg::ExportThreadEntry(LPVOID pVoid)\r
744 {\r
745         return ((CFileDiffDlg*)pVoid)->ExportThread();\r
746 }\r
747 \r
748 UINT CFileDiffDlg::ExportThread()\r
749 {\r
750 #if 0\r
751         RefreshCursor();\r
752 //      if (m_pProgDlg == NULL)\r
753 //              return 1;\r
754         long count = 0;\r
755 //      SetAndClearProgressInfo(m_pProgDlg, false);\r
756         m_pProgDlg->SetTitle(IDS_PROGRESSWAIT);\r
757         m_pProgDlg->SetAnimation(AfxGetResourceHandle(), IDR_DOWNLOAD);\r
758         m_pProgDlg->ShowModeless(this);\r
759         for (INT_PTR i=0; (i<m_arSelectedFileList.GetCount())&&(!m_pProgDlg->HasUserCancelled()); ++i)\r
760         {\r
761                 CTGitPath* fd = m_arSelectedFileList[i];\r
762 //              CTGitPath url1 = CTGitPath(m_path1.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
763 //              CTGitPath url2 = m_bDoPegDiff ? url1 : CTGitPath(m_path2.GetGitPathString() + _T("/") + fd.path.GetGitPathString());\r
764 //              if ((fd.node == svn_node_dir)&&(fd.kind != svn_client_diff_summarize_kind_added))\r
765 //              {\r
766                         // just create the directory\r
767 //                      CreateDirectoryEx(NULL, m_strExportDir+_T("\\")+CPathUtils::PathUnescape(fd.path.GetWinPathString()), NULL);\r
768 //                      continue;\r
769 //              }\r
770 \r
771                 CString sTemp;\r
772                 m_pProgDlg->FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)url1.GetGitPathString());\r
773 \r
774                 CTGitPath savepath = CTGitPath(m_strExportDir);\r
775                 savepath.AppendPathString(_T("\\") + CPathUtils::PathUnescape(fd.path.GetWinPathString()));\r
776                 CPathUtils::MakeSureDirectoryPathExists(fd.node == svn_node_file ? savepath.GetContainingDirectory().GetWinPath() : savepath.GetDirectory().GetWinPath());\r
777                 if (fd.node == svn_node_dir)\r
778                 {\r
779                         // exporting a folder requires calling Git::Export() so we also export all\r
780                         // children of that added folder.\r
781                         if ((fd.kind == svn_client_diff_summarize_kind_added)&&(!Export(url2, savepath, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, true, true)))\r
782                         {\r
783                                 if ((!m_bDoPegDiff)||(!Export(url2, savepath, m_rev2, m_rev2, true, true)))\r
784                                 {\r
785                                         delete m_pProgDlg;\r
786                                         m_pProgDlg = NULL;\r
787                                         CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
788                                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
789                                         RefreshCursor();\r
790                                         return 1;\r
791                                 }\r
792                         }\r
793                 }\r
794                 else\r
795                 {\r
796                         // exporting a file requires calling Git::Cat(), since Git::Export() only works\r
797                         // with folders.\r
798                         if ((fd.kind != svn_client_diff_summarize_kind_deleted)&&(!Cat(url2, m_bDoPegDiff ? m_peg : m_rev2, m_rev2, savepath)))\r
799                         {\r
800                                 if ((!m_bDoPegDiff)||(!Cat(url2, m_rev2, m_rev2, savepath)))\r
801                                 {\r
802                                         delete m_pProgDlg;\r
803                                         m_pProgDlg = NULL;\r
804                                         CMessageBox::Show(NULL, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
805                                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
806                                         RefreshCursor();\r
807                                         return 1;\r
808                                 }\r
809                         }\r
810                 }\r
811                 count++;\r
812                 m_pProgDlg->SetProgress (count, static_cast<DWORD>(m_arSelectedFileList.GetCount()));\r
813         }                                       \r
814         m_pProgDlg->Stop();\r
815         SetAndClearProgressInfo(NULL, false);\r
816         delete m_pProgDlg;\r
817         m_pProgDlg = NULL;\r
818         InterlockedExchange(&m_bThreadRunning, FALSE);\r
819         RefreshCursor();\r
820 #endif\r
821         return 0;\r
822 }\r
823 \r
824 BOOL CFileDiffDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
825 {\r
826         if (pWnd != &m_cFileList)\r
827                 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);\r
828         if (m_bThreadRunning == 0)\r
829         {\r
830                 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
831                 SetCursor(hCur);\r
832                 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);\r
833         }\r
834         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
835         SetCursor(hCur);\r
836         return TRUE;\r
837 }\r
838 \r
839 void CFileDiffDlg::OnEnSetfocusFirsturl()\r
840 {\r
841         GetDlgItem(IDC_FIRSTURL)->HideCaret();\r
842 }\r
843 \r
844 void CFileDiffDlg::OnEnSetfocusSecondurl()\r
845 {\r
846         GetDlgItem(IDC_SECONDURL)->HideCaret();\r
847 }\r
848 \r
849 \r
850 void CFileDiffDlg::OnBnClickedSwitchleftright()\r
851 {\r
852 \r
853         if (m_bThreadRunning)\r
854                 return;\r
855         CString sFilterString;\r
856         m_cFilter.GetWindowText(sFilterString);\r
857 \r
858         m_cFileList.SetRedraw(false);\r
859         m_cFileList.DeleteAllItems();\r
860         for (int i=0; i<(int)m_arFileList.GetCount(); ++i)\r
861         {\r
862                 CTGitPath fd = m_arFileList[i];\r
863                 if (fd.m_Action == CTGitPath::LOGACTIONS_ADDED)\r
864                         fd.m_Action = CTGitPath::LOGACTIONS_DELETED;\r
865                 else if (fd.m_Action == CTGitPath::LOGACTIONS_DELETED)\r
866                         fd.m_Action = CTGitPath::LOGACTIONS_ADDED;\r
867                 std::swap(fd.m_StatAdd, fd.m_StatDel);\r
868                 (CTGitPath&)m_arFileList[i] = fd;\r
869         }\r
870         Filter(sFilterString);\r
871 \r
872         m_cFileList.SetRedraw(true);\r
873         CTGitPath path = m_path1;\r
874         m_path1 = m_path2;\r
875         m_path2 = path;\r
876         GitRev rev = m_rev1;\r
877         m_rev1 = m_rev2;\r
878         m_rev2 = rev;\r
879         SetURLLabels();\r
880 \r
881 }\r
882 \r
883 void CFileDiffDlg::SetURLLabels()\r
884 {\r
885 \r
886         m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.Left(6));\r
887         m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.Left(6));\r
888 \r
889         SetDlgItemText(IDC_FIRSTURL, m_rev1.m_Subject+CString(_T("\r\n"))+m_rev1.m_CommitHash);\r
890         SetDlgItemText(IDC_SECONDURL,m_rev2.m_Subject+CString(_T("\r\n"))+m_rev2.m_CommitHash);\r
891 \r
892         m_tooltips.AddTool(IDC_FIRSTURL,  \r
893                 CAppUtils::FormatDateAndTime( m_rev1.m_AuthorDate, DATE_SHORTDATE, false )+_T("  ")+m_rev1.m_AuthorName);\r
894         m_tooltips.AddTool(IDC_SECONDURL, \r
895                 CAppUtils::FormatDateAndTime( m_rev2.m_AuthorDate, DATE_SHORTDATE, false )+_T("  ")+m_rev2.m_AuthorName);\r
896 \r
897 }\r
898 \r
899 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)\r
900 {\r
901         m_tooltips.RelayEvent(pMsg);\r
902         if (pMsg->message == WM_KEYDOWN)\r
903         {\r
904                 switch (pMsg->wParam)\r
905                 {\r
906                 case 'A':\r
907                         {\r
908                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
909                                 {\r
910                                         // select all entries\r
911                                         for (int i=0; i<m_cFileList.GetItemCount(); ++i)\r
912                                         {\r
913                                                 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
914                                         }\r
915                                         return TRUE;\r
916                                 }\r
917                         }\r
918                         break;\r
919                 case 'C':\r
920                 case VK_INSERT:\r
921                         {\r
922                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
923                                 {\r
924                                         CopySelectionToClipboard();\r
925                                         return TRUE;\r
926                                 }\r
927                         }\r
928                         break;\r
929                 case '\r':\r
930                         {\r
931                                 if (GetFocus() == GetDlgItem(IDC_FILELIST))\r
932                                 {\r
933                                         // Return pressed in file list. Show diff, as for double click\r
934                                         int selIndex = m_cFileList.GetSelectionMark();\r
935                                         if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))\r
936                                                 DoDiff(selIndex, m_bBlame);\r
937                                         return TRUE;\r
938                                 }\r
939                         }\r
940                         break;\r
941                 }\r
942         }\r
943         return __super::PreTranslateMessage(pMsg);\r
944 }\r
945 \r
946 void CFileDiffDlg::OnCancel()\r
947 {\r
948         if (m_bThreadRunning)\r
949         {\r
950                 m_bCancelled = true;\r
951                 return;\r
952         }\r
953         __super::OnCancel();\r
954 }\r
955 \r
956 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)\r
957 {\r
958         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
959         if (m_bThreadRunning)\r
960                 return;\r
961 \r
962         if (m_nSortedColumn == phdr->iItem)\r
963                 m_bAscending = !m_bAscending;\r
964         else\r
965                 m_bAscending = TRUE;\r
966         m_nSortedColumn = phdr->iItem;\r
967         m_arSelectedFileList.RemoveAll();\r
968         Sort();\r
969 \r
970         CString temp;\r
971         m_cFileList.SetRedraw(FALSE);\r
972         m_cFileList.DeleteAllItems();\r
973         m_cFilter.GetWindowText(temp);\r
974         Filter(temp);\r
975 \r
976         CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();\r
977         HDITEM HeaderItem = {0};\r
978         HeaderItem.mask = HDI_FORMAT;\r
979         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
980         {\r
981                 pHeader->GetItem(i, &HeaderItem);\r
982                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
983                 pHeader->SetItem(i, &HeaderItem);\r
984         }\r
985         pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
986         HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
987         pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
988 \r
989         m_cFileList.SetRedraw(TRUE);\r
990 \r
991         *pResult = 0;\r
992 }\r
993 \r
994 void CFileDiffDlg::Sort()\r
995 {\r
996         if(m_arFileList.GetCount() < 2)\r
997         {\r
998                 return;\r
999         }\r
1000 \r
1001 //      std::sort(m_arFileList.begin(), m_arFileList.end(), &CFileDiffDlg::SortCompare);\r
1002 }\r
1003 #if 0\r
1004 bool CFileDiffDlg::SortCompare(const CTGitPath*& Data1, const CTGitPath*& Data2)\r
1005 {\r
1006         int result = 0;\r
1007         switch (m_nSortedColumn)\r
1008         {\r
1009         case 0:         //path column\r
1010                 result = Data1.path.GetWinPathString().Compare(Data2.path.GetWinPathString());\r
1011                 break;\r
1012         case 1:         //action column\r
1013                 result = Data1.kind - Data2.kind;\r
1014                 break;\r
1015         default:\r
1016                 break;\r
1017         }\r
1018 \r
1019         if (!m_bAscending)\r
1020                 result = -result;\r
1021         return result < 0;\r
1022 }\r
1023 #endif\r
1024 \r
1025 void CFileDiffDlg::OnBnClickedRev1btn()\r
1026 {\r
1027 #if 0\r
1028         if (m_bThreadRunning)\r
1029                 return; // do nothing as long as the thread is still running\r
1030 \r
1031         // show a dialog where the user can enter a revision\r
1032         CRevisionDlg dlg(this);\r
1033         dlg.AllowWCRevs(false);\r
1034         *((GitRev*)&dlg) = m_rev1;\r
1035 \r
1036         if (dlg.DoModal() == IDOK)\r
1037         {\r
1038                 m_rev1 = dlg;\r
1039                 m_cRev1Btn.SetWindowText(m_rev1.ToString());\r
1040                 m_cFileList.DeleteAllItems();\r
1041                 // start a new thread to re-fetch the diff\r
1042                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
1043                 if (AfxBeginThread(DiffThreadEntry, this)==NULL)\r
1044                 {\r
1045                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1046                         CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1047                 }\r
1048         }\r
1049 #endif\r
1050 }\r
1051 \r
1052 void CFileDiffDlg::OnBnClickedRev2btn()\r
1053 {\r
1054 #if 0\r
1055         if (m_bThreadRunning)\r
1056                 return; // do nothing as long as the thread is still running\r
1057 \r
1058         // show a dialog where the user can enter a revision\r
1059         CRevisionDlg dlg(this);\r
1060         dlg.AllowWCRevs(false);\r
1061         *((GitRev*)&dlg) = m_rev2;\r
1062 \r
1063         if (dlg.DoModal() == IDOK)\r
1064         {\r
1065                 m_rev2 = dlg;\r
1066                 m_cRev2Btn.SetWindowText(m_rev2.ToString());\r
1067                 m_cFileList.DeleteAllItems();\r
1068                 // start a new thread to re-fetch the diff\r
1069                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
1070                 if (AfxBeginThread(DiffThreadEntry, this)==NULL)\r
1071                 {\r
1072                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1073                         CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1074                 }\r
1075         }\r
1076 #endif\r
1077 }\r
1078 \r
1079 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)\r
1080 {\r
1081         if (m_bThreadRunning)\r
1082         {\r
1083                 SetTimer(IDT_FILTER, 1000, NULL);\r
1084                 return 0L;\r
1085         }\r
1086 \r
1087         KillTimer(IDT_FILTER);\r
1088 \r
1089         m_cFileList.SetRedraw(FALSE);\r
1090         m_arFilteredList.clear();\r
1091         m_cFileList.DeleteAllItems();\r
1092 \r
1093         Filter(_T(""));\r
1094 \r
1095         m_cFileList.SetRedraw(TRUE);\r
1096         return 0L;\r
1097 }\r
1098 \r
1099 void CFileDiffDlg::OnEnChangeFilter()\r
1100 {\r
1101         SetTimer(IDT_FILTER, 1000, NULL);\r
1102 }\r
1103 \r
1104 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)\r
1105 {\r
1106         if (m_bThreadRunning)\r
1107                 return;\r
1108 \r
1109         CString sFilterText;\r
1110         KillTimer(IDT_FILTER);\r
1111         m_cFilter.GetWindowText(sFilterText);\r
1112 \r
1113         m_cFileList.SetRedraw(FALSE);\r
1114         m_cFileList.DeleteAllItems();\r
1115 \r
1116         Filter(sFilterText);\r
1117 \r
1118         m_cFileList.SetRedraw(TRUE);\r
1119 \r
1120         __super::OnTimer(nIDEvent);\r
1121 }\r
1122 \r
1123 void CFileDiffDlg::Filter(CString sFilterText)\r
1124 {\r
1125 \r
1126         sFilterText.MakeLower();\r
1127 \r
1128         m_arFilteredList.clear();\r
1129         \r
1130         for (int i=0;i<m_arFileList.GetCount();i++)\r
1131         {\r
1132                 CString sPath = m_arFileList[i].GetGitPathString();\r
1133                 sPath.MakeLower();\r
1134                 if (sPath.Find(sFilterText) >= 0)\r
1135                 {\r
1136                         m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));\r
1137                 }\r
1138         }\r
1139         for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)\r
1140         {\r
1141                 AddEntry(*it);\r
1142         }\r
1143 \r
1144 }\r
1145 \r
1146 void CFileDiffDlg::CopySelectionToClipboard()\r
1147 {\r
1148         // copy all selected paths to the clipboard\r
1149         POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
1150         int index;\r
1151         CString sTextForClipboard;\r
1152         while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)\r
1153         {\r
1154                 sTextForClipboard += m_cFileList.GetItemText(index, 0);\r
1155                 sTextForClipboard += _T("\t");\r
1156                 sTextForClipboard += m_cFileList.GetItemText(index, 1);\r
1157                 sTextForClipboard += _T("\r\n");\r
1158         }\r
1159         CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);\r
1160 }\r
1161 \r