OSDN Git Service

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