OSDN Git Service

63c33cf080dad2367d8db5a4895c1b029dce998c
[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                 case ID_STASH_APPLY:\r
421                         CAppUtils::StashApply(pSelLogEntry->m_Ref);\r
422                         break;\r
423                 \r
424                 case ID_REFLOG_DEL:\r
425                         {       \r
426                                 CString str;\r
427                                 str.Format(_T("Warning: %s will be deleted. It can <ct=0x0000FF><b>NOT</b></ct> recovered,\r\n \r\n Are you sure delete these?"),pSelLogEntry->m_Ref);\r
428                                 if(CMessageBox::Show(NULL,str,_T("TortoiseGit"),MB_YESNO|MB_ICONWARNING) == IDYES)\r
429                                 {\r
430                                         CString cmd,out;\r
431                                         cmd.Format(_T("git.exe reflog delete %s"),pSelLogEntry->m_Ref);\r
432                                         if(g_Git.Run(cmd,&out,CP_ACP))\r
433                                         {\r
434                                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
435                                         }                                               \r
436                                         ::PostMessage(this->GetParent()->m_hWnd,MSG_REFLOG_CHANGED,0,0);\r
437                                 }\r
438                         }\r
439                         break;\r
440                 default:\r
441                         //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);\r
442                         break;\r
443 #if 0\r
444         \r
445                 case ID_REVERTREV:\r
446                         {\r
447                                 // we need an URL to complete this command, so error out if we can't get an URL\r
448                                 if (pathURL.IsEmpty())\r
449                                 {\r
450                                         CString strMessage;\r
451                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
452                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
453                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
454                                         break;          //exit\r
455                                 }\r
456                                 CString msg;\r
457                                 msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
458                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
459                                 {\r
460                                         CGitProgressDlg dlg;\r
461                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
462                                         dlg.SetPathList(CTGitPathList(m_path));\r
463                                         dlg.SetUrl(pathURL);\r
464                                         dlg.SetSecondUrl(pathURL);\r
465                                         revisionRanges.AdjustForMerge(true);\r
466                                         dlg.SetRevisionRanges(revisionRanges);\r
467                                         dlg.SetPegRevision(m_LogRevision);\r
468                                         dlg.DoModal();\r
469                                 }\r
470                         }\r
471                         break;\r
472                 case ID_MERGEREV:\r
473                         {\r
474                                 // we need an URL to complete this command, so error out if we can't get an URL\r
475                                 if (pathURL.IsEmpty())\r
476                                 {\r
477                                         CString strMessage;\r
478                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
479                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
480                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
481                                         break;          //exit\r
482                                 }\r
483 \r
484                                 CString path = m_path.GetWinPathString();\r
485                                 bool bGotSavePath = false;\r
486                                 if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
487                                 {\r
488                                         bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
489                                 }\r
490                                 else\r
491                                 {\r
492                                         CBrowseFolder folderBrowser;\r
493                                         folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
494                                         bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
495                                 }\r
496                                 if (bGotSavePath)\r
497                                 {\r
498                                         CGitProgressDlg dlg;\r
499                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
500                                         dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
501                                         dlg.SetUrl(pathURL);\r
502                                         dlg.SetSecondUrl(pathURL);\r
503                                         revisionRanges.AdjustForMerge(false);\r
504                                         dlg.SetRevisionRanges(revisionRanges);\r
505                                         dlg.SetPegRevision(m_LogRevision);\r
506                                         dlg.DoModal();\r
507                                 }\r
508                         }\r
509                         break;\r
510                 case ID_REVERTTOREV:\r
511                         {\r
512                                 // we need an URL to complete this command, so error out if we can't get an URL\r
513                                 if (pathURL.IsEmpty())\r
514                                 {\r
515                                         CString strMessage;\r
516                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
517                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
518                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
519                                         break;          //exit\r
520                                 }\r
521 \r
522                                 CString msg;\r
523                                 msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
524                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
525                                 {\r
526                                         CGitProgressDlg dlg;\r
527                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
528                                         dlg.SetPathList(CTGitPathList(m_path));\r
529                                         dlg.SetUrl(pathURL);\r
530                                         dlg.SetSecondUrl(pathURL);\r
531                                         GitRevRangeArray revarray;\r
532                                         revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
533                                         dlg.SetRevisionRanges(revarray);\r
534                                         dlg.SetPegRevision(m_LogRevision);\r
535                                         dlg.DoModal();\r
536                                 }\r
537                         }\r
538                         break;\r
539         \r
540 \r
541         \r
542                 case ID_BLAMECOMPARE:\r
543                         {\r
544                                 //user clicked on the menu item "compare with working copy"\r
545                                 //now first get the revision which is selected\r
546                                 if (PromptShown())\r
547                                 {\r
548                                         GitDiff diff(this, this->m_hWnd, true);\r
549                                         diff.SetHEADPeg(m_LogRevision);\r
550                                         diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
551                                 }\r
552                                 else\r
553                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
554                         }\r
555                         break;\r
556                 case ID_BLAMETWO:\r
557                         {\r
558                                 //user clicked on the menu item "compare and blame revisions"\r
559                                 if (PromptShown())\r
560                                 {\r
561                                         GitDiff diff(this, this->m_hWnd, true);\r
562                                         diff.SetHEADPeg(m_LogRevision);\r
563                                         diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
564                                 }\r
565                                 else\r
566                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
567                         }\r
568                         break;\r
569                 case ID_BLAMEWITHPREVIOUS:\r
570                         {\r
571                                 //user clicked on the menu item "Compare and Blame with previous revision"\r
572                                 if (PromptShown())\r
573                                 {\r
574                                         GitDiff diff(this, this->m_hWnd, true);\r
575                                         diff.SetHEADPeg(m_LogRevision);\r
576                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
577                                 }\r
578                                 else\r
579                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
580                         }\r
581                         break;\r
582                 \r
583                 case ID_OPENWITH:\r
584                         bOpenWith = true;\r
585                 case ID_OPEN:\r
586                         {\r
587                                 CProgressDlg progDlg;\r
588                                 progDlg.SetTitle(IDS_APPNAME);\r
589                                 progDlg.SetAnimation(IDR_DOWNLOAD);\r
590                                 CString sInfoLine;\r
591                                 sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
592                                 progDlg.SetLine(1, sInfoLine, true);\r
593                                 SetAndClearProgressInfo(&progDlg);\r
594                                 progDlg.ShowModeless(m_hWnd);\r
595                                 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
596                                 bool bSuccess = true;\r
597                                 if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
598                                 {\r
599                                         bSuccess = false;\r
600                                         // try again, but with the selected revision as the peg revision\r
601                                         if (!Cat(m_path, revSelected, revSelected, tempfile))\r
602                                         {\r
603                                                 progDlg.Stop();\r
604                                                 SetAndClearProgressInfo((HWND)NULL);\r
605                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
606                                                 EnableOKButton();\r
607                                                 break;\r
608                                         }\r
609                                         bSuccess = true;\r
610                                 }\r
611                                 if (bSuccess)\r
612                                 {\r
613                                         progDlg.Stop();\r
614                                         SetAndClearProgressInfo((HWND)NULL);\r
615                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
616                                         int ret = 0;\r
617                                         if (!bOpenWith)\r
618                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
619                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
620                                         {\r
621                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
622                                                 cmd += tempfile.GetWinPathString() + _T(" ");\r
623                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
624                                         }\r
625                                 }\r
626                         }\r
627                         break;\r
628                 case ID_BLAME:\r
629                         {\r
630                                 CBlameDlg dlg;\r
631                                 dlg.EndRev = revSelected;\r
632                                 if (dlg.DoModal() == IDOK)\r
633                                 {\r
634                                         CBlame blame;\r
635                                         CString tempfile;\r
636                                         CString logfile;\r
637                                         tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
638                                         if (!tempfile.IsEmpty())\r
639                                         {\r
640                                                 if (dlg.m_bTextView)\r
641                                                 {\r
642                                                         //open the default text editor for the result file\r
643                                                         CAppUtils::StartTextViewer(tempfile);\r
644                                                 }\r
645                                                 else\r
646                                                 {\r
647                                                         CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
648                                                         if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
649                                                         {\r
650                                                                 break;\r
651                                                         }\r
652                                                 }\r
653                                         }\r
654                                         else\r
655                                         {\r
656                                                 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
657                                         }\r
658                                 }\r
659                         }\r
660                         break;\r
661                 case ID_UPDATE:\r
662                         {\r
663                                 CString sCmd;\r
664                                 CString url = _T("tgit:")+pathURL;\r
665                                 sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
666                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
667                                         (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
668                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
669                         }\r
670                         break;\r
671                 case ID_FINDENTRY:\r
672                         {\r
673                                 m_nSearchIndex = GetSelectionMark();\r
674                                 if (m_nSearchIndex < 0)\r
675                                         m_nSearchIndex = 0;\r
676                                 if (m_pFindDialog)\r
677                                 {\r
678                                         break;\r
679                                 }\r
680                                 else\r
681                                 {\r
682                                         m_pFindDialog = new CFindReplaceDialog();\r
683                                         m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
684                                 }\r
685                         }\r
686                         break;\r
687                 case ID_REPOBROWSE:\r
688                         {\r
689                                 CString sCmd;\r
690                                 sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
691                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
692                                         (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
693 \r
694                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
695                         }\r
696                         break;\r
697                 case ID_EDITLOG:\r
698                         {\r
699                                 EditLogMessage(selIndex);\r
700                         }\r
701                         break;\r
702                 case ID_EDITAUTHOR:\r
703                         {\r
704                                 EditAuthor(selEntries);\r
705                         }\r
706                         break;\r
707                 case ID_REVPROPS:\r
708                         {\r
709                                 CEditPropertiesDlg dlg;\r
710                                 dlg.SetProjectProperties(&m_ProjectProperties);\r
711                                 CTGitPathList escapedlist;\r
712                                 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
713                                 dlg.SetRevision(revSelected);\r
714                                 dlg.RevProps(true);\r
715                                 dlg.DoModal();\r
716                         }\r
717                         break;\r
718                 \r
719                 case ID_EXPORT:\r
720                         {\r
721                                 CString sCmd;\r
722                                 sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
723                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
724                                         (LPCTSTR)pathURL, (LONG)revSelected);\r
725                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
726                         }\r
727                         break;\r
728                 case ID_CHECKOUT:\r
729                         {\r
730                                 CString sCmd;\r
731                                 CString url = _T("tgit:")+pathURL;\r
732                                 sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
733                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
734                                         (LPCTSTR)url, (LONG)revSelected);\r
735                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
736                         }\r
737                         break;\r
738                 case ID_VIEWREV:\r
739                         {\r
740                                 CString url = m_ProjectProperties.sWebViewerRev;\r
741                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
742                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
743                                 if (!url.IsEmpty())\r
744                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
745                         }\r
746                         break;\r
747                 case ID_VIEWPATHREV:\r
748                         {\r
749                                 CString relurl = pathURL;\r
750                                 CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
751                                 relurl = relurl.Mid(sRoot.GetLength());\r
752                                 CString url = m_ProjectProperties.sWebViewerPathRev;\r
753                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
754                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
755                                 url.Replace(_T("%PATH%"), relurl);\r
756                                 if (!url.IsEmpty())\r
757                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
758                         }\r
759                         break;\r
760 #endif\r
761                 \r
762                 } // switch (cmd)\r
763 \r
764                 theApp.DoWaitCursor(-1);\r
765 }\r
766 \r
767 void CGitLogList::SetSelectedAction(int action)\r
768 {\r
769         POSITION pos = GetFirstSelectedItemPosition();\r
770         int index;\r
771         while(pos)\r
772         {\r
773                 index = GetNextSelectedItem(pos);\r
774                 ((GitRev*)m_arShownList[index])->m_Action = action;\r
775                 CRect rect;\r
776                 this->GetItemRect(index,&rect,LVIR_BOUNDS);\r
777                 this->InvalidateRect(rect);\r
778 \r
779         }\r
780 \r
781 }