OSDN Git Service

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