OSDN Git Service

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