OSDN Git Service

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