OSDN Git Service

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