1 // GitLogList.cpp : implementation file
4 Description: qgit revision list view
6 Author: Marco Costalba (C) 2005-2007
8 Copyright: See COPYING file that comes with this distribution
12 #include "TortoiseProc.h"
13 #include "GitLogList.h"
15 //#include "VssStyle.h"
21 #include "SVNProgressDlg.h"
22 #include "ProgressDlg.h"
23 //#include "RepositoryBrowser.h"
24 //#include "CopyDlg.h"
25 //#include "StatGraphDlg.h"
27 #include "MessageBox.h"
30 #include "PathUtils.h"
31 #include "StringUtils.h"
32 #include "UnicodeUtils.h"
34 //#include "GitInfo.h"
35 //#include "GitDiff.h"
37 //#include "RevisionRangeDlg.h"
38 //#include "BrowseFolder.h"
39 //#include "BlameDlg.h"
41 //#include "GitHelpers.h"
42 #include "GitStatus.h"
43 //#include "LogDlgHelper.h"
44 //#include "CachedLogInfo.h"
45 //#include "RepositoryInfo.h"
46 //#include "EditPropertiesDlg.h"
47 #include "FileDiffDlg.h"
49 IMPLEMENT_DYNAMIC(CGitLogList
, CHintListCtrl
)
51 void CGitLogList::ContextMenuAction(int cmd
,int FirstSelect
, int LastSelect
)
53 POSITION pos
= GetFirstSelectedItemPosition();
54 int indexNext
= GetNextSelectedItem(pos
);
58 GitRev
* pSelLogEntry
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(indexNext
));
60 theApp
.DoWaitCursor(1);
61 bool bOpenWith
= false;
66 CString tempfile
=GetTempFile();
68 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
69 cmd
.Format(_T("git.exe diff-tree -r -p --stat %s"),r1
->m_CommitHash
);
70 g_Git
.RunLogFile(cmd
,tempfile
);
71 CAppUtils::StartUnifiedDiffViewer(tempfile
,r1
->m_CommitHash
.Left(6)+_T(":")+r1
->m_Subject
);
77 CString tempfile
=GetTempFile();
79 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
80 GitRev
* r2
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
81 cmd
.Format(_T("git.exe diff-tree -r -p --stat %s %s"),r1
->m_CommitHash
,r2
->m_CommitHash
);
82 g_Git
.RunLogFile(cmd
,tempfile
);
83 CAppUtils::StartUnifiedDiffViewer(tempfile
,r1
->m_CommitHash
.Left(6)+_T(":")+r2
->m_CommitHash
.Left(6));
90 GitRev
* r1
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(FirstSelect
));
91 GitRev
* r2
= reinterpret_cast<GitRev
*>(m_arShownList
.GetAt(LastSelect
));
93 dlg
.SetDiff(NULL
,*r1
,*r2
);
102 GitRev
* r1
= &m_wcRev
;
103 GitRev
* r2
= pSelLogEntry
;
105 dlg
.SetDiff(NULL
,*r1
,*r2
);
108 //user clicked on the menu item "compare with working copy"
111 // GitDiff diff(this, m_hWnd, true);
112 // diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
113 // diff.SetHEADPeg(m_LogRevision);
114 // diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);
117 // CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
121 case ID_COMPAREWITHPREVIOUS
:
126 if(pSelLogEntry
->m_ParentHash
.size()>0)
127 //if(m_logEntries.m_HashMap[pSelLogEntry->m_ParentHash[0]]>=0)
129 dlg
.SetDiff(NULL
,pSelLogEntry
->m_CommitHash
,pSelLogEntry
->m_ParentHash
[0]);
133 CMessageBox::Show(NULL
,_T("No previous version"),_T("TortoiseGit"),MB_OK
);
137 // GitDiff diff(this, m_hWnd, true);
138 // diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
139 // diff.SetHEADPeg(m_LogRevision);
140 // diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);
143 // CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
146 case ID_COPYCLIPBOARD
:
148 CopySelectionToClipBoard();
153 CopySelectionToClipBoard(TRUE
);
157 CAppUtils::Export(&pSelLogEntry
->m_CommitHash
);
159 case ID_CREATE_BRANCH
:
160 CAppUtils::CreateBranchTag(FALSE
,&pSelLogEntry
->m_CommitHash
);
165 CAppUtils::CreateBranchTag(TRUE
,&pSelLogEntry
->m_CommitHash
);
170 CAppUtils::Switch(&pSelLogEntry
->m_CommitHash
);
175 CAppUtils::GitReset(&pSelLogEntry
->m_CommitHash
);
180 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK
);
183 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT
);
185 case ID_REBASE_SQUASH
:
186 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH
);
189 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP
);
192 //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);
198 // we need an URL to complete this command, so error out if we can't get an URL
199 if (pathURL
.IsEmpty())
202 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
203 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
204 TRACE(_T("could not retrieve the URL of the folder!\n"));
208 msg
.Format(IDS_LOG_REVERT_CONFIRM
, m_path
.GetWinPath());
209 if (CMessageBox::Show(this->m_hWnd
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
212 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
213 dlg
.SetPathList(CTGitPathList(m_path
));
215 dlg
.SetSecondUrl(pathURL
);
216 revisionRanges
.AdjustForMerge(true);
217 dlg
.SetRevisionRanges(revisionRanges
);
218 dlg
.SetPegRevision(m_LogRevision
);
225 // we need an URL to complete this command, so error out if we can't get an URL
226 if (pathURL
.IsEmpty())
229 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
230 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
231 TRACE(_T("could not retrieve the URL of the folder!\n"));
235 CString path
= m_path
.GetWinPathString();
236 bool bGotSavePath
= false;
237 if ((GetSelectedCount() == 1)&&(!m_path
.IsDirectory()))
239 bGotSavePath
= CAppUtils::FileOpenSave(path
, NULL
, IDS_LOG_MERGETO
, IDS_COMMONFILEFILTER
, true, GetSafeHwnd());
243 CBrowseFolder folderBrowser
;
244 folderBrowser
.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO
)));
245 bGotSavePath
= (folderBrowser
.Show(GetSafeHwnd(), path
, path
) == CBrowseFolder::OK
);
250 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
251 dlg
.SetPathList(CTGitPathList(CTGitPath(path
)));
253 dlg
.SetSecondUrl(pathURL
);
254 revisionRanges
.AdjustForMerge(false);
255 dlg
.SetRevisionRanges(revisionRanges
);
256 dlg
.SetPegRevision(m_LogRevision
);
263 // we need an URL to complete this command, so error out if we can't get an URL
264 if (pathURL
.IsEmpty())
267 strMessage
.Format(IDS_ERR_NOURLOFFILE
, (LPCTSTR
)(m_path
.GetUIPathString()));
268 CMessageBox::Show(this->m_hWnd
, strMessage
, _T("TortoiseGit"), MB_ICONERROR
);
269 TRACE(_T("could not retrieve the URL of the folder!\n"));
274 msg
.Format(IDS_LOG_REVERTTOREV_CONFIRM
, m_path
.GetWinPath());
275 if (CMessageBox::Show(this->m_hWnd
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
278 dlg
.SetCommand(CGitProgressDlg::GitProgress_Merge
);
279 dlg
.SetPathList(CTGitPathList(m_path
));
281 dlg
.SetSecondUrl(pathURL
);
282 GitRevRangeArray revarray
;
283 revarray
.AddRevRange(GitRev::REV_HEAD
, revSelected
);
284 dlg
.SetRevisionRanges(revarray
);
285 dlg
.SetPegRevision(m_LogRevision
);
293 case ID_BLAMECOMPARE
:
295 //user clicked on the menu item "compare with working copy"
296 //now first get the revision which is selected
299 GitDiff
diff(this, this->m_hWnd
, true);
300 diff
.SetHEADPeg(m_LogRevision
);
301 diff
.ShowCompare(m_path
, GitRev::REV_BASE
, m_path
, revSelected
, GitRev(), false, true);
304 CAppUtils::StartShowCompare(m_hWnd
, m_path
, GitRev::REV_BASE
, m_path
, revSelected
, GitRev(), m_LogRevision
, false, false, true);
309 //user clicked on the menu item "compare and blame revisions"
312 GitDiff
diff(this, this->m_hWnd
, true);
313 diff
.SetHEADPeg(m_LogRevision
);
314 diff
.ShowCompare(CTGitPath(pathURL
), revSelected2
, CTGitPath(pathURL
), revSelected
, GitRev(), false, true);
317 CAppUtils::StartShowCompare(m_hWnd
, CTGitPath(pathURL
), revSelected2
, CTGitPath(pathURL
), revSelected
, GitRev(), m_LogRevision
, false, false, true);
320 case ID_BLAMEWITHPREVIOUS
:
322 //user clicked on the menu item "Compare and Blame with previous revision"
325 GitDiff
diff(this, this->m_hWnd
, true);
326 diff
.SetHEADPeg(m_LogRevision
);
327 diff
.ShowCompare(CTGitPath(pathURL
), revPrevious
, CTGitPath(pathURL
), revSelected
, GitRev(), false, true);
330 CAppUtils::StartShowCompare(m_hWnd
, CTGitPath(pathURL
), revPrevious
, CTGitPath(pathURL
), revSelected
, GitRev(), m_LogRevision
, false, false, true);
338 CProgressDlg progDlg
;
339 progDlg
.SetTitle(IDS_APPNAME
);
340 progDlg
.SetAnimation(IDR_DOWNLOAD
);
342 sInfoLine
.Format(IDS_PROGRESSGETFILEREVISION
, m_path
.GetWinPath(), (LPCTSTR
)revSelected
.ToString());
343 progDlg
.SetLine(1, sInfoLine
, true);
344 SetAndClearProgressInfo(&progDlg
);
345 progDlg
.ShowModeless(m_hWnd
);
346 CTGitPath tempfile
= CTempFiles::Instance().GetTempFilePath(false, m_path
, revSelected
);
347 bool bSuccess
= true;
348 if (!Cat(m_path
, GitRev(GitRev::REV_HEAD
), revSelected
, tempfile
))
351 // try again, but with the selected revision as the peg revision
352 if (!Cat(m_path
, revSelected
, revSelected
, tempfile
))
355 SetAndClearProgressInfo((HWND
)NULL
);
356 CMessageBox::Show(this->m_hWnd
, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
365 SetAndClearProgressInfo((HWND
)NULL
);
366 SetFileAttributes(tempfile
.GetWinPath(), FILE_ATTRIBUTE_READONLY
);
369 ret
= (int)ShellExecute(this->m_hWnd
, NULL
, tempfile
.GetWinPath(), NULL
, NULL
, SW_SHOWNORMAL
);
370 if ((ret
<= HINSTANCE_ERROR
)||bOpenWith
)
372 CString cmd
= _T("RUNDLL32 Shell32,OpenAs_RunDLL ");
373 cmd
+= tempfile
.GetWinPathString() + _T(" ");
374 CAppUtils::LaunchApplication(cmd
, NULL
, false);
382 dlg
.EndRev
= revSelected
;
383 if (dlg
.DoModal() == IDOK
)
388 tempfile
= blame
.BlameToTempFile(m_path
, dlg
.StartRev
, dlg
.EndRev
, dlg
.EndRev
, logfile
, _T(""), dlg
.m_bIncludeMerge
, TRUE
, TRUE
);
389 if (!tempfile
.IsEmpty())
393 //open the default text editor for the result file
394 CAppUtils::StartTextViewer(tempfile
);
398 CString sParams
= _T("/path:\"") + m_path
.GetGitPathString() + _T("\" ");
399 if(!CAppUtils::LaunchTortoiseBlame(tempfile
, logfile
, CPathUtils::GetFileNameFromPath(m_path
.GetFileOrDirectoryName()),sParams
))
407 CMessageBox::Show(this->m_hWnd
, blame
.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR
);
415 CString url
= _T("tgit:")+pathURL
;
416 sCmd
.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),
417 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
418 (LPCTSTR
)m_path
.GetWinPath(), (LONG
)revSelected
);
419 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
424 m_nSearchIndex
= GetSelectionMark();
425 if (m_nSearchIndex
< 0)
433 m_pFindDialog
= new CFindReplaceDialog();
434 m_pFindDialog
->Create(TRUE
, NULL
, NULL
, FR_HIDEUPDOWN
| FR_HIDEWHOLEWORD
, this);
441 sCmd
.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),
442 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
443 (LPCTSTR
)pathURL
, (LPCTSTR
)revSelected
.ToString());
445 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
450 EditLogMessage(selIndex
);
455 EditAuthor(selEntries
);
460 CEditPropertiesDlg dlg
;
461 dlg
.SetProjectProperties(&m_ProjectProperties
);
462 CTGitPathList escapedlist
;
463 dlg
.SetPathList(CTGitPathList(CTGitPath(pathURL
)));
464 dlg
.SetRevision(revSelected
);
473 sCmd
.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),
474 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
475 (LPCTSTR
)pathURL
, (LONG
)revSelected
);
476 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
482 CString url
= _T("tgit:")+pathURL
;
483 sCmd
.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),
484 (LPCTSTR
)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),
485 (LPCTSTR
)url
, (LONG
)revSelected
);
486 CAppUtils::LaunchApplication(sCmd
, NULL
, false);
491 CString url
= m_ProjectProperties
.sWebViewerRev
;
492 url
= GetAbsoluteUrlFromRelativeUrl(url
);
493 url
.Replace(_T("%REVISION%"), revSelected
.ToString());
495 ShellExecute(this->m_hWnd
, _T("open"), url
, NULL
, NULL
, SW_SHOWDEFAULT
);
500 CString relurl
= pathURL
;
501 CString sRoot
= GetRepositoryRoot(CTGitPath(relurl
));
502 relurl
= relurl
.Mid(sRoot
.GetLength());
503 CString url
= m_ProjectProperties
.sWebViewerPathRev
;
504 url
= GetAbsoluteUrlFromRelativeUrl(url
);
505 url
.Replace(_T("%REVISION%"), revSelected
.ToString());
506 url
.Replace(_T("%PATH%"), relurl
);
508 ShellExecute(this->m_hWnd
, _T("open"), url
, NULL
, NULL
, SW_SHOWDEFAULT
);
515 theApp
.DoWaitCursor(-1);
518 void CGitLogList::SetSelectedAction(int action
)
520 POSITION pos
= GetFirstSelectedItemPosition();
524 index
= GetNextSelectedItem(pos
);
525 ((GitRev
*)m_arShownList
[index
])->m_Action
= action
;
527 this->GetItemRect(index
,&rect
,LVIR_BOUNDS
);
528 this->InvalidateRect(rect
);