OSDN Git Service

Fix FileDiffDlg ToolTip show error time info problem
[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"),rev1,m_rev2.m_CommitHash);\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                 ( CTGitPath)m_arFileList[i] = ( CTGitPath)fd;\r
869         }\r
870         Filter(sFilterString);\r
871 \r
872         m_cFileList.SetRedraw(true);\r
873         CTGitPath path = m_path1;\r
874         m_path1 = m_path2;\r
875         m_path2 = path;\r
876         GitRev rev = m_rev1;\r
877         m_rev1 = m_rev2;\r
878         m_rev2 = rev;\r
879         SetURLLabels();\r
880 \r
881 }\r
882 \r
883 void CFileDiffDlg::SetURLLabels()\r
884 {\r
885 \r
886         m_cRev1Btn.SetWindowText(m_rev1.m_CommitHash.Left(6));\r
887         m_cRev2Btn.SetWindowText(m_rev2.m_CommitHash.Left(6));\r
888 \r
889         SetDlgItemText(IDC_FIRSTURL, m_rev1.m_Subject+CString(_T("\r\n"))+m_rev1.m_CommitHash);\r
890         SetDlgItemText(IDC_SECONDURL,m_rev2.m_Subject+CString(_T("\r\n"))+m_rev2.m_CommitHash);\r
891 \r
892         m_tooltips.AddTool(IDC_FIRSTURL,  m_rev1.m_AuthorDate.Format(_T("%Y-%m-%d  "))+m_rev1.m_AuthorName);\r
893         m_tooltips.AddTool(IDC_SECONDURL, m_rev2.m_AuthorDate.Format(_T("%Y-%m-%d  "))+m_rev2.m_AuthorName);\r
894 \r
895 }\r
896 \r
897 BOOL CFileDiffDlg::PreTranslateMessage(MSG* pMsg)\r
898 {\r
899         m_tooltips.RelayEvent(pMsg);\r
900         if (pMsg->message == WM_KEYDOWN)\r
901         {\r
902                 switch (pMsg->wParam)\r
903                 {\r
904                 case 'A':\r
905                         {\r
906                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
907                                 {\r
908                                         // select all entries\r
909                                         for (int i=0; i<m_cFileList.GetItemCount(); ++i)\r
910                                         {\r
911                                                 m_cFileList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
912                                         }\r
913                                         return TRUE;\r
914                                 }\r
915                         }\r
916                         break;\r
917                 case 'C':\r
918                 case VK_INSERT:\r
919                         {\r
920                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
921                                 {\r
922                                         CopySelectionToClipboard();\r
923                                         return TRUE;\r
924                                 }\r
925                         }\r
926                         break;\r
927                 case '\r':\r
928                         {\r
929                                 if (GetFocus() == GetDlgItem(IDC_FILELIST))\r
930                                 {\r
931                                         // Return pressed in file list. Show diff, as for double click\r
932                                         int selIndex = m_cFileList.GetSelectionMark();\r
933                                         if ((selIndex >= 0) && (selIndex < (int)m_arFileList.GetCount()))\r
934                                                 DoDiff(selIndex, m_bBlame);\r
935                                         return TRUE;\r
936                                 }\r
937                         }\r
938                         break;\r
939                 }\r
940         }\r
941         return __super::PreTranslateMessage(pMsg);\r
942 }\r
943 \r
944 void CFileDiffDlg::OnCancel()\r
945 {\r
946         if (m_bThreadRunning)\r
947         {\r
948                 m_bCancelled = true;\r
949                 return;\r
950         }\r
951         __super::OnCancel();\r
952 }\r
953 \r
954 void CFileDiffDlg::OnHdnItemclickFilelist(NMHDR *pNMHDR, LRESULT *pResult)\r
955 {\r
956         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
957         if (m_bThreadRunning)\r
958                 return;\r
959 \r
960         if (m_nSortedColumn == phdr->iItem)\r
961                 m_bAscending = !m_bAscending;\r
962         else\r
963                 m_bAscending = TRUE;\r
964         m_nSortedColumn = phdr->iItem;\r
965         m_arSelectedFileList.RemoveAll();\r
966         Sort();\r
967 \r
968         CString temp;\r
969         m_cFileList.SetRedraw(FALSE);\r
970         m_cFileList.DeleteAllItems();\r
971         m_cFilter.GetWindowText(temp);\r
972         Filter(temp);\r
973 \r
974         CHeaderCtrl * pHeader = m_cFileList.GetHeaderCtrl();\r
975         HDITEM HeaderItem = {0};\r
976         HeaderItem.mask = HDI_FORMAT;\r
977         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
978         {\r
979                 pHeader->GetItem(i, &HeaderItem);\r
980                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
981                 pHeader->SetItem(i, &HeaderItem);\r
982         }\r
983         pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
984         HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
985         pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
986 \r
987         m_cFileList.SetRedraw(TRUE);\r
988 \r
989         *pResult = 0;\r
990 }\r
991 \r
992 void CFileDiffDlg::Sort()\r
993 {\r
994         if(m_arFileList.GetCount() < 2)\r
995         {\r
996                 return;\r
997         }\r
998 \r
999 //      std::sort(m_arFileList.begin(), m_arFileList.end(), &CFileDiffDlg::SortCompare);\r
1000 }\r
1001 #if 0\r
1002 bool CFileDiffDlg::SortCompare(const CTGitPath*& Data1, const CTGitPath*& Data2)\r
1003 {\r
1004         int result = 0;\r
1005         switch (m_nSortedColumn)\r
1006         {\r
1007         case 0:         //path column\r
1008                 result = Data1.path.GetWinPathString().Compare(Data2.path.GetWinPathString());\r
1009                 break;\r
1010         case 1:         //action column\r
1011                 result = Data1.kind - Data2.kind;\r
1012                 break;\r
1013         default:\r
1014                 break;\r
1015         }\r
1016 \r
1017         if (!m_bAscending)\r
1018                 result = -result;\r
1019         return result < 0;\r
1020 }\r
1021 #endif\r
1022 \r
1023 void CFileDiffDlg::OnBnClickedRev1btn()\r
1024 {\r
1025 #if 0\r
1026         if (m_bThreadRunning)\r
1027                 return; // do nothing as long as the thread is still running\r
1028 \r
1029         // show a dialog where the user can enter a revision\r
1030         CRevisionDlg dlg(this);\r
1031         dlg.AllowWCRevs(false);\r
1032         *((GitRev*)&dlg) = m_rev1;\r
1033 \r
1034         if (dlg.DoModal() == IDOK)\r
1035         {\r
1036                 m_rev1 = dlg;\r
1037                 m_cRev1Btn.SetWindowText(m_rev1.ToString());\r
1038                 m_cFileList.DeleteAllItems();\r
1039                 // start a new thread to re-fetch the diff\r
1040                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
1041                 if (AfxBeginThread(DiffThreadEntry, this)==NULL)\r
1042                 {\r
1043                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1044                         CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1045                 }\r
1046         }\r
1047 #endif\r
1048 }\r
1049 \r
1050 void CFileDiffDlg::OnBnClickedRev2btn()\r
1051 {\r
1052 #if 0\r
1053         if (m_bThreadRunning)\r
1054                 return; // do nothing as long as the thread is still running\r
1055 \r
1056         // show a dialog where the user can enter a revision\r
1057         CRevisionDlg dlg(this);\r
1058         dlg.AllowWCRevs(false);\r
1059         *((GitRev*)&dlg) = m_rev2;\r
1060 \r
1061         if (dlg.DoModal() == IDOK)\r
1062         {\r
1063                 m_rev2 = dlg;\r
1064                 m_cRev2Btn.SetWindowText(m_rev2.ToString());\r
1065                 m_cFileList.DeleteAllItems();\r
1066                 // start a new thread to re-fetch the diff\r
1067                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
1068                 if (AfxBeginThread(DiffThreadEntry, this)==NULL)\r
1069                 {\r
1070                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1071                         CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
1072                 }\r
1073         }\r
1074 #endif\r
1075 }\r
1076 \r
1077 LRESULT CFileDiffDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)\r
1078 {\r
1079         if (m_bThreadRunning)\r
1080         {\r
1081                 SetTimer(IDT_FILTER, 1000, NULL);\r
1082                 return 0L;\r
1083         }\r
1084 \r
1085         KillTimer(IDT_FILTER);\r
1086 \r
1087         m_cFileList.SetRedraw(FALSE);\r
1088         m_arFilteredList.clear();\r
1089         m_cFileList.DeleteAllItems();\r
1090 \r
1091         Filter(_T(""));\r
1092 \r
1093         m_cFileList.SetRedraw(TRUE);\r
1094         return 0L;\r
1095 }\r
1096 \r
1097 void CFileDiffDlg::OnEnChangeFilter()\r
1098 {\r
1099         SetTimer(IDT_FILTER, 1000, NULL);\r
1100 }\r
1101 \r
1102 void CFileDiffDlg::OnTimer(UINT_PTR nIDEvent)\r
1103 {\r
1104         if (m_bThreadRunning)\r
1105                 return;\r
1106 \r
1107         CString sFilterText;\r
1108         KillTimer(IDT_FILTER);\r
1109         m_cFilter.GetWindowText(sFilterText);\r
1110 \r
1111         m_cFileList.SetRedraw(FALSE);\r
1112         m_cFileList.DeleteAllItems();\r
1113 \r
1114         Filter(sFilterText);\r
1115 \r
1116         m_cFileList.SetRedraw(TRUE);\r
1117 \r
1118         __super::OnTimer(nIDEvent);\r
1119 }\r
1120 \r
1121 void CFileDiffDlg::Filter(CString sFilterText)\r
1122 {\r
1123 \r
1124         sFilterText.MakeLower();\r
1125 \r
1126         m_arFilteredList.clear();\r
1127         \r
1128         for (int i=0;i<m_arFileList.GetCount();i++)\r
1129         {\r
1130                 CString sPath = m_arFileList[i].GetGitPathString();\r
1131                 sPath.MakeLower();\r
1132                 if (sPath.Find(sFilterText) >= 0)\r
1133                 {\r
1134                         m_arFilteredList.push_back((CTGitPath*)&(m_arFileList[i]));\r
1135                 }\r
1136         }\r
1137         for (std::vector<CTGitPath*>::const_iterator it = m_arFilteredList.begin(); it != m_arFilteredList.end(); ++it)\r
1138         {\r
1139                 AddEntry(*it);\r
1140         }\r
1141 \r
1142 }\r
1143 \r
1144 void CFileDiffDlg::CopySelectionToClipboard()\r
1145 {\r
1146         // copy all selected paths to the clipboard\r
1147         POSITION pos = m_cFileList.GetFirstSelectedItemPosition();\r
1148         int index;\r
1149         CString sTextForClipboard;\r
1150         while ((index = m_cFileList.GetNextSelectedItem(pos)) >= 0)\r
1151         {\r
1152                 sTextForClipboard += m_cFileList.GetItemText(index, 0);\r
1153                 sTextForClipboard += _T("\t");\r
1154                 sTextForClipboard += m_cFileList.GetItemText(index, 1);\r
1155                 sTextForClipboard += _T("\r\n");\r
1156         }\r
1157         CStringUtils::WriteAsciiStringToClipboard(sTextForClipboard);\r
1158 }\r
1159 \r