OSDN Git Service

Merge branch 'master' of git://repo.or.cz/TortoiseGit
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogListAction.cpp
1 // GitLogList.cpp : implementation file\r
2 //\r
3 /*\r
4         Description: qgit revision list view\r
5 \r
6         Author: Marco Costalba (C) 2005-2007\r
7 \r
8         Copyright: See COPYING file that comes with this distribution\r
9 \r
10 */\r
11 #include "stdafx.h"\r
12 #include "TortoiseProc.h"\r
13 #include "GitLogList.h"\r
14 #include "GitRev.h"\r
15 //#include "VssStyle.h"\r
16 #include "IconMenu.h"\r
17 // CGitLogList\r
18 #include "cursor.h"\r
19 #include "InputDlg.h"\r
20 #include "PropDlg.h"\r
21 #include "SVNProgressDlg.h"\r
22 #include "ProgressDlg.h"\r
23 #include "SysProgressDlg.h"\r
24 //#include "RepositoryBrowser.h"\r
25 //#include "CopyDlg.h"\r
26 //#include "StatGraphDlg.h"\r
27 #include "Logdlg.h"\r
28 #include "MessageBox.h"\r
29 #include "Registry.h"\r
30 #include "AppUtils.h"\r
31 #include "PathUtils.h"\r
32 #include "StringUtils.h"\r
33 #include "UnicodeUtils.h"\r
34 #include "TempFile.h"\r
35 //#include "GitInfo.h"\r
36 //#include "GitDiff.h"\r
37 #include "IconMenu.h"\r
38 //#include "RevisionRangeDlg.h"\r
39 //#include "BrowseFolder.h"\r
40 //#include "BlameDlg.h"\r
41 //#include "Blame.h"\r
42 //#include "GitHelpers.h"\r
43 #include "GitStatus.h"\r
44 //#include "LogDlgHelper.h"\r
45 //#include "CachedLogInfo.h"\r
46 //#include "RepositoryInfo.h"\r
47 //#include "EditPropertiesDlg.h"\r
48 #include "FileDiffDlg.h"\r
49 #include "CommitDlg.h"\r
50 #include "RebaseDlg.h"\r
51 \r
52 IMPLEMENT_DYNAMIC(CGitLogList, CHintListCtrl)\r
53 \r
54 int CGitLogList::CherryPickFrom(CString from, CString to)\r
55 {\r
56         CLogDataVector logs;\r
57         if(logs.ParserFromLog(NULL,-1,0,&from,&to))\r
58                 return -1;\r
59 \r
60         if(logs.size() == 0)\r
61                 return 0;\r
62 \r
63         CSysProgressDlg progress;\r
64         if (progress.IsValid())\r
65         {\r
66                 progress.SetTitle(_T("Cherry Pick"));\r
67                 progress.SetAnimation(IDR_MOVEANI);\r
68                 progress.SetTime(true);\r
69                 progress.ShowModeless(this);\r
70         }\r
71 \r
72         for(int i=logs.size()-1;i>=0;i--)\r
73         {\r
74                 if (progress.IsValid())\r
75                 {\r
76                         progress.FormatPathLine(1, _T("Pick up %s"), logs[i].m_CommitHash);\r
77                         progress.FormatPathLine(2, _T("%s"), logs[i].m_Subject);\r
78                         progress.SetProgress(logs.size()-i, logs.size());\r
79                 }\r
80                 if ((progress.IsValid())&&(progress.HasUserCancelled()))\r
81                 {\r
82                         //CMessageBox::Show(hwndExplorer, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_ICONINFORMATION);\r
83                         throw std::exception(CUnicodeUtils::GetUTF8(_T("User canceled\r\n\r\n")));\r
84                         return -1;\r
85                 }\r
86                 CString cmd,out;\r
87                 cmd.Format(_T("git.exe cherry-pick %s"),logs[i].m_CommitHash);\r
88                 out.Empty();\r
89                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
90                 {\r
91                         throw std::exception(CUnicodeUtils::GetUTF8(CString(_T("Cherry Pick Failure\r\n\r\n"))+out));\r
92                         return -1;\r
93                 }\r
94         }\r
95         \r
96         return 0;\r
97 }\r
98 \r
99 void CGitLogList::ContextMenuAction(int cmd,int FirstSelect, int LastSelect)\r
100 {       \r
101         POSITION pos = GetFirstSelectedItemPosition();\r
102         int indexNext = GetNextSelectedItem(pos);\r
103         if (indexNext < 0)\r
104                 return;\r
105 \r
106         GitRev* pSelLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(indexNext));\r
107 \r
108         theApp.DoWaitCursor(1);\r
109         bool bOpenWith = false;\r
110         switch (cmd)\r
111                 {\r
112                         case ID_GNUDIFF1:\r
113                         {\r
114                                 CString tempfile=GetTempFile();\r
115                                 CString cmd;\r
116                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
117                                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s"),r1->m_CommitHash);\r
118                                 g_Git.RunLogFile(cmd,tempfile);\r
119                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r1->m_Subject);\r
120                         }\r
121                         break;\r
122 \r
123                         case ID_GNUDIFF2:\r
124                         {\r
125                                 CString tempfile=GetTempFile();\r
126                                 CString cmd;\r
127                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
128                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
129                                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s %s"),r1->m_CommitHash,r2->m_CommitHash);\r
130                                 g_Git.RunLogFile(cmd,tempfile);\r
131                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r2->m_CommitHash.Left(6));\r
132 \r
133                         }\r
134                         break;\r
135 \r
136                 case ID_COMPARETWO:\r
137                         {\r
138                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
139                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
140                                 CFileDiffDlg dlg;\r
141                                 dlg.SetDiff(NULL,*r1,*r2);\r
142                                 dlg.DoModal();\r
143                                 \r
144                         }\r
145                         break;\r
146                 \r
147 \r
148                 case ID_COMPARE:\r
149                         {\r
150                                 GitRev * r1 = &m_wcRev;\r
151                                 GitRev * r2 = pSelLogEntry;\r
152                                 CFileDiffDlg dlg;\r
153                                 dlg.SetDiff(NULL,*r1,*r2);\r
154                                 dlg.DoModal();\r
155 \r
156                                 //user clicked on the menu item "compare with working copy"\r
157                                 //if (PromptShown())\r
158                                 //{\r
159                                 //      GitDiff diff(this, m_hWnd, true);\r
160                                 //      diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
161                                 //      diff.SetHEADPeg(m_LogRevision);\r
162                                 //      diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);\r
163                                 //}\r
164                                 //else\r
165                                 //      CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
166                         }\r
167                         break;\r
168 \r
169                 case ID_COMPAREWITHPREVIOUS:\r
170                         {\r
171 \r
172                                 CFileDiffDlg dlg;\r
173                                 \r
174                                 if(pSelLogEntry->m_ParentHash.size()>0)\r
175                                 //if(m_logEntries.m_HashMap[pSelLogEntry->m_ParentHash[0]]>=0)\r
176                                 {\r
177                                         dlg.SetDiff(NULL,pSelLogEntry->m_CommitHash,pSelLogEntry->m_ParentHash[0]);\r
178                                         dlg.DoModal();\r
179                                 }else\r
180                                 {\r
181                                         CMessageBox::Show(NULL,_T("No previous version"),_T("TortoiseGit"),MB_OK);      \r
182                                 }\r
183                                 //if (PromptShown())\r
184                                 //{\r
185                                 //      GitDiff diff(this, m_hWnd, true);\r
186                                 //      diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
187                                 //      diff.SetHEADPeg(m_LogRevision);\r
188                                 //      diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);\r
189                                 //}\r
190                                 //else\r
191                                 //      CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
192                         }\r
193                         break;\r
194                 case ID_COPYCLIPBOARD:\r
195                         {\r
196                                 CopySelectionToClipBoard();\r
197                         }\r
198                         break;\r
199                 case ID_COPYHASH:\r
200                         {\r
201                                 CopySelectionToClipBoard(TRUE);\r
202                         }\r
203                         break;\r
204                 case ID_EXPORT:\r
205                         CAppUtils::Export(&pSelLogEntry->m_CommitHash);\r
206                         break;\r
207                 case ID_CREATE_BRANCH:\r
208                         CAppUtils::CreateBranchTag(FALSE,&pSelLogEntry->m_CommitHash);\r
209                         ReloadHashMap();\r
210                         Invalidate();                   \r
211                         break;\r
212                 case ID_CREATE_TAG:\r
213                         CAppUtils::CreateBranchTag(TRUE,&pSelLogEntry->m_CommitHash);\r
214                         ReloadHashMap();\r
215                         Invalidate();\r
216                         break;\r
217                 case ID_SWITCHTOREV:\r
218                         CAppUtils::Switch(&pSelLogEntry->m_CommitHash);\r
219                         ReloadHashMap();\r
220                         Invalidate();\r
221                         break;\r
222                 case ID_RESET:\r
223                         CAppUtils::GitReset(&pSelLogEntry->m_CommitHash);\r
224                         ReloadHashMap();\r
225                         Invalidate();\r
226                         break;\r
227                 case ID_REBASE_PICK:\r
228                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK);\r
229                         break;\r
230                 case ID_REBASE_EDIT:\r
231                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT);\r
232                         break;\r
233                 case ID_REBASE_SQUASH:\r
234                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);\r
235                         break;\r
236                 case ID_REBASE_SKIP:\r
237                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP);\r
238                         break;\r
239                 case ID_COMBINE_COMMIT:\r
240                 {\r
241                         CString head;\r
242                         CString headhash;\r
243                         CString hashFirst,hashLast;\r
244 \r
245                         int headindex=GetHeadIndex();\r
246                         if(headindex>=0) //incase show all branch, head is not the first commits. \r
247                         {\r
248                                 head.Format(_T("HEAD~%d"),FirstSelect-headindex);\r
249                                 hashFirst=g_Git.GetHash(head);\r
250 \r
251                                 head.Format(_T("HEAD~%d"),LastSelect-headindex);\r
252                                 hashLast=g_Git.GetHash(head);\r
253                         }\r
254                                                 \r
255                         GitRev* pFirstEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
256                         GitRev* pLastEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
257                         if(pFirstEntry->m_CommitHash != hashFirst || pLastEntry->m_CommitHash != hashLast)\r
258                         {\r
259                                 CMessageBox::Show(NULL,_T(\r
260                                         "Cannot combine commits now.\r\n\\r
261                                         Make sure you are viewing the log of your current branch and \\r
262                                         no filters are applied."),_T("TortoiseGit"),MB_OK);\r
263                                 break;\r
264                         }\r
265                         \r
266                         headhash=g_Git.GetHash(CString(_T("HEAD")));\r
267                         \r
268                         if(!g_Git.CheckCleanWorkTree())\r
269                         {\r
270                                 CMessageBox::Show(NULL,_T("Combine needs a clean work tree"),_T("TortoiseGit"),MB_OK);\r
271                                 break;\r
272                         }\r
273                         CString cmd,out;\r
274 \r
275                         //Use throw to abort this process (reset back to original HEAD)\r
276                         try\r
277                         {\r
278                                 cmd.Format(_T("git.exe reset --hard  %s"),pFirstEntry->m_CommitHash);\r
279                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
280                                 {\r
281                                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
282                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to first commit (first step) aborting...\r\n\r\n")+out));\r
283                                 }\r
284                                 cmd.Format(_T("git.exe reset --mixed  %s"),hashLast);\r
285                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
286                                 {\r
287                                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
288                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to last commit (second step) aborting...\r\n\r\n")+out));\r
289                                 }\r
290                                 CCommitDlg dlg;\r
291                                 for(int i=FirstSelect;i<=LastSelect;i++)\r
292                                 {\r
293                                         GitRev* pRev = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
294                                         dlg.m_sLogMessage+=pRev->m_Subject+_T("\n")+pRev->m_Body;\r
295                                         dlg.m_sLogMessage+=_T("\n");\r
296                                 }\r
297                                 dlg.m_bWholeProject=true;\r
298                                 dlg.m_bSelectFilesForCommit = true;\r
299                                 dlg.m_bCommitAmend=true;\r
300                                 dlg.m_AmendStr=dlg.m_sLogMessage;\r
301 \r
302                                 bool abort=false;\r
303                                 if (dlg.DoModal() == IDOK)\r
304                                 {\r
305                                         if(pFirstEntry->m_CommitHash!=headhash)\r
306                                         {\r
307                                                 //Commitrange firstEntry..headhash (from top of combine to original head) needs to be 'cherry-picked'\r
308                                                 //on top of new commit.\r
309                                                 //Use the rebase --onto command for it.\r
310                                                 //\r
311                                                 //All this can be done in one step using the following command:\r
312                                                 //cmd.Format(_T("git.exe format-patch --stdout --binary --full-index -k %s..%s | git am -k -3"),\r
313                                                 //      pFirstEntry->m_CommitHash,\r
314                                                 //      headhash);\r
315                                                 //But I am not sure if a '|' is going to work in a CreateProcess() call.\r
316                                                 //\r
317                                                 //Later the progress dialog could be used to execute these steps.\r
318 \r
319                                                 if(CherryPickFrom(pFirstEntry->m_CommitHash,headhash))\r
320                                                 {\r
321                                                         CString msg;\r
322                                                         msg.Format(_T("Error while cherry pick commits on top of combined commits. Aborting.\r\n\r\n"));\r
323                                                         throw std::exception(CUnicodeUtils::GetUTF8(msg));\r
324                                                 }\r
325 #if 0\r
326                                                 CString currentBranch=g_Git.GetCurrentBranch();\r
327                                                 cmd.Format(_T("git.exe rebase --onto \"%s\" %s %s"),\r
328                                                         currentBranch,\r
329                                                         pFirstEntry->m_CommitHash,\r
330                                                         headhash);\r
331                                                 if(g_Git.Run(cmd,&out,CP_UTF8)!=0)\r
332                                                 {\r
333                                                         CString msg;\r
334                                                         msg.Format(_T("Error while rebasing commits on top of combined commits. Aborting.\r\n\r\n%s"),out);\r
335 //                                                      CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_OK);\r
336                                                         g_Git.Run(_T("git.exe rebase --abort"),&out,CP_UTF8);\r
337                                                         throw std::exception(CUnicodeUtils::GetUTF8(msg));\r
338                                                 }\r
339 \r
340                                                 //HEAD is now on <no branch>. \r
341                                                 //The following steps are to get HEAD back on the original branch and reset the branch to the new HEAD\r
342                                                 //To avoid 2 working copy changes, we could use git branch -f <original branch> <hash new head> \r
343                                                 //And then git checkout <original branch>\r
344                                                 //But I don't know if 'git branch -f' removes tracking options. So for now, do a checkout and a reset.\r
345                                                 \r
346                                                 //Store new HEAD\r
347                                                 CString newHead=g_Git.GetHash(CString(_T("HEAD")));\r
348 \r
349                                                 //Checkout working branch\r
350                                                 cmd.Format(_T("git.exe checkout -f \"%s\""),currentBranch);\r
351                                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
352                                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not checkout original branch. Aborting...\r\n\r\n")+out));\r
353 \r
354                                                 //Reset to new HEAD\r
355                                                 cmd.Format(_T("git.exe reset --hard  %s"),newHead);\r
356                                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
357                                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to new head. Aborting...\r\n\r\n")+out));\r
358 #endif\r
359                                         }\r
360                                 }\r
361                                 else\r
362                                         throw std::exception("User aborted the combine process");\r
363                         }\r
364                         catch(std::exception& e)\r
365                         {\r
366                                 CMessageBox::Show(NULL,CUnicodeUtils::GetUnicode(CStringA(e.what())),_T("TortoiseGit: Combine error"),MB_OK|MB_ICONERROR);\r
367                                 cmd.Format(_T("git.exe reset --hard  %s"),headhash);\r
368                                 out.Empty();\r
369                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
370                                 {\r
371                                         CMessageBox::Show(NULL,_T("Could not reset to original HEAD\r\n\r\n")+out,_T("TortoiseGit"),MB_OK);\r
372                                 }\r
373                         }\r
374                         Refresh();\r
375                 }\r
376                         break;\r
377 \r
378                 case ID_CHERRY_PICK:\r
379                         if(!g_Git.CheckCleanWorkTree())\r
380                         {\r
381                                 CMessageBox::Show(NULL,_T("Cherry Pick Require Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
382                         \r
383                         }else\r
384                         {\r
385                                 CRebaseDlg dlg;\r
386                                 dlg.m_IsCherryPick = TRUE;\r
387                                 dlg.m_Upstream = this->m_CurrentBranch;\r
388                                 POSITION pos = GetFirstSelectedItemPosition();\r
389                                 while(pos)\r
390                                 {\r
391                                         int indexNext = GetNextSelectedItem(pos);\r
392                                         dlg.m_CommitList.m_logEntries.push_back(*(GitRev*)m_arShownList[indexNext]);\r
393                                         dlg.m_CommitList.m_logEntries.at(dlg.m_CommitList.m_logEntries.size()-1).m_Action |= CTGitPath::LOGACTIONS_REBASE_PICK;\r
394                                 }\r
395         \r
396                                 if(dlg.DoModal() == IDOK)\r
397                                 {\r
398                                         Refresh();\r
399                                 }\r
400                         }\r
401                         break;\r
402                 case ID_REBASE_TO_VERSION:\r
403                         if(!g_Git.CheckCleanWorkTree())\r
404                         {\r
405                                 CMessageBox::Show(NULL,_T("Rebase Require Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
406                         \r
407                         }else\r
408                         {\r
409                                 CRebaseDlg dlg;\r
410                                 dlg.m_Upstream = pSelLogEntry->m_CommitHash;\r
411 \r
412                                 if(dlg.DoModal() == IDOK)\r
413                                 {\r
414                                         Refresh();\r
415                                 }\r
416                         }\r
417 \r
418                         break;\r
419 \r
420                 default:\r
421                         //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);\r
422                         break;\r
423 #if 0\r
424         \r
425                 case ID_REVERTREV:\r
426                         {\r
427                                 // we need an URL to complete this command, so error out if we can't get an URL\r
428                                 if (pathURL.IsEmpty())\r
429                                 {\r
430                                         CString strMessage;\r
431                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
432                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
433                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
434                                         break;          //exit\r
435                                 }\r
436                                 CString msg;\r
437                                 msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
438                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
439                                 {\r
440                                         CGitProgressDlg dlg;\r
441                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
442                                         dlg.SetPathList(CTGitPathList(m_path));\r
443                                         dlg.SetUrl(pathURL);\r
444                                         dlg.SetSecondUrl(pathURL);\r
445                                         revisionRanges.AdjustForMerge(true);\r
446                                         dlg.SetRevisionRanges(revisionRanges);\r
447                                         dlg.SetPegRevision(m_LogRevision);\r
448                                         dlg.DoModal();\r
449                                 }\r
450                         }\r
451                         break;\r
452                 case ID_MERGEREV:\r
453                         {\r
454                                 // we need an URL to complete this command, so error out if we can't get an URL\r
455                                 if (pathURL.IsEmpty())\r
456                                 {\r
457                                         CString strMessage;\r
458                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
459                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
460                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
461                                         break;          //exit\r
462                                 }\r
463 \r
464                                 CString path = m_path.GetWinPathString();\r
465                                 bool bGotSavePath = false;\r
466                                 if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
467                                 {\r
468                                         bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
469                                 }\r
470                                 else\r
471                                 {\r
472                                         CBrowseFolder folderBrowser;\r
473                                         folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
474                                         bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
475                                 }\r
476                                 if (bGotSavePath)\r
477                                 {\r
478                                         CGitProgressDlg dlg;\r
479                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
480                                         dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
481                                         dlg.SetUrl(pathURL);\r
482                                         dlg.SetSecondUrl(pathURL);\r
483                                         revisionRanges.AdjustForMerge(false);\r
484                                         dlg.SetRevisionRanges(revisionRanges);\r
485                                         dlg.SetPegRevision(m_LogRevision);\r
486                                         dlg.DoModal();\r
487                                 }\r
488                         }\r
489                         break;\r
490                 case ID_REVERTTOREV:\r
491                         {\r
492                                 // we need an URL to complete this command, so error out if we can't get an URL\r
493                                 if (pathURL.IsEmpty())\r
494                                 {\r
495                                         CString strMessage;\r
496                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
497                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
498                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
499                                         break;          //exit\r
500                                 }\r
501 \r
502                                 CString msg;\r
503                                 msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
504                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
505                                 {\r
506                                         CGitProgressDlg dlg;\r
507                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
508                                         dlg.SetPathList(CTGitPathList(m_path));\r
509                                         dlg.SetUrl(pathURL);\r
510                                         dlg.SetSecondUrl(pathURL);\r
511                                         GitRevRangeArray revarray;\r
512                                         revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
513                                         dlg.SetRevisionRanges(revarray);\r
514                                         dlg.SetPegRevision(m_LogRevision);\r
515                                         dlg.DoModal();\r
516                                 }\r
517                         }\r
518                         break;\r
519         \r
520 \r
521         \r
522                 case ID_BLAMECOMPARE:\r
523                         {\r
524                                 //user clicked on the menu item "compare with working copy"\r
525                                 //now first get the revision which is selected\r
526                                 if (PromptShown())\r
527                                 {\r
528                                         GitDiff diff(this, this->m_hWnd, true);\r
529                                         diff.SetHEADPeg(m_LogRevision);\r
530                                         diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
531                                 }\r
532                                 else\r
533                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
534                         }\r
535                         break;\r
536                 case ID_BLAMETWO:\r
537                         {\r
538                                 //user clicked on the menu item "compare and blame revisions"\r
539                                 if (PromptShown())\r
540                                 {\r
541                                         GitDiff diff(this, this->m_hWnd, true);\r
542                                         diff.SetHEADPeg(m_LogRevision);\r
543                                         diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
544                                 }\r
545                                 else\r
546                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
547                         }\r
548                         break;\r
549                 case ID_BLAMEWITHPREVIOUS:\r
550                         {\r
551                                 //user clicked on the menu item "Compare and Blame with previous revision"\r
552                                 if (PromptShown())\r
553                                 {\r
554                                         GitDiff diff(this, this->m_hWnd, true);\r
555                                         diff.SetHEADPeg(m_LogRevision);\r
556                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
557                                 }\r
558                                 else\r
559                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
560                         }\r
561                         break;\r
562                 \r
563                 case ID_OPENWITH:\r
564                         bOpenWith = true;\r
565                 case ID_OPEN:\r
566                         {\r
567                                 CProgressDlg progDlg;\r
568                                 progDlg.SetTitle(IDS_APPNAME);\r
569                                 progDlg.SetAnimation(IDR_DOWNLOAD);\r
570                                 CString sInfoLine;\r
571                                 sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
572                                 progDlg.SetLine(1, sInfoLine, true);\r
573                                 SetAndClearProgressInfo(&progDlg);\r
574                                 progDlg.ShowModeless(m_hWnd);\r
575                                 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
576                                 bool bSuccess = true;\r
577                                 if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
578                                 {\r
579                                         bSuccess = false;\r
580                                         // try again, but with the selected revision as the peg revision\r
581                                         if (!Cat(m_path, revSelected, revSelected, tempfile))\r
582                                         {\r
583                                                 progDlg.Stop();\r
584                                                 SetAndClearProgressInfo((HWND)NULL);\r
585                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
586                                                 EnableOKButton();\r
587                                                 break;\r
588                                         }\r
589                                         bSuccess = true;\r
590                                 }\r
591                                 if (bSuccess)\r
592                                 {\r
593                                         progDlg.Stop();\r
594                                         SetAndClearProgressInfo((HWND)NULL);\r
595                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
596                                         int ret = 0;\r
597                                         if (!bOpenWith)\r
598                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
599                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
600                                         {\r
601                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
602                                                 cmd += tempfile.GetWinPathString() + _T(" ");\r
603                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
604                                         }\r
605                                 }\r
606                         }\r
607                         break;\r
608                 case ID_BLAME:\r
609                         {\r
610                                 CBlameDlg dlg;\r
611                                 dlg.EndRev = revSelected;\r
612                                 if (dlg.DoModal() == IDOK)\r
613                                 {\r
614                                         CBlame blame;\r
615                                         CString tempfile;\r
616                                         CString logfile;\r
617                                         tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
618                                         if (!tempfile.IsEmpty())\r
619                                         {\r
620                                                 if (dlg.m_bTextView)\r
621                                                 {\r
622                                                         //open the default text editor for the result file\r
623                                                         CAppUtils::StartTextViewer(tempfile);\r
624                                                 }\r
625                                                 else\r
626                                                 {\r
627                                                         CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
628                                                         if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
629                                                         {\r
630                                                                 break;\r
631                                                         }\r
632                                                 }\r
633                                         }\r
634                                         else\r
635                                         {\r
636                                                 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
637                                         }\r
638                                 }\r
639                         }\r
640                         break;\r
641                 case ID_UPDATE:\r
642                         {\r
643                                 CString sCmd;\r
644                                 CString url = _T("tgit:")+pathURL;\r
645                                 sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
646                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
647                                         (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
648                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
649                         }\r
650                         break;\r
651                 case ID_FINDENTRY:\r
652                         {\r
653                                 m_nSearchIndex = GetSelectionMark();\r
654                                 if (m_nSearchIndex < 0)\r
655                                         m_nSearchIndex = 0;\r
656                                 if (m_pFindDialog)\r
657                                 {\r
658                                         break;\r
659                                 }\r
660                                 else\r
661                                 {\r
662                                         m_pFindDialog = new CFindReplaceDialog();\r
663                                         m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
664                                 }\r
665                         }\r
666                         break;\r
667                 case ID_REPOBROWSE:\r
668                         {\r
669                                 CString sCmd;\r
670                                 sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
671                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
672                                         (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
673 \r
674                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
675                         }\r
676                         break;\r
677                 case ID_EDITLOG:\r
678                         {\r
679                                 EditLogMessage(selIndex);\r
680                         }\r
681                         break;\r
682                 case ID_EDITAUTHOR:\r
683                         {\r
684                                 EditAuthor(selEntries);\r
685                         }\r
686                         break;\r
687                 case ID_REVPROPS:\r
688                         {\r
689                                 CEditPropertiesDlg dlg;\r
690                                 dlg.SetProjectProperties(&m_ProjectProperties);\r
691                                 CTGitPathList escapedlist;\r
692                                 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
693                                 dlg.SetRevision(revSelected);\r
694                                 dlg.RevProps(true);\r
695                                 dlg.DoModal();\r
696                         }\r
697                         break;\r
698                 \r
699                 case ID_EXPORT:\r
700                         {\r
701                                 CString sCmd;\r
702                                 sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
703                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
704                                         (LPCTSTR)pathURL, (LONG)revSelected);\r
705                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
706                         }\r
707                         break;\r
708                 case ID_CHECKOUT:\r
709                         {\r
710                                 CString sCmd;\r
711                                 CString url = _T("tgit:")+pathURL;\r
712                                 sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
713                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
714                                         (LPCTSTR)url, (LONG)revSelected);\r
715                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
716                         }\r
717                         break;\r
718                 case ID_VIEWREV:\r
719                         {\r
720                                 CString url = m_ProjectProperties.sWebViewerRev;\r
721                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
722                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
723                                 if (!url.IsEmpty())\r
724                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
725                         }\r
726                         break;\r
727                 case ID_VIEWPATHREV:\r
728                         {\r
729                                 CString relurl = pathURL;\r
730                                 CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
731                                 relurl = relurl.Mid(sRoot.GetLength());\r
732                                 CString url = m_ProjectProperties.sWebViewerPathRev;\r
733                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
734                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
735                                 url.Replace(_T("%PATH%"), relurl);\r
736                                 if (!url.IsEmpty())\r
737                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
738                         }\r
739                         break;\r
740 #endif\r
741                 \r
742                 } // switch (cmd)\r
743 \r
744                 theApp.DoWaitCursor(-1);\r
745 }\r
746 \r
747 void CGitLogList::SetSelectedAction(int action)\r
748 {\r
749         POSITION pos = GetFirstSelectedItemPosition();\r
750         int index;\r
751         while(pos)\r
752         {\r
753                 index = GetNextSelectedItem(pos);\r
754                 ((GitRev*)m_arShownList[index])->m_Action = action;\r
755                 CRect rect;\r
756                 this->GetItemRect(index,&rect,LVIR_BOUNDS);\r
757                 this->InvalidateRect(rect);\r
758 \r
759         }\r
760 \r
761 }