OSDN Git Service

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