OSDN Git Service

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