OSDN Git Service

Fix Issue #111: Undo Add does not work
[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_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 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
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                 case ID_CREATE_PATCH:\r
441                         {\r
442                                 int select=this->GetSelectedCount();\r
443                                 CString cmd;\r
444                                 cmd = CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe");\r
445                                 cmd += _T(" /command:formatpatch");\r
446 \r
447                                 GitRev * r1 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(FirstSelect));\r
448                                 GitRev * r2 = NULL;\r
449                                 if(select == 1)\r
450                                 {\r
451                                         cmd += _T(" /startrev:")+r1->m_CommitHash;\r
452                                 }\r
453                                 else \r
454                                 {\r
455                                         r2 = reinterpret_cast<GitRev*>(m_arShownList.GetAt(LastSelect));\r
456                                         if( this->m_IsOldFirst )\r
457                                         {       \r
458                                                 cmd += _T(" /startrev:")+r1->m_CommitHash;\r
459                                                 cmd += _T(" /endrev:")+r2->m_CommitHash;\r
460         \r
461                                         }else\r
462                                         {       \r
463                                                 cmd += _T(" /startrev:")+r2->m_CommitHash;\r
464                                                 cmd += _T(" /endrev:")+r1->m_CommitHash;        \r
465                                         }                               \r
466                                         \r
467                                 }\r
468 \r
469                                 CAppUtils::LaunchApplication(cmd,IDS_ERR_PROC,false);\r
470                         }\r
471                         break;\r
472                 case ID_DELETE:\r
473                         {\r
474                                 int index = cmd>>16;\r
475                                 if( this->m_HashMap.find(pSelLogEntry->m_CommitHash) == m_HashMap.end() )\r
476                                 {\r
477                                         CMessageBox::Show(NULL,IDS_ERROR_NOREF,IDS_APPNAME,MB_OK|MB_ICONERROR);\r
478                                         return;\r
479                                 }\r
480                                 if( index >= m_HashMap[pSelLogEntry->m_CommitHash].size())\r
481                                 {\r
482                                         CMessageBox::Show(NULL,IDS_ERROR_INDEX,IDS_APPNAME,MB_OK|MB_ICONERROR);\r
483                                         return;                         \r
484                                 }\r
485                                 CString ref,msg;\r
486                                 ref=m_HashMap[pSelLogEntry->m_CommitHash][index];\r
487                                 \r
488                                 msg=CString(_T("<ct=0x0000FF>Delete</ct> <b>"))+ref;\r
489                                 msg+=_T("</b>\n\n Are you sure?");\r
490                                 if( CMessageBox::Show(NULL,msg,_T("TortoiseGit"),MB_YESNO) == IDYES )\r
491                                 {\r
492                                         CString shortname;\r
493                                         CString cmd;\r
494                                         if(this->GetShortName(ref,shortname,_T("refs/heads/")))\r
495                                         {\r
496                                                 cmd.Format(_T("git.exe branch -D %s"),shortname);\r
497                                         }\r
498 \r
499                                         if(this->GetShortName(ref,shortname,_T("refs/remotes/")))\r
500                                         {\r
501                                                 cmd.Format(_T("git.exe branch -r -D %s"),shortname);\r
502                                         }\r
503 \r
504                                         if(this->GetShortName(ref,shortname,_T("refs/tags/")))\r
505                                         {\r
506                                                 cmd.Format(_T("git.exe tag -d %s"),shortname);\r
507                                         }\r
508 \r
509                                         CString out;\r
510                                         if(g_Git.Run(cmd,&out,CP_UTF8))\r
511                                         {\r
512                                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
513                                         }\r
514                                         this->ReloadHashMap();\r
515                                         CRect rect;\r
516                                         this->GetItemRect(FirstSelect,&rect,LVIR_BOUNDS);\r
517                                         this->InvalidateRect(rect);\r
518                                 }\r
519                         }\r
520                         break;\r
521                 default:\r
522                         //CMessageBox::Show(NULL,_T("Have not implemented"),_T("TortoiseGit"),MB_OK);\r
523                         break;\r
524 #if 0\r
525         \r
526                 case ID_REVERTREV:\r
527                         {\r
528                                 // we need an URL to complete this command, so error out if we can't get an URL\r
529                                 if (pathURL.IsEmpty())\r
530                                 {\r
531                                         CString strMessage;\r
532                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
533                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
534                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
535                                         break;          //exit\r
536                                 }\r
537                                 CString msg;\r
538                                 msg.Format(IDS_LOG_REVERT_CONFIRM, m_path.GetWinPath());\r
539                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
540                                 {\r
541                                         CGitProgressDlg dlg;\r
542                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
543                                         dlg.SetPathList(CTGitPathList(m_path));\r
544                                         dlg.SetUrl(pathURL);\r
545                                         dlg.SetSecondUrl(pathURL);\r
546                                         revisionRanges.AdjustForMerge(true);\r
547                                         dlg.SetRevisionRanges(revisionRanges);\r
548                                         dlg.SetPegRevision(m_LogRevision);\r
549                                         dlg.DoModal();\r
550                                 }\r
551                         }\r
552                         break;\r
553                 case ID_MERGEREV:\r
554                         {\r
555                                 // we need an URL to complete this command, so error out if we can't get an URL\r
556                                 if (pathURL.IsEmpty())\r
557                                 {\r
558                                         CString strMessage;\r
559                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
560                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
561                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
562                                         break;          //exit\r
563                                 }\r
564 \r
565                                 CString path = m_path.GetWinPathString();\r
566                                 bool bGotSavePath = false;\r
567                                 if ((GetSelectedCount() == 1)&&(!m_path.IsDirectory()))\r
568                                 {\r
569                                         bGotSavePath = CAppUtils::FileOpenSave(path, NULL, IDS_LOG_MERGETO, IDS_COMMONFILEFILTER, true, GetSafeHwnd());\r
570                                 }\r
571                                 else\r
572                                 {\r
573                                         CBrowseFolder folderBrowser;\r
574                                         folderBrowser.SetInfo(CString(MAKEINTRESOURCE(IDS_LOG_MERGETO)));\r
575                                         bGotSavePath = (folderBrowser.Show(GetSafeHwnd(), path, path) == CBrowseFolder::OK);\r
576                                 }\r
577                                 if (bGotSavePath)\r
578                                 {\r
579                                         CGitProgressDlg dlg;\r
580                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
581                                         dlg.SetPathList(CTGitPathList(CTGitPath(path)));\r
582                                         dlg.SetUrl(pathURL);\r
583                                         dlg.SetSecondUrl(pathURL);\r
584                                         revisionRanges.AdjustForMerge(false);\r
585                                         dlg.SetRevisionRanges(revisionRanges);\r
586                                         dlg.SetPegRevision(m_LogRevision);\r
587                                         dlg.DoModal();\r
588                                 }\r
589                         }\r
590                         break;\r
591                 case ID_REVERTTOREV:\r
592                         {\r
593                                 // we need an URL to complete this command, so error out if we can't get an URL\r
594                                 if (pathURL.IsEmpty())\r
595                                 {\r
596                                         CString strMessage;\r
597                                         strMessage.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)(m_path.GetUIPathString()));\r
598                                         CMessageBox::Show(this->m_hWnd, strMessage, _T("TortoiseGit"), MB_ICONERROR);\r
599                                         TRACE(_T("could not retrieve the URL of the folder!\n"));\r
600                                         break;          //exit\r
601                                 }\r
602 \r
603                                 CString msg;\r
604                                 msg.Format(IDS_LOG_REVERTTOREV_CONFIRM, m_path.GetWinPath());\r
605                                 if (CMessageBox::Show(this->m_hWnd, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)\r
606                                 {\r
607                                         CGitProgressDlg dlg;\r
608                                         dlg.SetCommand(CGitProgressDlg::GitProgress_Merge);\r
609                                         dlg.SetPathList(CTGitPathList(m_path));\r
610                                         dlg.SetUrl(pathURL);\r
611                                         dlg.SetSecondUrl(pathURL);\r
612                                         GitRevRangeArray revarray;\r
613                                         revarray.AddRevRange(GitRev::REV_HEAD, revSelected);\r
614                                         dlg.SetRevisionRanges(revarray);\r
615                                         dlg.SetPegRevision(m_LogRevision);\r
616                                         dlg.DoModal();\r
617                                 }\r
618                         }\r
619                         break;\r
620         \r
621 \r
622         \r
623                 case ID_BLAMECOMPARE:\r
624                         {\r
625                                 //user clicked on the menu item "compare with working copy"\r
626                                 //now first get the revision which is selected\r
627                                 if (PromptShown())\r
628                                 {\r
629                                         GitDiff diff(this, this->m_hWnd, true);\r
630                                         diff.SetHEADPeg(m_LogRevision);\r
631                                         diff.ShowCompare(m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), false, true);\r
632                                 }\r
633                                 else\r
634                                         CAppUtils::StartShowCompare(m_hWnd, m_path, GitRev::REV_BASE, m_path, revSelected, GitRev(), m_LogRevision, false, false, true);\r
635                         }\r
636                         break;\r
637                 case ID_BLAMETWO:\r
638                         {\r
639                                 //user clicked on the menu item "compare and blame revisions"\r
640                                 if (PromptShown())\r
641                                 {\r
642                                         GitDiff diff(this, this->m_hWnd, true);\r
643                                         diff.SetHEADPeg(m_LogRevision);\r
644                                         diff.ShowCompare(CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
645                                 }\r
646                                 else\r
647                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revSelected2, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
648                         }\r
649                         break;\r
650                 case ID_BLAMEWITHPREVIOUS:\r
651                         {\r
652                                 //user clicked on the menu item "Compare and Blame with previous revision"\r
653                                 if (PromptShown())\r
654                                 {\r
655                                         GitDiff diff(this, this->m_hWnd, true);\r
656                                         diff.SetHEADPeg(m_LogRevision);\r
657                                         diff.ShowCompare(CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), false, true);\r
658                                 }\r
659                                 else\r
660                                         CAppUtils::StartShowCompare(m_hWnd, CTGitPath(pathURL), revPrevious, CTGitPath(pathURL), revSelected, GitRev(), m_LogRevision, false, false, true);\r
661                         }\r
662                         break;\r
663                 \r
664                 case ID_OPENWITH:\r
665                         bOpenWith = true;\r
666                 case ID_OPEN:\r
667                         {\r
668                                 CProgressDlg progDlg;\r
669                                 progDlg.SetTitle(IDS_APPNAME);\r
670                                 progDlg.SetAnimation(IDR_DOWNLOAD);\r
671                                 CString sInfoLine;\r
672                                 sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, m_path.GetWinPath(), (LPCTSTR)revSelected.ToString());\r
673                                 progDlg.SetLine(1, sInfoLine, true);\r
674                                 SetAndClearProgressInfo(&progDlg);\r
675                                 progDlg.ShowModeless(m_hWnd);\r
676                                 CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, m_path, revSelected);\r
677                                 bool bSuccess = true;\r
678                                 if (!Cat(m_path, GitRev(GitRev::REV_HEAD), revSelected, tempfile))\r
679                                 {\r
680                                         bSuccess = false;\r
681                                         // try again, but with the selected revision as the peg revision\r
682                                         if (!Cat(m_path, revSelected, revSelected, tempfile))\r
683                                         {\r
684                                                 progDlg.Stop();\r
685                                                 SetAndClearProgressInfo((HWND)NULL);\r
686                                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
687                                                 EnableOKButton();\r
688                                                 break;\r
689                                         }\r
690                                         bSuccess = true;\r
691                                 }\r
692                                 if (bSuccess)\r
693                                 {\r
694                                         progDlg.Stop();\r
695                                         SetAndClearProgressInfo((HWND)NULL);\r
696                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
697                                         int ret = 0;\r
698                                         if (!bOpenWith)\r
699                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
700                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
701                                         {\r
702                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
703                                                 cmd += tempfile.GetWinPathString() + _T(" ");\r
704                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
705                                         }\r
706                                 }\r
707                         }\r
708                         break;\r
709                 case ID_BLAME:\r
710                         {\r
711                                 CBlameDlg dlg;\r
712                                 dlg.EndRev = revSelected;\r
713                                 if (dlg.DoModal() == IDOK)\r
714                                 {\r
715                                         CBlame blame;\r
716                                         CString tempfile;\r
717                                         CString logfile;\r
718                                         tempfile = blame.BlameToTempFile(m_path, dlg.StartRev, dlg.EndRev, dlg.EndRev, logfile, _T(""), dlg.m_bIncludeMerge, TRUE, TRUE);\r
719                                         if (!tempfile.IsEmpty())\r
720                                         {\r
721                                                 if (dlg.m_bTextView)\r
722                                                 {\r
723                                                         //open the default text editor for the result file\r
724                                                         CAppUtils::StartTextViewer(tempfile);\r
725                                                 }\r
726                                                 else\r
727                                                 {\r
728                                                         CString sParams = _T("/path:\"") + m_path.GetGitPathString() + _T("\" ");\r
729                                                         if(!CAppUtils::LaunchTortoiseBlame(tempfile, logfile, CPathUtils::GetFileNameFromPath(m_path.GetFileOrDirectoryName()),sParams))\r
730                                                         {\r
731                                                                 break;\r
732                                                         }\r
733                                                 }\r
734                                         }\r
735                                         else\r
736                                         {\r
737                                                 CMessageBox::Show(this->m_hWnd, blame.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
738                                         }\r
739                                 }\r
740                         }\r
741                         break;\r
742                 case ID_UPDATE:\r
743                         {\r
744                                 CString sCmd;\r
745                                 CString url = _T("tgit:")+pathURL;\r
746                                 sCmd.Format(_T("%s /command:update /path:\"%s\" /rev:%ld"),\r
747                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
748                                         (LPCTSTR)m_path.GetWinPath(), (LONG)revSelected);\r
749                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
750                         }\r
751                         break;\r
752                 case ID_FINDENTRY:\r
753                         {\r
754                                 m_nSearchIndex = GetSelectionMark();\r
755                                 if (m_nSearchIndex < 0)\r
756                                         m_nSearchIndex = 0;\r
757                                 if (m_pFindDialog)\r
758                                 {\r
759                                         break;\r
760                                 }\r
761                                 else\r
762                                 {\r
763                                         m_pFindDialog = new CFindReplaceDialog();\r
764                                         m_pFindDialog->Create(TRUE, NULL, NULL, FR_HIDEUPDOWN | FR_HIDEWHOLEWORD, this);                                                                        \r
765                                 }\r
766                         }\r
767                         break;\r
768                 case ID_REPOBROWSE:\r
769                         {\r
770                                 CString sCmd;\r
771                                 sCmd.Format(_T("%s /command:repobrowser /path:\"%s\" /rev:%s"),\r
772                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
773                                         (LPCTSTR)pathURL, (LPCTSTR)revSelected.ToString());\r
774 \r
775                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
776                         }\r
777                         break;\r
778                 case ID_EDITLOG:\r
779                         {\r
780                                 EditLogMessage(selIndex);\r
781                         }\r
782                         break;\r
783                 case ID_EDITAUTHOR:\r
784                         {\r
785                                 EditAuthor(selEntries);\r
786                         }\r
787                         break;\r
788                 case ID_REVPROPS:\r
789                         {\r
790                                 CEditPropertiesDlg dlg;\r
791                                 dlg.SetProjectProperties(&m_ProjectProperties);\r
792                                 CTGitPathList escapedlist;\r
793                                 dlg.SetPathList(CTGitPathList(CTGitPath(pathURL)));\r
794                                 dlg.SetRevision(revSelected);\r
795                                 dlg.RevProps(true);\r
796                                 dlg.DoModal();\r
797                         }\r
798                         break;\r
799                 \r
800                 case ID_EXPORT:\r
801                         {\r
802                                 CString sCmd;\r
803                                 sCmd.Format(_T("%s /command:export /path:\"%s\" /revision:%ld"),\r
804                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
805                                         (LPCTSTR)pathURL, (LONG)revSelected);\r
806                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
807                         }\r
808                         break;\r
809                 case ID_CHECKOUT:\r
810                         {\r
811                                 CString sCmd;\r
812                                 CString url = _T("tgit:")+pathURL;\r
813                                 sCmd.Format(_T("%s /command:checkout /url:\"%s\" /revision:%ld"),\r
814                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")),\r
815                                         (LPCTSTR)url, (LONG)revSelected);\r
816                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
817                         }\r
818                         break;\r
819                 case ID_VIEWREV:\r
820                         {\r
821                                 CString url = m_ProjectProperties.sWebViewerRev;\r
822                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
823                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
824                                 if (!url.IsEmpty())\r
825                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
826                         }\r
827                         break;\r
828                 case ID_VIEWPATHREV:\r
829                         {\r
830                                 CString relurl = pathURL;\r
831                                 CString sRoot = GetRepositoryRoot(CTGitPath(relurl));\r
832                                 relurl = relurl.Mid(sRoot.GetLength());\r
833                                 CString url = m_ProjectProperties.sWebViewerPathRev;\r
834                                 url = GetAbsoluteUrlFromRelativeUrl(url);\r
835                                 url.Replace(_T("%REVISION%"), revSelected.ToString());\r
836                                 url.Replace(_T("%PATH%"), relurl);\r
837                                 if (!url.IsEmpty())\r
838                                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);                                        \r
839                         }\r
840                         break;\r
841 #endif\r
842                 \r
843                 } // switch (cmd)\r
844 \r
845                 theApp.DoWaitCursor(-1);\r
846 }\r
847 \r
848 void CGitLogList::SetSelectedAction(int action)\r
849 {\r
850         POSITION pos = GetFirstSelectedItemPosition();\r
851         int index;\r
852         while(pos)\r
853         {\r
854                 index = GetNextSelectedItem(pos);\r
855                 ((GitRev*)m_arShownList[index])->m_Action = action;\r
856                 CRect rect;\r
857                 this->GetItemRect(index,&rect,LVIR_BOUNDS);\r
858                 this->InvalidateRect(rect);\r
859 \r
860         }\r
861 \r
862 }