From 9ca4d2e217422a32912a1c77d1c6cc230361ff83 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 16 Jan 2009 22:40:07 +0800 Subject: [PATCH] Git Blame Add context menu Action Signed-off-by: Frank Li --- src/TortoiseGitBlame/LogListBlameAction.cpp | 443 ++++++++++++++++++++++++++++ src/TortoiseProc/Commands/BranchCommand.cpp | 7 +- src/TortoiseProc/Commands/ExportCommand.cpp | 7 +- src/TortoiseProc/Commands/SwitchCommand.cpp | 7 +- src/TortoiseProc/Commands/TagCommand.cpp | 7 +- src/TortoiseProc/TortoiseProc.vcproj | 48 +-- 6 files changed, 491 insertions(+), 28 deletions(-) diff --git a/src/TortoiseGitBlame/LogListBlameAction.cpp b/src/TortoiseGitBlame/LogListBlameAction.cpp index 74e9b697a..d047b36b3 100644 --- a/src/TortoiseGitBlame/LogListBlameAction.cpp +++ b/src/TortoiseGitBlame/LogListBlameAction.cpp @@ -1,9 +1,452 @@ #include "stdafx.h" #include "GitBlameLogList.h" #include "GitRev.h" +#include "TortoiseGitBlameDoc.h" +#include "TortoiseGitBlameView.h" +#include "MainFrm.h" +#include "PathUtils.h" IMPLEMENT_DYNAMIC(CGitBlameLogList, CHintListCtrl) void CGitBlameLogList::ContextMenuAction(int cmd,int FirstSelect, int LastSelect) { + POSITION pos = GetFirstSelectedItemPosition(); + int indexNext = GetNextSelectedItem(pos); + if (indexNext < 0) + return; + + CString procCmd; + + GitRev* pSelLogEntry = reinterpret_cast(m_arShownList.GetAt(indexNext)); + + bool bOpenWith = false; + + procCmd+=_T("/path:\""); + procCmd+=((CMainFrame*)::AfxGetApp()->GetMainWnd())->GetActiveView()->GetDocument()->GetPathName(); + procCmd+=_T("\" "); + procCmd+=_T(" /rev:")+this->m_logEntries[indexNext].m_CommitHash; + + procCmd+=_T(" /command:"); + + switch (cmd) + { + case ID_GNUDIFF1: + procCmd+=_T("diff /udiff"); + break; + +#if 0 + case ID_GNUDIFF2: + { + CString tempfile=GetTempFile(); + CString cmd; + GitRev * r1 = reinterpret_cast(m_arShownList.GetAt(FirstSelect)); + GitRev * r2 = reinterpret_cast(m_arShownList.GetAt(LastSelect)); + cmd.Format(_T("git.exe diff-tree -r -p --stat %s %s"),r1->m_CommitHash,r2->m_CommitHash); + g_Git.RunLogFile(cmd,tempfile); + CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r2->m_CommitHash.Left(6)); + + } + break; +#endif +#if 0 + case ID_COMPARETWO: + { + GitRev * r1 = reinterpret_cast(m_arShownList.GetAt(FirstSelect)); + GitRev * r2 = reinterpret_cast(m_arShownList.GetAt(LastSelect)); + CFileDiffDlg dlg; + dlg.SetDiff(NULL,*r1,*r2); + dlg.DoModal(); + + } + break; +#endif +#if 0 + case ID_COMPARE: + { + GitRev * r1 = &m_wcRev; + GitRev * r2 = pSelLogEntry; + CFileDiffDlg dlg; + dlg.SetDiff(NULL,*r1,*r2); + dlg.DoModal(); + + //user clicked on the menu item "compare with working copy" + //if (PromptShown()) + //{ + // GitDiff diff(this, m_hWnd, true); + // diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000)); + // diff.SetHEADPeg(m_LogRevision); + // diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected); + //} + //else + // CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)); + } + break; +#endif + case ID_COMPARE: + procCmd+=CString(_T("diff \rev1:"))+CString(GIT_REV_ZERO)+CString(_T(" \rev2:"))+this->m_logEntries[indexNext].m_CommitHash; + break; + case ID_COMPAREWITHPREVIOUS: + procCmd+=_T("prevdiff"); + break; + case ID_COPYCLIPBOARD: + { + CopySelectionToClipBoard(); + } + return; + case ID_COPYHASH: + { + CopySelectionToClipBoard(TRUE); + } + return; + case ID_EXPORT: + procCmd+=_T("export"); + break; + case ID_CREATE_BRANCH: + procCmd+=_T("branch"); + break; + case ID_CREATE_TAG: + procCmd+=_T("tag"); + break; + case ID_SWITCHTOREV: + procCmd+=_T("switch"); + break; + + default: + //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK); + return; + +#if 0 + + case ID_REVERTREV: + { + // we need an URL to complete this command, so error out if we can't get an URL + if (pathURL.IsEmpty()) + { + CString strMessage; + strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString())); + CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR); + TRACE(_T("could not retrieve the URL of the folder!\n")); + break; //exit + } + CString msg; + msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath()); + if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES) + { + CGitProgressDlg dlg; + dlg.SetCommand(CGitProgressDlg::GitProgress_Merge); + dlg.SetPathList(CTGitPathList(m_path)); + dlg.SetUrl(pathURL); + dlg.SetSecondUrl(pathURL); + revisionRanges.AdjustForMerge(true); + dlg.SetRevisionRanges(revisionRanges); + dlg.SetPegRevision(m_LogRevision); + dlg.DoModal(); + } + } + break; + case ID_MERGEREV: + { + // we need an URL to complete this command, so error out if we can't get an URL + if (pathURL.IsEmpty()) + { + CString strMessage; + strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString())); + CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR); + TRACE(_T("could not retrieve the URL of the folder!\n")); + break; //exit + } + + CString path = m_path.GetWinPathString(); + bool bGotSavePath = false; + if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory())) + { + bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd()); + } + else + { + CBrowseFolder folderBrowser; + folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO))); + bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK); + } + if (bGotSavePath) + { + CGitProgressDlg dlg; + dlg.SetCommand(CGitProgressDlg::GitProgress_Merge); + dlg.SetPathList(CTGitPathList(CTGitPath(path))); + dlg.SetUrl(pathURL); + dlg.SetSecondUrl(pathURL); + revisionRanges.AdjustForMerge(false); + dlg.SetRevisionRanges(revisionRanges); + dlg.SetPegRevision(m_LogRevision); + dlg.DoModal(); + } + } + break; + case ID_REVERTTOREV: + { + // we need an URL to complete this command, so error out if we can't get an URL + if (pathURL.IsEmpty()) + { + CString strMessage; + strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString())); + CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR); + TRACE(_T("could not retrieve the URL of the folder!\n")); + break; //exit + } + + CString msg; + msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath()); + if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES) + { + CGitProgressDlg dlg; + dlg.SetCommand(CGitProgressDlg::GitProgress_Merge); + dlg.SetPathList(CTGitPathList(m_path)); + dlg.SetUrl(pathURL); + dlg.SetSecondUrl(pathURL); + GitRevRangeArray revarray; + revarray.AddRevRange(GitRev::REV_HEAD, revSelected); + dlg.SetRevisionRanges(revarray); + dlg.SetPegRevision(m_LogRevision); + dlg.DoModal(); + } + } + break; + + + + case ID_BLAMECOMPARE: + { + //user clicked on the menu item "compare with working copy" + //now first get the revision which is selected + if (PromptShown()) + { + GitDiff diff(this, this->m_hWnd, true); + diff.SetHEADPeg(m_LogRevision); + diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true); + } + else + CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true); + } + break; + case ID_BLAMETWO: + { + //user clicked on the menu item "compare and blame revisions" + if (PromptShown()) + { + GitDiff diff(this, this->m_hWnd, true); + diff.SetHEADPeg(m_LogRevision); + diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true); + } + else + CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true); + } + break; + case ID_BLAMEWITHPREVIOUS: + { + //user clicked on the menu item "Compare and Blame with previous revision" + if (PromptShown()) + { + GitDiff diff(this, this->m_hWnd, true); + diff.SetHEADPeg(m_LogRevision); + diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true); + } + else + CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true); + } + break; + + case ID_OPENWITH: + bOpenWith = true; + case ID_OPEN: + { + CProgressDlg progDlg; + progDlg.SetTitle(IDS_APPNAME); + progDlg.SetAnimation(IDR_DOWNLOAD); + CString sInfoLine; + sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString()); + progDlg.SetLine(1, sInfoLine, true); + SetAndClearProgressInfo(&progDlg); + progDlg.ShowModeless(m_hWnd); + CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected); + bool bSuccess = true; + if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile)) + { + bSuccess = false; + // try again, but with the selected revision as the peg revision + if (!Cat(m_path, revSelected, revSelected, tempfile)) + { + progDlg.Stop(); + SetAndClearProgressInfo((HWND)NULL); + CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); + EnableOKButton(); + break; + } + bSuccess = true; + } + if (bSuccess) + { + progDlg.Stop(); + SetAndClearProgressInfo((HWND)NULL); + SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY); + int ret = 0; + if (!bOpenWith) + ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL); + if ((ret <= HINSTANCE_ERROR)||bOpenWith) + { + CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL "); + cmd += tempfile.GetWinPathString() + _T(" "); + CAppUtils::LaunchApplication(cmd, NULL, false); + } + } + } + break; + case ID_BLAME: + { + CBlameDlg dlg; + dlg.EndRev = revSelected; + if (dlg.DoModal() == IDOK) + { + CBlame blame; + CString tempfile; + CString logfile; + tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE); + if (!tempfile.IsEmpty()) + { + if (dlg.m_bTextView) + { + //open the default text editor for the result file + CAppUtils::StartTextViewer(tempfile); + } + else + { + CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" "); + if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams)) + { + break; + } + } + } + else + { + CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR); + } + } + } + break; + case ID_UPDATE: + { + CString sCmd; + CString url = _T("tgit:")+pathURL; + sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"), + (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), + (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected); + CAppUtils::LaunchApplication(sCmd, NULL, false); + } + break; + case ID_FINDENTRY: + { + m_nSearchIndex = GetSelectionMark(); + if (m_nSearchIndex < 0) + m_nSearchIndex = 0; + if (m_pFindDialog) + { + break; + } + else + { + m_pFindDialog = new CFindReplaceDialog(); + m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this); + } + } + break; + case ID_REPOBROWSE: + { + CString sCmd; + sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"), + (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), + (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString()); + + CAppUtils::LaunchApplication(sCmd, NULL, false); + } + break; + case ID_EDITLOG: + { + EditLogMessage(selIndex); + } + break; + case ID_EDITAUTHOR: + { + EditAuthor(selEntries); + } + break; + case ID_REVPROPS: + { + CEditPropertiesDlg dlg; + dlg.SetProjectProperties(&m_ProjectProperties); + CTGitPathList escapedlist; + dlg.SetPathList(CTGitPathList(CTGitPath(pathURL))); + dlg.SetRevision(revSelected); + dlg.RevProps(true); + dlg.DoModal(); + } + break; + + case ID_EXPORT: + { + CString sCmd; + sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"), + (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), + (LPCTSTR)pathURL, (LONG)revSelected); + CAppUtils::LaunchApplication(sCmd, NULL, false); + } + break; + case ID_CHECKOUT: + { + CString sCmd; + CString url = _T("tgit:")+pathURL; + sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"), + (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), + (LPCTSTR)url, (LONG)revSelected); + CAppUtils::LaunchApplication(sCmd, NULL, false); + } + break; + case ID_VIEWREV: + { + CString url = m_ProjectProperties.sWebViewerRev; + url = GetAbsoluteUrlFromRelativeUrl(url); + url.Replace(_T("%REVISION%"), revSelected.ToString()); + if (!url.IsEmpty()) + ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT); + } + break; + case ID_VIEWPATHREV: + { + CString relurl = pathURL; + CString sRoot = GetRepositoryRoot(CTGitPath(relurl)); + relurl = relurl.Mid(sRoot.GetLength()); + CString url = m_ProjectProperties.sWebViewerPathRev; + url = GetAbsoluteUrlFromRelativeUrl(url); + url.Replace(_T("%REVISION%"), revSelected.ToString()); + url.Replace(_T("%PATH%"), relurl); + if (!url.IsEmpty()) + ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT); + } + break; +#endif + + } // switch (cmd) + + + STARTUPINFO startup; + PROCESS_INFORMATION process; + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + memset(&process, 0, sizeof(process)); + CString tortoiseProcPath = CPathUtils::GetAppDirectory() + _T("TortoiseProc.exe"); + + if (CreateProcess(tortoiseProcPath, procCmd.GetBuffer(), NULL, NULL, FALSE, 0, 0, 0, &startup, &process)) + { + CloseHandle(process.hThread); + CloseHandle(process.hProcess); + } } \ No newline at end of file diff --git a/src/TortoiseProc/Commands/BranchCommand.cpp b/src/TortoiseProc/Commands/BranchCommand.cpp index 4abf978ee..3d14618ef 100644 --- a/src/TortoiseProc/Commands/BranchCommand.cpp +++ b/src/TortoiseProc/Commands/BranchCommand.cpp @@ -31,5 +31,10 @@ bool BranchCommand::Execute() { - return CAppUtils::CreateBranchTag(FALSE); + CString base=parser.GetVal(_T("rev")); + CString *p=&base; + if(base.IsEmpty()) + p=NULL; + + return CAppUtils::CreateBranchTag(FALSE,p); } diff --git a/src/TortoiseProc/Commands/ExportCommand.cpp b/src/TortoiseProc/Commands/ExportCommand.cpp index 8d32deee1..1a4aaab1d 100644 --- a/src/TortoiseProc/Commands/ExportCommand.cpp +++ b/src/TortoiseProc/Commands/ExportCommand.cpp @@ -23,5 +23,10 @@ bool ExportCommand::Execute() { - return CAppUtils::Export(); + CString base=parser.GetVal(_T("rev")); + CString *p=&base; + if(base.IsEmpty()) + p=NULL; + + return CAppUtils::Export(p); } diff --git a/src/TortoiseProc/Commands/SwitchCommand.cpp b/src/TortoiseProc/Commands/SwitchCommand.cpp index 400414bb2..551d6632a 100644 --- a/src/TortoiseProc/Commands/SwitchCommand.cpp +++ b/src/TortoiseProc/Commands/SwitchCommand.cpp @@ -26,5 +26,10 @@ bool SwitchCommand::Execute() { - return CAppUtils::Switch(NULL); + CString base=parser.GetVal(_T("rev")); + CString *p=&base; + if(base.IsEmpty()) + p=NULL; + + return CAppUtils::Switch(p); } diff --git a/src/TortoiseProc/Commands/TagCommand.cpp b/src/TortoiseProc/Commands/TagCommand.cpp index 3c2e20da6..ba9026ea5 100644 --- a/src/TortoiseProc/Commands/TagCommand.cpp +++ b/src/TortoiseProc/Commands/TagCommand.cpp @@ -29,5 +29,10 @@ bool TagCommand::Execute() { - return CAppUtils::CreateBranchTag(TRUE); + CString base=parser.GetVal(_T("rev")); + CString *p=&base; + if(base.IsEmpty()) + p=NULL; + + return CAppUtils::CreateBranchTag(TRUE,p); } diff --git a/src/TortoiseProc/TortoiseProc.vcproj b/src/TortoiseProc/TortoiseProc.vcproj index 078aa33a2..3d681156c 100644 --- a/src/TortoiseProc/TortoiseProc.vcproj +++ b/src/TortoiseProc/TortoiseProc.vcproj @@ -574,11 +574,11 @@ > + + + + + + - - - - - - -- 2.11.4.GIT