OSDN Git Service

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