OSDN Git Service

Impliment commit command at log dialog when choose work copy
[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&0xFFFF)\r
111                 {\r
112                         case ID_COMMIT:\r
113                         {\r
114                                 CTGitPathList pathlist;\r
115                                 bool bSelectFilesForCommit = !!DWORD(CRegStdWORD(_T("Software\\TortoiseGit\\SelectFilesForCommit"), TRUE));\r
116                                 CAppUtils::Commit(CString(),true,CString(),\r
117                                                                   pathlist,pathlist,bSelectFilesForCommit);\r
118                                 this->Refresh();\r
119                                                                   \r
120                         }\r
121                         break;\r
122                         case ID_GNUDIFF1:\r
123                         {\r
124                                 CString tempfile=GetTempFile();\r
125                                 CString cmd;\r
126                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
127                                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s"),r1->m_CommitHash);\r
128                                 g_Git.RunLogFile(cmd,tempfile);\r
129                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r1->m_Subject);\r
130                         }\r
131                         break;\r
132 \r
133                         case ID_GNUDIFF2:\r
134                         {\r
135                                 CString tempfile=GetTempFile();\r
136                                 CString cmd;\r
137                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
138                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
139                                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s %s"),r1->m_CommitHash,r2->m_CommitHash);\r
140                                 g_Git.RunLogFile(cmd,tempfile);\r
141                                 CAppUtils::StartUnifiedDiffViewer(tempfile,r1->m_CommitHash.Left(6)+_T(":")+r2->m_CommitHash.Left(6));\r
142 \r
143                         }\r
144                         break;\r
145   \r
146                 case ID_COMPARETWO:\r
147                         {\r
148                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
149                                 GitRev * r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
150                                 CFileDiffDlg dlg;\r
151                                 dlg.SetDiff(NULL,*r1,*r2);\r
152                                 dlg.DoModal();\r
153                                 \r
154                         }\r
155                         break;\r
156                 \r
157 \r
158                 case ID_COMPARE:\r
159                         {\r
160                                 GitRev * r1 = &m_wcRev;\r
161                                 GitRev * r2 = pSelLogEntry;\r
162                                 CFileDiffDlg dlg;\r
163                                 dlg.SetDiff(NULL,*r1,*r2);\r
164                                 dlg.DoModal();\r
165 \r
166                                 //user clicked on the menu item "compare with working copy"\r
167                                 //if (PromptShown())\r
168                                 //{\r
169                                 //      GitDiff diff(this, m_hWnd, true);\r
170                                 //      diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
171                                 //      diff.SetHEADPeg(m_LogRevision);\r
172                                 //      diff.ShowCompare(m_path, GitRev::REV_WC, m_path, revSelected);\r
173                                 //}\r
174                                 //else\r
175                                 //      CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_WC, m_path, revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
176                         }\r
177                         break;\r
178 \r
179                 case ID_COMPAREWITHPREVIOUS:\r
180                         {\r
181 \r
182                                 CFileDiffDlg dlg;\r
183                                 \r
184                                 if(pSelLogEntry->m_ParentHash.size()>0)\r
185                                 //if(m_logEntries.m_HashMap[pSelLogEntry->m_ParentHash[0]]>=0)\r
186                                 {\r
187                                         dlg.SetDiff(NULL,pSelLogEntry->m_CommitHash,pSelLogEntry->m_ParentHash[0]);\r
188                                         dlg.DoModal();\r
189                                 }else\r
190                                 {\r
191                                         CMessageBox::Show(NULL,_T("No previous version"),_T("TortoiseGit"),MB_OK);      \r
192                                 }\r
193                                 //if (PromptShown())\r
194                                 //{\r
195                                 //      GitDiff diff(this, m_hWnd, true);\r
196                                 //      diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
197                                 //      diff.SetHEADPeg(m_LogRevision);\r
198                                 //      diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected);\r
199                                 //}\r
200                                 //else\r
201                                 //      CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
202                         }\r
203                         break;\r
204                 case ID_COPYCLIPBOARD:\r
205                         {\r
206                                 CopySelectionToClipBoard();\r
207                         }\r
208                         break;\r
209                 case ID_COPYHASH:\r
210                         {\r
211                                 CopySelectionToClipBoard(TRUE);\r
212                         }\r
213                         break;\r
214                 case ID_EXPORT:\r
215                         CAppUtils::Export(&pSelLogEntry->m_CommitHash);\r
216                         break;\r
217                 case ID_CREATE_BRANCH:\r
218                         CAppUtils::CreateBranchTag(FALSE,&pSelLogEntry->m_CommitHash);\r
219                         ReloadHashMap();\r
220                         Invalidate();                   \r
221                         break;\r
222                 case ID_CREATE_TAG:\r
223                         CAppUtils::CreateBranchTag(TRUE,&pSelLogEntry->m_CommitHash);\r
224                         ReloadHashMap();\r
225                         Invalidate();\r
226                         break;\r
227                 case ID_SWITCHTOREV:\r
228                         CAppUtils::Switch(&pSelLogEntry->m_CommitHash);\r
229                         ReloadHashMap();\r
230                         Invalidate();\r
231                         break;\r
232                 case ID_RESET:\r
233                         CAppUtils::GitReset(&pSelLogEntry->m_CommitHash);\r
234                         ReloadHashMap();\r
235                         Invalidate();\r
236                         break;\r
237                 case ID_REBASE_PICK:\r
238                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK);\r
239                         break;\r
240                 case ID_REBASE_EDIT:\r
241                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT);\r
242                         break;\r
243                 case ID_REBASE_SQUASH:\r
244                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);\r
245                         break;\r
246                 case ID_REBASE_SKIP:\r
247                         SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP);\r
248                         break;\r
249                 case ID_COMBINE_COMMIT:\r
250                 {\r
251                         CString head;\r
252                         CString headhash;\r
253                         CString hashFirst,hashLast;\r
254 \r
255                         int headindex=GetHeadIndex();\r
256                         if(headindex>=0) //incase show all branch, head is not the first commits. \r
257                         {\r
258                                 head.Format(_T("HEAD~%d"),FirstSelect-headindex);\r
259                                 hashFirst=g_Git.GetHash(head);\r
260 \r
261                                 head.Format(_T("HEAD~%d"),LastSelect-headindex);\r
262                                 hashLast=g_Git.GetHash(head);\r
263                         }\r
264                                                 \r
265                         GitRev* pFirstEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
266                         GitRev* pLastEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
267                         if(pFirstEntry->m_CommitHash != hashFirst || pLastEntry->m_CommitHash != hashLast)\r
268                         {\r
269                                 CMessageBox::Show(NULL,_T(\r
270                                         "Cannot combine commits now.\r\n\\r
271                                         Make sure you are viewing the log of your current branch and \\r
272                                         no filters are applied."),_T("TortoiseGit"),MB_OK);\r
273                                 break;\r
274                         }\r
275                         \r
276                         headhash=g_Git.GetHash(CString(_T("HEAD")));\r
277                         \r
278                         if(!g_Git.CheckCleanWorkTree())\r
279                         {\r
280                                 CMessageBox::Show(NULL,_T("Combine needs a clean work tree"),_T("TortoiseGit"),MB_OK);\r
281                                 break;\r
282                         }\r
283                         CString cmd,out;\r
284 \r
285                         //Use throw to abort this process (reset back to original HEAD)\r
286                         try\r
287                         {\r
288                                 cmd.Format(_T("git.exe reset --hard  %s"),pFirstEntry->m_CommitHash);\r
289                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
290                                 {\r
291                                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
292                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to first commit (first step) aborting...\r\n\r\n")+out));\r
293                                 }\r
294                                 cmd.Format(_T("git.exe reset --mixed  %s"),hashLast);\r
295                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
296                                 {\r
297                                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
298                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to last commit (second step) aborting...\r\n\r\n")+out));\r
299                                 }\r
300                                 CCommitDlg dlg;\r
301                                 for(int i=FirstSelect;i<=LastSelect;i++)\r
302                                 {\r
303                                         GitRev* pRev = reinterpret_cast<GitRev*>(m_arShownList.GetAt(i));\r
304                                         dlg.m_sLogMessage+=pRev->m_Subject+_T("\n")+pRev->m_Body;\r
305                                         dlg.m_sLogMessage+=_T("\n");\r
306                                 }\r
307                                 dlg.m_bWholeProject=true;\r
308                                 dlg.m_bSelectFilesForCommit = true;\r
309                                 dlg.m_bCommitAmend=true;\r
310                                 dlg.m_AmendStr=dlg.m_sLogMessage;\r
311 \r
312                                 bool abort=false;\r
313                                 if (dlg.DoModal() == IDOK)\r
314                                 {\r
315                                         if(pFirstEntry->m_CommitHash!=headhash)\r
316                                         {\r
317                                                 //Commitrange firstEntry..headhash (from top of combine to original head) needs to be 'cherry-picked'\r
318                                                 //on top of new commit.\r
319                                                 //Use the rebase --onto command for it.\r
320                                                 //\r
321                                                 //All this can be done in one step using the following command:\r
322                                                 //cmd.Format(_T("git.exe format-patch --stdout --binary --full-index -k %s..%s | git am -k -3"),\r
323                                                 //      pFirstEntry->m_CommitHash,\r
324                                                 //      headhash);\r
325                                                 //But I am not sure if a '|' is going to work in a CreateProcess() call.\r
326                                                 //\r
327                                                 //Later the progress dialog could be used to execute these steps.\r
328 \r
329                                                 if(CherryPickFrom(pFirstEntry->m_CommitHash,headhash))\r
330                                                 {\r
331                                                         CString msg;\r
332                                                         msg.Format(_T("Error while cherry pick commits on top of combined commits. Aborting.\r\n\r\n"));\r
333                                                         throw std::exception(CUnicodeUtils::GetUTF8(msg));\r
334                                                 }\r
335 #if 0\r
336                                                 CString currentBranch=g_Git.GetCurrentBranch();\r
337                                                 cmd.Format(_T("git.exe rebase --onto \"%s\" %s %s"),\r
338                                                         currentBranch,\r
339                                                         pFirstEntry->m_CommitHash,\r
340                                                         headhash);\r
341                                                 if(g_Git.Run(cmd,&out,CP_UTF8)!=0)\r
342                                                 {\r
343                                                         CString msg;\r
344                                                         msg.Format(_T("Error while rebasing commits on top of combined commits. Aborting.\r\n\r\n%s"),out);\r
345 //                                                      CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_OK);\r
346                                                         g_Git.Run(_T("git.exe rebase --abort"),&out,CP_UTF8);\r
347                                                         throw std::exception(CUnicodeUtils::GetUTF8(msg));\r
348                                                 }\r
349 \r
350                                                 //HEAD is now on <no branch>. \r
351                                                 //The following steps are to get HEAD back on the original branch and reset the branch to the new HEAD\r
352                                                 //To avoid 2 working copy changes, we could use git branch -f <original branch> <hash new head> \r
353                                                 //And then git checkout <original branch>\r
354                                                 //But I don't know if 'git branch -f' removes tracking options. So for now, do a checkout and a reset.\r
355                                                 \r
356                                                 //Store new HEAD\r
357                                                 CString newHead=g_Git.GetHash(CString(_T("HEAD")));\r
358 \r
359                                                 //Checkout working branch\r
360                                                 cmd.Format(_T("git.exe checkout -f \"%s\""),currentBranch);\r
361                                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
362                                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not checkout original branch. Aborting...\r\n\r\n")+out));\r
363 \r
364                                                 //Reset to new HEAD\r
365                                                 cmd.Format(_T("git.exe reset --hard  %s"),newHead);\r
366                                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
367                                                         throw std::exception(CUnicodeUtils::GetUTF8(_T("Could not reset to new head. Aborting...\r\n\r\n")+out));\r
368 #endif\r
369                                         }\r
370                                 }\r
371                                 else\r
372                                         throw std::exception("User aborted the combine process");\r
373                         }\r
374                         catch(std::exception& e)\r
375                         {\r
376                                 CMessageBox::Show(NULL,CUnicodeUtils::GetUnicode(CStringA(e.what())),_T("TortoiseGit: Combine error"),MB_OK|MB_ICONERROR);\r
377                                 cmd.Format(_T("git.exe reset --hard  %s"),headhash);\r
378                                 out.Empty();\r
379                                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
380                                 {\r
381                                         CMessageBox::Show(NULL,_T("Could not reset to original HEAD\r\n\r\n")+out,_T("TortoiseGit"),MB_OK);\r
382                                 }\r
383                         }\r
384                         Refresh();\r
385                 }\r
386                         break;\r
387 \r
388                 case ID_CHERRY_PICK:\r
389                         if(!g_Git.CheckCleanWorkTree())\r
390                         {\r
391                                 CMessageBox::Show(NULL,_T("Cherry Pick requires a clean working tree"),_T("TortoiseGit"),MB_OK);\r
392                         \r
393                         }else\r
394                         {\r
395                                 CRebaseDlg dlg;\r
396                                 dlg.m_IsCherryPick = TRUE;\r
397                                 dlg.m_Upstream = this->m_CurrentBranch;\r
398                                 POSITION pos = GetFirstSelectedItemPosition();\r
399                                 while(pos)\r
400                                 {\r
401                                         int indexNext = GetNextSelectedItem(pos);\r
402                                         dlg.m_CommitList.m_logEntries.push_back(*(GitRev*)m_arShownList[indexNext]);\r
403                                         dlg.m_CommitList.m_logEntries.at(dlg.m_CommitList.m_logEntries.size()-1).m_Action |= CTGitPath::LOGACTIONS_REBASE_PICK;\r
404                                 }\r
405         \r
406                                 if(dlg.DoModal() == IDOK)\r
407                                 {\r
408                                         Refresh();\r
409                                 }\r
410                         }\r
411                         break;\r
412                 case ID_REBASE_TO_VERSION:\r
413                         if(!g_Git.CheckCleanWorkTree())\r
414                         {\r
415                                 CMessageBox::Show(NULL,_T("Rebase requires a clean working tree"),_T("TortoiseGit"),MB_OK);\r
416                         \r
417                         }else\r
418                         {\r
419                                 CRebaseDlg dlg;\r
420                                 dlg.m_Upstream = pSelLogEntry->m_CommitHash;\r
421 \r
422                                 if(dlg.DoModal() == IDOK)\r
423                                 {\r
424                                         Refresh();\r
425                                 }\r
426                         }\r
427 \r
428                         break;\r
429 \r
430                 case ID_STASH_APPLY:\r
431                         CAppUtils::StashApply(pSelLogEntry->m_Ref);\r
432                         break;\r
433                 \r
434                 case ID_REFLOG_DEL:\r
435                         {       \r
436                                 CString str;\r
437                                 str.Format(_T("Warning: %s will be permanently deleted. It can <ct=0x0000FF><b>NOT</b></ct> be recovered!\r\n \r\n Are you sure you want to continue?"),pSelLogEntry->m_Ref);\r
438                                 if(CMessageBox::Show(NULL,str,_T("TortoiseGit"),MB_YESNO|MB_ICONWARNING) == IDYES)\r
439                                 {\r
440                                         CString cmd,out;\r
441                                         cmd.Format(_T("git.exe reflog delete %s"),pSelLogEntry->m_Ref);\r
442                                         if(g_Git.Run(cmd,&out,CP_ACP))\r
443                                         {\r
444                                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
445                                         }                                               \r
446                                         ::PostMessage(this->GetParent()->m_hWnd,MSG_REFLOG_CHANGED,0,0);\r
447                                 }\r
448                         }\r
449                         break;\r
450                 case ID_CREATE_PATCH:\r
451                         {\r
452                                 int select=this->GetSelectedCount();\r
453                                 CString cmd;\r
454                                 cmd = CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe");\r
455                                 cmd += _T(" /command:formatpatch");\r
456 \r
457                                 cmd += _T(" /path:")+g_Git.m_CurrentDir+_T(" ");\r
458 \r
459                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
460                                 GitRev * r2 = NULL;\r
461                                 if(select == 1)\r
462                                 {\r
463                                         cmd += _T(" /startrev:")+r1->m_CommitHash;\r
464                                 }\r
465                                 else \r
466                                 {\r
467                                         r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
468                                         if( this->m_IsOldFirst )\r
469                                         {       \r
470                                                 cmd += _T(" /startrev:")+r1->m_CommitHash+_T("~1");\r
471                                                 cmd += _T(" /endrev:")+r2->m_CommitHash;\r
472         \r
473                                         }else\r
474                                         {       \r
475                                                 cmd += _T(" /startrev:")+r2->m_CommitHash+_T("~1");\r
476                                                 cmd += _T(" /endrev:")+r1->m_CommitHash;        \r
477                                         }                               \r
478                                         \r
479                                 }\r
480 \r
481                                 CAppUtils::LaunchApplication(cmd,IDS_ERR_PROC,false);\r
482                         }\r
483                         break;\r
484                 case ID_DELETE:\r
485                         {\r
486                                 int index = cmd>>16;\r
487                                 if( this->m_HashMap.find(pSelLogEntry->m_CommitHash) == m_HashMap.end() )\r
488                                 {\r
489                                         CMessageBox::Show(NULL,IDS_ERROR_NOREF,IDS_APPNAME,MB_OK|MB_ICONERROR);\r
490                                         return;\r
491                                 }\r
492                                 if( index >= m_HashMap[pSelLogEntry->m_CommitHash].size())\r
493                                 {\r
494                                         CMessageBox::Show(NULL,IDS_ERROR_INDEX,IDS_APPNAME,MB_OK|MB_ICONERROR);\r
495                                         return;                         \r
496                                 }\r
497                                 CString ref,msg;\r
498                                 ref=m_HashMap[pSelLogEntry->m_CommitHash][index];\r
499                                 \r
500                                 msg=CString(_T("<ct=0x0000FF>Delete</ct> <b>"))+ref;\r
501                                 msg+=_T("</b>\n\n Are you sure?");\r
502                                 if( CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_YESNO) == IDYES )\r
503                                 {\r
504                                         CString shortname;\r
505                                         CString cmd;\r
506                                         if(this->GetShortName(ref,shortname,_T("refs/heads/")))\r
507                                         {\r
508                                                 cmd.Format(_T("git.exe branch -D %s"),shortname);\r
509                                         }\r
510 \r
511                                         if(this->GetShortName(ref,shortname,_T("refs/remotes/")))\r
512                                         {\r
513                                                 cmd.Format(_T("git.exe branch -r -D %s"),shortname);\r
514                                         }\r
515 \r
516                                         if(this->GetShortName(ref,shortname,_T("refs/tags/")))\r
517                                         {\r
518                                                 cmd.Format(_T("git.exe tag -d %s"),shortname);\r
519                                         }\r
520 \r
521                                         if(this->GetShortName(ref,shortname,_T("refs/stash")))\r
522                                         {\r
523                                                 if(CMessageBox::Show(NULL,_T("<ct=0x0000FF>Are you sure remove <b>ALL</b> stash?</ct>"),\r
524                                                                                            _T("TortoiseGit"),MB_YESNO)==IDYES)\r
525                                                         cmd.Format(_T("git.exe stash clear"));\r
526                                                 else\r
527                                                         return;\r
528                                         }\r
529 \r
530                                         CString out;\r
531                                         if(g_Git.Run(cmd,&out,CP_UTF8))\r
532                                         {\r
533                                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
534                                         }\r
535                                         this->ReloadHashMap();\r
536                                         CRect rect;\r
537                                         this->GetItemRect(FirstSelect,&rect,LVIR_BOUNDS);\r
538                                         this->InvalidateRect(rect);\r
539                                 }\r
540                         }\r
541                         break;\r
542                 default:\r
543                         //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);\r
544                         break;\r
545 #if 0\r
546         \r
547                 case ID_REVERTREV:\r
548                         {\r
549                                 // we need an URL to complete this command, so error out if we can't get an URL\r
550                                 if (pathURL.IsEmpty())\r
551                                 {\r
552                                         CString strMessage;\r
553                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
554                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
555                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
556                                         break;          //exit\r
557                                 }\r
558                                 CString msg;\r
559                                 msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
560                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
561                                 {\r
562                                         CGitProgressDlg dlg;\r
563                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
564                                         dlg.SetPathList(CTGitPathList(m_path));\r
565                                         dlg.SetUrl(pathURL);\r
566                                         dlg.SetSecondUrl(pathURL);\r
567                                         revisionRanges.AdjustForMerge(true);\r
568                                         dlg.SetRevisionRanges(revisionRanges);\r
569                                         dlg.SetPegRevision(m_LogRevision);\r
570                                         dlg.DoModal();\r
571                                 }\r
572                         }\r
573                         break;\r
574                 case ID_MERGEREV:\r
575                         {\r
576                                 // we need an URL to complete this command, so error out if we can't get an URL\r
577                                 if (pathURL.IsEmpty())\r
578                                 {\r
579                                         CString strMessage;\r
580                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
581                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
582                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
583                                         break;          //exit\r
584                                 }\r
585 \r
586                                 CString path = m_path.GetWinPathString();\r
587                                 bool bGotSavePath = false;\r
588                                 if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
589                                 {\r
590                                         bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
591                                 }\r
592                                 else\r
593                                 {\r
594                                         CBrowseFolder folderBrowser;\r
595                                         folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
596                                         bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
597                                 }\r
598                                 if (bGotSavePath)\r
599                                 {\r
600                                         CGitProgressDlg dlg;\r
601                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
602                                         dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
603                                         dlg.SetUrl(pathURL);\r
604                                         dlg.SetSecondUrl(pathURL);\r
605                                         revisionRanges.AdjustForMerge(false);\r
606                                         dlg.SetRevisionRanges(revisionRanges);\r
607                                         dlg.SetPegRevision(m_LogRevision);\r
608                                         dlg.DoModal();\r
609                                 }\r
610                         }\r
611                         break;\r
612                 case ID_REVERTTOREV:\r
613                         {\r
614                                 // we need an URL to complete this command, so error out if we can't get an URL\r
615                                 if (pathURL.IsEmpty())\r
616                                 {\r
617                                         CString strMessage;\r
618                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
619                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
620                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
621                                         break;          //exit\r
622                                 }\r
623 \r
624                                 CString msg;\r
625                                 msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
626                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
627                                 {\r
628                                         CGitProgressDlg dlg;\r
629                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
630                                         dlg.SetPathList(CTGitPathList(m_path));\r
631                                         dlg.SetUrl(pathURL);\r
632                                         dlg.SetSecondUrl(pathURL);\r
633                                         GitRevRangeArray revarray;\r
634                                         revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
635                                         dlg.SetRevisionRanges(revarray);\r
636                                         dlg.SetPegRevision(m_LogRevision);\r
637                                         dlg.DoModal();\r
638                                 }\r
639                         }\r
640                         break;\r
641         \r
642 \r
643         \r
644                 case ID_BLAMECOMPARE:\r
645                         {\r
646                                 //user clicked on the menu item "compare with working copy"\r
647                                 //now first get the revision which is selected\r
648                                 if (PromptShown())\r
649                                 {\r
650                                         GitDiff diff(this, this->m_hWnd, true);\r
651                                         diff.SetHEADPeg(m_LogRevision);\r
652                                         diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
653                                 }\r
654                                 else\r
655                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
656                         }\r
657                         break;\r
658                 case ID_BLAMETWO:\r
659                         {\r
660                                 //user clicked on the menu item "compare and blame revisions"\r
661                                 if (PromptShown())\r
662                                 {\r
663                                         GitDiff diff(this, this->m_hWnd, true);\r
664                                         diff.SetHEADPeg(m_LogRevision);\r
665                                         diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
666                                 }\r
667                                 else\r
668                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
669                         }\r
670                         break;\r
671                 case ID_BLAMEWITHPREVIOUS:\r
672                         {\r
673                                 //user clicked on the menu item "Compare and Blame with previous revision"\r
674                                 if (PromptShown())\r
675                                 {\r
676                                         GitDiff diff(this, this->m_hWnd, true);\r
677                                         diff.SetHEADPeg(m_LogRevision);\r
678                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
679                                 }\r
680                                 else\r
681                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
682                         }\r
683                         break;\r
684                 \r
685                 case ID_OPENWITH:\r
686                         bOpenWith = true;\r
687                 case ID_OPEN:\r
688                         {\r
689                                 CProgressDlg progDlg;\r
690                                 progDlg.SetTitle(IDS_APPNAME);\r
691                                 progDlg.SetAnimation(IDR_DOWNLOAD);\r
692                                 CString sInfoLine;\r
693                                 sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
694                                 progDlg.SetLine(1, sInfoLine, true);\r
695                                 SetAndClearProgressInfo(&progDlg);\r
696                                 progDlg.ShowModeless(m_hWnd);\r
697                                 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
698                                 bool bSuccess = true;\r
699                                 if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
700                                 {\r
701                                         bSuccess = false;\r
702                                         // try again, but with the selected revision as the peg revision\r
703                                         if (!Cat(m_path, revSelected, revSelected, tempfile))\r
704                                         {\r
705                                                 progDlg.Stop();\r
706                                                 SetAndClearProgressInfo((HWND)NULL);\r
707                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
708                                                 EnableOKButton();\r
709                                                 break;\r
710                                         }\r
711                                         bSuccess = true;\r
712                                 }\r
713                                 if (bSuccess)\r
714                                 {\r
715                                         progDlg.Stop();\r
716                                         SetAndClearProgressInfo((HWND)NULL);\r
717                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
718                                         int ret = 0;\r
719                                         if (!bOpenWith)\r
720                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
721                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
722                                         {\r
723                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
724                                                 cmd += tempfile.GetWinPathString() + _T(" ");\r
725                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
726                                         }\r
727                                 }\r
728                         }\r
729                         break;\r
730                 case ID_BLAME:\r
731                         {\r
732                                 CBlameDlg dlg;\r
733                                 dlg.EndRev = revSelected;\r
734                                 if (dlg.DoModal() == IDOK)\r
735                                 {\r
736                                         CBlame blame;\r
737                                         CString tempfile;\r
738                                         CString logfile;\r
739                                         tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
740                                         if (!tempfile.IsEmpty())\r
741                                         {\r
742                                                 if (dlg.m_bTextView)\r
743                                                 {\r
744                                                         //open the default text editor for the result file\r
745                                                         CAppUtils::StartTextViewer(tempfile);\r
746                                                 }\r
747                                                 else\r
748                                                 {\r
749                                                         CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
750                                                         if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
751                                                         {\r
752                                                                 break;\r
753                                                         }\r
754                                                 }\r
755                                         }\r
756                                         else\r
757                                         {\r
758                                                 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
759                                         }\r
760                                 }\r
761                         }\r
762                         break;\r
763                 case ID_UPDATE:\r
764                         {\r
765                                 CString sCmd;\r
766                                 CString url = _T("tgit:")+pathURL;\r
767                                 sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
768                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
769                                         (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
770                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
771                         }\r
772                         break;\r
773                 case ID_FINDENTRY:\r
774                         {\r
775                                 m_nSearchIndex = GetSelectionMark();\r
776                                 if (m_nSearchIndex < 0)\r
777                                         m_nSearchIndex = 0;\r
778                                 if (m_pFindDialog)\r
779                                 {\r
780                                         break;\r
781                                 }\r
782                                 else\r
783                                 {\r
784                                         m_pFindDialog = new CFindReplaceDialog();\r
785                                         m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
786                                 }\r
787                         }\r
788                         break;\r
789                 case ID_REPOBROWSE:\r
790                         {\r
791                                 CString sCmd;\r
792                                 sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
793                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
794                                         (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
795 \r
796                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
797                         }\r
798                         break;\r
799                 case ID_EDITLOG:\r
800                         {\r
801                                 EditLogMessage(selIndex);\r
802                         }\r
803                         break;\r
804                 case ID_EDITAUTHOR:\r
805                         {\r
806                                 EditAuthor(selEntries);\r
807                         }\r
808                         break;\r
809                 case ID_REVPROPS:\r
810                         {\r
811                                 CEditPropertiesDlg dlg;\r
812                                 dlg.SetProjectProperties(&m_ProjectProperties);\r
813                                 CTGitPathList escapedlist;\r
814                                 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
815                                 dlg.SetRevision(revSelected);\r
816                                 dlg.RevProps(true);\r
817                                 dlg.DoModal();\r
818                         }\r
819                         break;\r
820                 \r
821                 case ID_EXPORT:\r
822                         {\r
823                                 CString sCmd;\r
824                                 sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
825                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
826                                         (LPCTSTR)pathURL, (LONG)revSelected);\r
827                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
828                         }\r
829                         break;\r
830                 case ID_CHECKOUT:\r
831                         {\r
832                                 CString sCmd;\r
833                                 CString url = _T("tgit:")+pathURL;\r
834                                 sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
835                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
836                                         (LPCTSTR)url, (LONG)revSelected);\r
837                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
838                         }\r
839                         break;\r
840                 case ID_VIEWREV:\r
841                         {\r
842                                 CString url = m_ProjectProperties.sWebViewerRev;\r
843                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
844                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
845                                 if (!url.IsEmpty())\r
846                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
847                         }\r
848                         break;\r
849                 case ID_VIEWPATHREV:\r
850                         {\r
851                                 CString relurl = pathURL;\r
852                                 CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
853                                 relurl = relurl.Mid(sRoot.GetLength());\r
854                                 CString url = m_ProjectProperties.sWebViewerPathRev;\r
855                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
856                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
857                                 url.Replace(_T("%PATH%"), relurl);\r
858                                 if (!url.IsEmpty())\r
859                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
860                         }\r
861                         break;\r
862 #endif\r
863                 \r
864                 } // switch (cmd)\r
865 \r
866                 theApp.DoWaitCursor(-1);\r
867 }\r
868 \r
869 void CGitLogList::SetSelectedAction(int action)\r
870 {\r
871         POSITION pos = GetFirstSelectedItemPosition();\r
872         int index;\r
873         while(pos)\r
874         {\r
875                 index = GetNextSelectedItem(pos);\r
876                 ((GitRev*)m_arShownList[index])->m_Action = action;\r
877                 CRect rect;\r
878                 this->GetItemRect(index,&rect,LVIR_BOUNDS);\r
879                 this->InvalidateRect(rect);\r
880 \r
881         }\r
882 \r
883 }