OSDN Git Service

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