RebaseDlg: Add New is top option. Disable Edit control after start rebase
[TortoiseGit.git] / src / TortoiseProc / GitLogListAction.cpp
blob0b3d00375c74cd741599645bd1780f15fc0afe75
1 // GitLogList.cpp : implementation file
2 //
3 /*
4 Description: qgit revision list view
6 Author: Marco Costalba (C) 2005-2007
8 Copyright: See COPYING file that comes with this distribution
11 #include "stdafx.h"
12 #include "TortoiseProc.h"
13 #include "GitLogList.h"
14 #include "GitRev.h"
15 //#include "VssStyle.h"
16 #include "IconMenu.h"
17 // CGitLogList
18 #include "cursor.h"
19 #include "InputDlg.h"
20 #include "PropDlg.h"
21 #include "SVNProgressDlg.h"
22 #include "ProgressDlg.h"
23 //#include "RepositoryBrowser.h"
24 //#include "CopyDlg.h"
25 //#include "StatGraphDlg.h"
26 #include "Logdlg.h"
27 #include "MessageBox.h"
28 #include "Registry.h"
29 #include "AppUtils.h"
30 #include "PathUtils.h"
31 #include "StringUtils.h"
32 #include "UnicodeUtils.h"
33 #include "TempFile.h"
34 //#include "GitInfo.h"
35 //#include "GitDiff.h"
36 #include "IconMenu.h"
37 //#include "RevisionRangeDlg.h"
38 //#include "BrowseFolder.h"
39 //#include "BlameDlg.h"
40 //#include "Blame.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);
55 if (indexNext < 0)
56 return;
58 GitRev* pSelLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(indexNext));
60 theApp.DoWaitCursor(1);
61 bool bOpenWith = false;
62 switch (cmd)
64 case ID_GNUDIFF1:
66 CString tempfile=GetTempFile();
67 CString cmd;
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);
73 break;
75 case ID_GNUDIFF2:
77 CString tempfile=GetTempFile();
78 CString cmd;
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));
86 break;
88 case ID_COMPARETWO:
90 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));
91 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));
92 CFileDiffDlg dlg;
93 dlg.SetDiff(NULL,*r1,*r2);
94 dlg.DoModal();
97 break;
100 case ID_COMPARE:
102 GitRev * r1 = &m_wcRev;
103 GitRev * r2 = pSelLogEntry;
104 CFileDiffDlg dlg;
105 dlg.SetDiff(NULL,*r1,*r2);
106 dlg.DoModal();
108 //user clicked on the menu item "compare with working copy"
109 //if (PromptShown())
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);
116 //else
117 // CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
119 break;
121 case ID_COMPAREWITHPREVIOUS:
124 CFileDiffDlg dlg;
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]);
130 dlg.DoModal();
131 }else
133 CMessageBox::Show(NULL,_T("No previous version"),_T("TortoiseGit"),MB_OK);
135 //if (PromptShown())
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);
142 //else
143 // CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
145 break;
146 case ID_COPYCLIPBOARD:
148 CopySelectionToClipBoard();
150 break;
151 case ID_COPYHASH:
153 CopySelectionToClipBoard(TRUE);
155 break;
156 case ID_EXPORT:
157 CAppUtils::Export(&pSelLogEntry->m_CommitHash);
158 break;
159 case ID_CREATE_BRANCH:
160 CAppUtils::CreateBranchTag(FALSE,&pSelLogEntry->m_CommitHash);
161 ReloadHashMap();
162 Invalidate();
163 break;
164 case ID_CREATE_TAG:
165 CAppUtils::CreateBranchTag(TRUE,&pSelLogEntry->m_CommitHash);
166 ReloadHashMap();
167 Invalidate();
168 break;
169 case ID_SWITCHTOREV:
170 CAppUtils::Switch(&pSelLogEntry->m_CommitHash);
171 ReloadHashMap();
172 Invalidate();
173 break;
174 case ID_RESET:
175 CAppUtils::GitReset(&pSelLogEntry->m_CommitHash);
176 ReloadHashMap();
177 Invalidate();
178 break;
179 case ID_REBASE_PICK:
180 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK);
181 break;
182 case ID_REBASE_EDIT:
183 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT);
184 break;
185 case ID_REBASE_SQUASH:
186 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);
187 break;
188 case ID_REBASE_SKIP:
189 SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP);
190 break;
191 default:
192 //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);
193 break;
194 #if 0
196 case ID_REVERTREV:
198 // we need an URL to complete this command, so error out if we can't get an URL
199 if (pathURL.IsEmpty())
201 CString strMessage;
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"));
205 break; //exit
207 CString msg;
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)
211 CGitProgressDlg dlg;
212 dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);
213 dlg.SetPathList(CTGitPathList(m_path));
214 dlg.SetUrl(pathURL);
215 dlg.SetSecondUrl(pathURL);
216 revisionRanges.AdjustForMerge(true);
217 dlg.SetRevisionRanges(revisionRanges);
218 dlg.SetPegRevision(m_LogRevision);
219 dlg.DoModal();
222 break;
223 case ID_MERGEREV:
225 // we need an URL to complete this command, so error out if we can't get an URL
226 if (pathURL.IsEmpty())
228 CString strMessage;
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"));
232 break; //exit
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());
241 else
243 CBrowseFolder folderBrowser;
244 folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));
245 bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);
247 if (bGotSavePath)
249 CGitProgressDlg dlg;
250 dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);
251 dlg.SetPathList(CTGitPathList(CTGitPath(path)));
252 dlg.SetUrl(pathURL);
253 dlg.SetSecondUrl(pathURL);
254 revisionRanges.AdjustForMerge(false);
255 dlg.SetRevisionRanges(revisionRanges);
256 dlg.SetPegRevision(m_LogRevision);
257 dlg.DoModal();
260 break;
261 case ID_REVERTTOREV:
263 // we need an URL to complete this command, so error out if we can't get an URL
264 if (pathURL.IsEmpty())
266 CString strMessage;
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"));
270 break; //exit
273 CString msg;
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)
277 CGitProgressDlg dlg;
278 dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);
279 dlg.SetPathList(CTGitPathList(m_path));
280 dlg.SetUrl(pathURL);
281 dlg.SetSecondUrl(pathURL);
282 GitRevRangeArray revarray;
283 revarray.AddRevRange(GitRev::REV_HEAD, revSelected);
284 dlg.SetRevisionRanges(revarray);
285 dlg.SetPegRevision(m_LogRevision);
286 dlg.DoModal();
289 break;
293 case ID_BLAMECOMPARE:
295 //user clicked on the menu item "compare with working copy"
296 //now first get the revision which is selected
297 if (PromptShown())
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);
303 else
304 CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);
306 break;
307 case ID_BLAMETWO:
309 //user clicked on the menu item "compare and blame revisions"
310 if (PromptShown())
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);
316 else
317 CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);
319 break;
320 case ID_BLAMEWITHPREVIOUS:
322 //user clicked on the menu item "Compare and Blame with previous revision"
323 if (PromptShown())
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);
329 else
330 CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);
332 break;
334 case ID_OPENWITH:
335 bOpenWith = true;
336 case ID_OPEN:
338 CProgressDlg progDlg;
339 progDlg.SetTitle(IDS_APPNAME);
340 progDlg.SetAnimation(IDR_DOWNLOAD);
341 CString sInfoLine;
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))
350 bSuccess = false;
351 // try again, but with the selected revision as the peg revision
352 if (!Cat(m_path, revSelected, revSelected, tempfile))
354 progDlg.Stop();
355 SetAndClearProgressInfo((HWND)NULL);
356 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
357 EnableOKButton();
358 break;
360 bSuccess = true;
362 if (bSuccess)
364 progDlg.Stop();
365 SetAndClearProgressInfo((HWND)NULL);
366 SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
367 int ret = 0;
368 if (!bOpenWith)
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);
378 break;
379 case ID_BLAME:
381 CBlameDlg dlg;
382 dlg.EndRev = revSelected;
383 if (dlg.DoModal() == IDOK)
385 CBlame blame;
386 CString tempfile;
387 CString logfile;
388 tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);
389 if (!tempfile.IsEmpty())
391 if (dlg.m_bTextView)
393 //open the default text editor for the result file
394 CAppUtils::StartTextViewer(tempfile);
396 else
398 CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");
399 if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))
401 break;
405 else
407 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);
411 break;
412 case ID_UPDATE:
414 CString sCmd;
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);
421 break;
422 case ID_FINDENTRY:
424 m_nSearchIndex = GetSelectionMark();
425 if (m_nSearchIndex < 0)
426 m_nSearchIndex = 0;
427 if (m_pFindDialog)
429 break;
431 else
433 m_pFindDialog = new CFindReplaceDialog();
434 m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);
437 break;
438 case ID_REPOBROWSE:
440 CString sCmd;
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);
447 break;
448 case ID_EDITLOG:
450 EditLogMessage(selIndex);
452 break;
453 case ID_EDITAUTHOR:
455 EditAuthor(selEntries);
457 break;
458 case ID_REVPROPS:
460 CEditPropertiesDlg dlg;
461 dlg.SetProjectProperties(&m_ProjectProperties);
462 CTGitPathList escapedlist;
463 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));
464 dlg.SetRevision(revSelected);
465 dlg.RevProps(true);
466 dlg.DoModal();
468 break;
470 case ID_EXPORT:
472 CString sCmd;
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);
478 break;
479 case ID_CHECKOUT:
481 CString sCmd;
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);
488 break;
489 case ID_VIEWREV:
491 CString url = m_ProjectProperties.sWebViewerRev;
492 url = GetAbsoluteUrlFromRelativeUrl(url);
493 url.Replace(_T("%REVISION%"), revSelected.ToString());
494 if (!url.IsEmpty())
495 ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);
497 break;
498 case ID_VIEWPATHREV:
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);
507 if (!url.IsEmpty())
508 ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);
510 break;
511 #endif
513 } // switch (cmd)
515 theApp.DoWaitCursor(-1);
518 void CGitLogList::SetSelectedAction(int action)
520 POSITION pos = GetFirstSelectedItemPosition();
521 int index;
522 while(pos)
524 index = GetNextSelectedItem(pos);
525 ((GitRev*)m_arShownList[index])->m_Action = action;
526 CRect rect;
527 this->GetItemRect(index,&rect,LVIR_BOUNDS);
528 this->InvalidateRect(rect);