OSDN Git Service

BrowseRefs: Made the dialog usable for picking a ref
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / BrowseRefsDlg.cpp
1 // BrowseRefsDlg.cpp : implementation file\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "TortoiseProc.h"\r
6 #include "BrowseRefsDlg.h"\r
7 #include "LogDlg.h"\r
8 #include "AddRemoteDlg.h"\r
9 #include "AppUtils.h"\r
10 #include "Settings\SettingGitRemote.h"\r
11 #include "SinglePropSheetDlg.h"\r
12 #include "MessageBox.h"\r
13 \r
14 void SetSortArrow(CListCtrl * control, int nColumn, bool bAscending)\r
15 {\r
16         if (control == NULL)\r
17                 return;\r
18         // set the sort arrow\r
19         CHeaderCtrl * pHeader = control->GetHeaderCtrl();\r
20         HDITEM HeaderItem = {0};\r
21         HeaderItem.mask = HDI_FORMAT;\r
22         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
23         {\r
24                 pHeader->GetItem(i, &HeaderItem);\r
25                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
26                 pHeader->SetItem(i, &HeaderItem);\r
27         }\r
28         if (nColumn >= 0)\r
29         {\r
30                 pHeader->GetItem(nColumn, &HeaderItem);\r
31                 HeaderItem.fmt |= (bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
32                 pHeader->SetItem(nColumn, &HeaderItem);\r
33         }\r
34 }\r
35 \r
36 // CBrowseRefsDlg dialog\r
37 \r
38 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
39 \r
40 CBrowseRefsDlg::CBrowseRefsDlg(CString cmdPath, CWnd* pParent /*=NULL*/)\r
41 :       CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent),\r
42         m_cmdPath(cmdPath),\r
43         m_currSortCol(-1),\r
44         m_currSortDesc(false),\r
45         m_initialRef(L"HEAD")\r
46 {\r
47 \r
48 }\r
49 \r
50 CBrowseRefsDlg::~CBrowseRefsDlg()\r
51 {\r
52 }\r
53 \r
54 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)\r
55 {\r
56         CDialog::DoDataExchange(pDX);\r
57         DDX_Control(pDX, IDC_TREE_REF,                  m_RefTreeCtrl);\r
58         DDX_Control(pDX, IDC_LIST_REF_LEAFS,    m_ListRefLeafs);\r
59 }\r
60 \r
61 \r
62 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)\r
63         ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
64         ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
65         ON_WM_CONTEXTMENU()\r
66         ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnLvnColumnclickListRefLeafs)\r
67         ON_WM_DESTROY()\r
68         ON_NOTIFY(NM_DBLCLK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnNMDblclkListRefLeafs)\r
69 END_MESSAGE_MAP()\r
70 \r
71 \r
72 // CBrowseRefsDlg message handlers\r
73 \r
74 void CBrowseRefsDlg::OnBnClickedOk()\r
75 {\r
76         OnOK();\r
77 }\r
78 \r
79 BOOL CBrowseRefsDlg::OnInitDialog()\r
80 {\r
81         CResizableStandAloneDialog::OnInitDialog();\r
82 \r
83         AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
84         AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
85 \r
86         m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);\r
87         m_ListRefLeafs.InsertColumn(eCol_Name,  L"Name",0,150);\r
88         m_ListRefLeafs.InsertColumn(eCol_Date,  L"Date Last Commit",0,100);\r
89         m_ListRefLeafs.InsertColumn(eCol_Msg,   L"Last Commit",0,300);\r
90         m_ListRefLeafs.InsertColumn(eCol_Hash,  L"Hash",0,80);\r
91 \r
92         AddAnchor(IDOK,BOTTOM_RIGHT);\r
93         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
94 \r
95         Refresh(m_initialRef);\r
96 \r
97 \r
98         return TRUE;\r
99 }\r
100 \r
101 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)\r
102 {\r
103         int posSlash=nameLeft.Find('/');\r
104         CString nameSub;\r
105         if(posSlash<0)\r
106         {\r
107                 nameSub=nameLeft;\r
108                 nameLeft.Empty();//Nothing left\r
109         }\r
110         else\r
111         {\r
112                 nameSub=nameLeft.Left(posSlash);\r
113                 nameLeft=nameLeft.Mid(posSlash+1);\r
114         }\r
115         if(nameSub.IsEmpty())\r
116                 return NULL;\r
117 \r
118         if(!bCreateIfNotExist && m_ShadowTree.find(nameSub)==m_ShadowTree.end())\r
119                 return NULL;\r
120 \r
121         CShadowTree& nextNode=m_ShadowTree[nameSub];\r
122         nextNode.m_csRefName=nameSub;\r
123         nextNode.m_pParent=this;\r
124         return &nextNode;\r
125 }\r
126 \r
127 typedef std::map<CString,CString> MAP_STRING_STRING;\r
128 \r
129 CString CBrowseRefsDlg::GetSelectedRef(bool onlyIfLeaf)\r
130 {\r
131         POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
132         //List ctrl selection?\r
133         if(pos)\r
134         {\r
135                 //A leaf is selected\r
136                 CShadowTree* pTree=(CShadowTree*)m_ListRefLeafs.GetItemData(\r
137                                 m_ListRefLeafs.GetNextSelectedItem(pos));\r
138                 return pTree->GetRefName();\r
139         }\r
140         else if(!onlyIfLeaf)\r
141         {\r
142                 //Tree ctrl selection?\r
143                 HTREEITEM hTree=m_RefTreeCtrl.GetSelectedItem();\r
144                 if(hTree!=NULL)\r
145                 {\r
146                         CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTree);\r
147                         return pTree->GetRefName();\r
148                 }\r
149         }\r
150         return CString();//None\r
151 }\r
152 \r
153 void CBrowseRefsDlg::Refresh(CString selectRef)\r
154 {\r
155 //      m_RefMap.clear();\r
156 //      g_Git.GetMapHashToFriendName(m_RefMap);\r
157                 \r
158         if(!selectRef.IsEmpty())\r
159         {\r
160                 if(selectRef == "HEAD")\r
161                 {\r
162                         selectRef.Empty();\r
163                         g_Git.Run(L"git symbolic-ref HEAD",&selectRef,CP_UTF8);\r
164                         selectRef.Trim(L"\r\n\t ");\r
165                 }\r
166         }\r
167         else\r
168         {\r
169                 selectRef = GetSelectedRef(false);\r
170         }\r
171 \r
172         m_RefTreeCtrl.DeleteAllItems();\r
173         m_ListRefLeafs.DeleteAllItems();\r
174         m_TreeRoot.m_ShadowTree.clear();\r
175         m_TreeRoot.m_csRefName="refs";\r
176 //      m_TreeRoot.m_csShowName="Refs";\r
177         m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
178         m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
179 \r
180         CString allRefs;\r
181         g_Git.Run(L"git for-each-ref --format="\r
182                           L"%(refname)%04"\r
183                           L"%(objectname)%04"\r
184                           L"%(authordate:relative)%04"\r
185                           L"%(subject)%04"\r
186                           L"%(authorname)%04"\r
187                           L"%(authordate:iso8601)",\r
188                           &allRefs,CP_UTF8);\r
189 \r
190         int linePos=0;\r
191         CString singleRef;\r
192 \r
193         MAP_STRING_STRING refMap;\r
194 \r
195         //First sort on ref name\r
196         while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())\r
197         {\r
198                 int valuePos=0;\r
199                 CString refName=singleRef.Tokenize(L"\04",valuePos);\r
200                 CString refRest=singleRef.Mid(valuePos);\r
201                 refMap[refName]=refRest;\r
202         }\r
203 \r
204 \r
205 \r
206 //      for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
207 //              for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
208 //                      refName[*iterRefName]=iterRef->first;\r
209 \r
210         //Populate ref tree\r
211         for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
212         {\r
213                 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first,NULL,true);\r
214                 CString values=iterRefMap->second;\r
215 \r
216                 int valuePos=0;\r
217                 treeLeaf.m_csRefHash=           values.Tokenize(L"\04",valuePos);\r
218                 treeLeaf.m_csDate=                      values.Tokenize(L"\04",valuePos);\r
219                 treeLeaf.m_csSubject=           values.Tokenize(L"\04",valuePos);\r
220                 treeLeaf.m_csAuthor=            values.Tokenize(L"\04",valuePos);\r
221                 treeLeaf.m_csDate_Iso8601=      values.Tokenize(L"\04",valuePos);\r
222         }\r
223 \r
224 \r
225         if(selectRef.IsEmpty() || !SelectRef(selectRef))\r
226                 //Probably not on a branch. Select root node.\r
227                 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
228 \r
229 }\r
230 \r
231 bool CBrowseRefsDlg::SelectRef(CString refName)\r
232 {\r
233         if(wcsnicmp(refName,L"refs/",5)!=0)\r
234                 return false; // Not a ref name\r
235 \r
236         CShadowTree& treeLeafHead=GetTreeNode(refName,NULL,false);\r
237         if(treeLeafHead.m_hTree != NULL)\r
238         {\r
239                 //Not a leaf. Select tree node and return\r
240                 m_RefTreeCtrl.Select(treeLeafHead.m_hTree,TVGN_CARET);\r
241                 return true;\r
242         }\r
243 \r
244         if(treeLeafHead.m_pParent==NULL)\r
245                 return false; //Weird... should not occur.\r
246 \r
247         //This is the current head.\r
248         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
249 \r
250         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
251         {\r
252                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
253                 if(pCurrShadowTree == &treeLeafHead)\r
254                 {\r
255                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
256                         m_ListRefLeafs.EnsureVisible(indexPos,FALSE);\r
257                 }\r
258         }\r
259 \r
260         return true;\r
261 }\r
262 \r
263 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos, bool bCreateIfNotExist)\r
264 {\r
265         if(pTreePos==NULL)\r
266         {\r
267                 if(wcsnicmp(refName,L"refs/",5)==0)\r
268                         refName=refName.Mid(5);\r
269                 pTreePos=&m_TreeRoot;\r
270         }\r
271         if(refName.IsEmpty())\r
272                 return *pTreePos;//Found leaf\r
273 \r
274         CShadowTree* pNextTree=pTreePos->GetNextSub(refName,bCreateIfNotExist);\r
275         if(pNextTree==NULL)\r
276         {\r
277                 //Should not occur when all ref-names are valid and bCreateIfNotExist is true.\r
278                 ASSERT(!bCreateIfNotExist);\r
279                 return *pTreePos;\r
280         }\r
281 \r
282         if(!refName.IsEmpty())\r
283         {\r
284                 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.\r
285                 //Leafs are for the list control.\r
286                 if(pNextTree->m_hTree==NULL)\r
287                 {\r
288                         //New tree. Create node in control.\r
289                         pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);\r
290                         m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
291                 }\r
292         }\r
293 \r
294         return GetTreeNode(refName, pNextTree, bCreateIfNotExist);\r
295 }\r
296 \r
297 \r
298 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
299 {\r
300         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
301         *pResult = 0;\r
302 \r
303         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
304 }\r
305 \r
306 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
307 {\r
308         m_ListRefLeafs.DeleteAllItems();\r
309         m_currSortCol = -1;\r
310         m_currSortDesc = false;\r
311         SetSortArrow(&m_ListRefLeafs,-1,false);\r
312 \r
313         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
314         if(pTree==NULL)\r
315         {\r
316                 ASSERT(FALSE);\r
317                 return;\r
318         }\r
319         FillListCtrlForShadowTree(pTree,L"",true);\r
320 }\r
321 \r
322 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
323 {\r
324         if(pTree->IsLeaf())\r
325         {\r
326                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
327 \r
328                 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
329                 m_ListRefLeafs.SetItemText(indexItem,eCol_Name, refNamePrefix+pTree->m_csRefName);\r
330                 m_ListRefLeafs.SetItemText(indexItem,eCol_Date, pTree->m_csDate);\r
331                 m_ListRefLeafs.SetItemText(indexItem,eCol_Msg,  pTree->m_csSubject);\r
332                 m_ListRefLeafs.SetItemText(indexItem,eCol_Hash, pTree->m_csRefHash);\r
333         }\r
334         else\r
335         {\r
336 \r
337                 CString csThisName;\r
338                 if(!isFirstLevel)\r
339                         csThisName=refNamePrefix+pTree->m_csRefName+L"/";\r
340                 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
341                 {\r
342                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
343                 }\r
344         }\r
345 }\r
346 \r
347 bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)\r
348 {\r
349         CString csMessage;\r
350         CString csTitle;\r
351 \r
352         UINT mbIcon=MB_ICONQUESTION;\r
353         csMessage=L"Are you sure you want to delete the ";\r
354         if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
355         {\r
356                 CString branchToDelete = completeRefName.Mid(11);\r
357                 csTitle.Format(L"Confirm deletion of branch %s", branchToDelete);\r
358                 csMessage += "branch:\r\n\r\n<b>";\r
359                 csMessage += branchToDelete;\r
360                 csMessage += "</b>";\r
361 \r
362                 //Check if branch is fully merged in HEAD\r
363                 CString branchHash = g_Git.GetHash(completeRefName);\r
364                 CString commonAncestor;\r
365                 CString cmd;\r
366                 cmd.Format(L"git.exe merge-base HEAD %s",completeRefName);\r
367                 g_Git.Run(cmd,&commonAncestor,CP_UTF8);\r
368 \r
369                 branchHash=branchHash.Left(40);\r
370                 commonAncestor=commonAncestor.Left(40);\r
371                 \r
372                 if(commonAncestor != branchHash)\r
373                 {\r
374                         csMessage += L"\r\n\r\n<b>Warning:\r\nThis branch is not fully merged into HEAD.</b>";\r
375                         mbIcon=MB_ICONWARNING;\r
376                 }\r
377         }\r
378         else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
379         {\r
380                 CString tagToDelete = completeRefName.Mid(10);\r
381                 csTitle.Format(L"Confirm deletion of tag %s", tagToDelete);\r
382                 csMessage += "tag:\r\n\r\n<b>";\r
383                 csMessage += tagToDelete;\r
384                 csMessage += "</b>";\r
385         }\r
386 \r
387         return CMessageBox::Show(m_hWnd,csMessage,csTitle,MB_YESNO|mbIcon)==IDYES;\r
388 \r
389 }\r
390 \r
391 \r
392 bool CBrowseRefsDlg::DoDeleteRef(CString completeRefName, bool bForce)\r
393 {\r
394         if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
395         {\r
396                 CString branchToDelete = completeRefName.Mid(11);\r
397                 CString cmd;\r
398                 cmd.Format(L"git.exe branch -%c %s",bForce?L'D':L'd',branchToDelete);\r
399                 CString resultDummy;\r
400                 if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
401                 {\r
402                         CString errorMsg;\r
403                         errorMsg.Format(L"Could not delete branch %s. Message from git:\r\n\r\n%s",branchToDelete,resultDummy);\r
404                         CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting branch",MB_OK|MB_ICONERROR);\r
405                         return false;\r
406                 }\r
407         }\r
408         else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
409         {\r
410                 CString tagToDelete = completeRefName.Mid(10);\r
411                 CString cmd;\r
412                 cmd.Format(L"git.exe tag -d %s",tagToDelete);\r
413                 CString resultDummy;\r
414                 if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
415                 {\r
416                         CString errorMsg;\r
417                         errorMsg.Format(L"Could not delete tag %s. Message from git:\r\n\r\n%s",tagToDelete,resultDummy);\r
418                         CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting tag",MB_OK|MB_ICONERROR);\r
419                         return false;\r
420                 }\r
421         }\r
422         return true;\r
423 }\r
424 \r
425 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)\r
426 {\r
427         if(pWndFrom==&m_RefTreeCtrl)       OnContextMenu_RefTreeCtrl(point);\r
428         else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);\r
429 }\r
430 \r
431 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)\r
432 {\r
433         CPoint clientPoint=point;\r
434         m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
435 \r
436         HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);\r
437         if(hTreeItem!=NULL)\r
438                 m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);\r
439 \r
440         ShowContextMenu(point,hTreeItem,VectorPShadowTree());\r
441 }\r
442 \r
443 \r
444 void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)\r
445 {\r
446         std::vector<CShadowTree*> selectedLeafs;\r
447         selectedLeafs.reserve(m_ListRefLeafs.GetSelectedCount());\r
448         POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
449         while(pos)\r
450         {\r
451                 selectedLeafs.push_back(\r
452                         (CShadowTree*)m_ListRefLeafs.GetItemData(\r
453                                 m_ListRefLeafs.GetNextSelectedItem(pos)));\r
454         }\r
455 \r
456         ShowContextMenu(point,m_RefTreeCtrl.GetSelectedItem(),selectedLeafs);\r
457 }\r
458 \r
459 void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)\r
460 {\r
461         CMenu popupMenu;\r
462         popupMenu.CreatePopupMenu();\r
463 \r
464         if(selectedLeafs.size()==1)\r
465         {\r
466                 popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
467                 if(selectedLeafs[0]->IsFrom(L"refs/heads"))\r
468                         popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");\r
469                 else if(selectedLeafs[0]->IsFrom(L"refs/tags"))\r
470                         popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");\r
471 \r
472 //              CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
473 //              if(pTree==NULL)\r
474 //                      return;\r
475         }\r
476 \r
477         if(hTreePos!=NULL)\r
478         {\r
479                 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreePos);\r
480                 if(pTree->IsFrom(L"refs/remotes"))\r
481                 {\r
482 //                      popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");\r
483                         if(!m_cmdPath.IsEmpty())\r
484                                 popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");\r
485                 }\r
486                 else if(pTree->IsFrom(L"refs/heads"))\r
487                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
488                 else if(pTree->IsFrom(L"refs/tags"))\r
489                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\r
490         }\r
491 \r
492 \r
493         eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
494         switch(cmd)\r
495         {\r
496         case eCmd_ViewLog:\r
497                 {\r
498                         CLogDlg dlg;\r
499                         dlg.SetStartRef(selectedLeafs[0]->m_csRefHash);\r
500                         dlg.DoModal();\r
501                 }\r
502                 break;\r
503         case eCmd_DeleteBranch:\r
504                 {\r
505                         if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
506                                 DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
507                         Refresh();\r
508                 }\r
509                 break;\r
510         case eCmd_DeleteTag:\r
511                 {\r
512                         if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
513                                 DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
514                         Refresh();\r
515                 }\r
516                 break;\r
517         case eCmd_AddRemote:\r
518                 {\r
519                         CAddRemoteDlg(this).DoModal();\r
520                         Refresh();\r
521                 }\r
522                 break;\r
523         case eCmd_ManageRemotes:\r
524                 {\r
525                         CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();\r
526 //                      CSettingGitRemote W_Remotes(m_cmdPath);\r
527 //                      W_Remotes.DoModal();\r
528                         Refresh();\r
529                 }\r
530                 break;\r
531         case eCmd_CreateBranch:\r
532                 {\r
533                         CAppUtils::CreateBranchTag(false);\r
534                         Refresh();\r
535                 }\r
536                 break;\r
537         case eCmd_CreateTag:\r
538                 {\r
539                         CAppUtils::CreateBranchTag(true);\r
540                         Refresh();\r
541                 }\r
542                 break;\r
543         }\r
544 }\r
545 \r
546 BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)\r
547 {\r
548         if (pMsg->message == WM_KEYDOWN)\r
549         {\r
550                 switch (pMsg->wParam)\r
551                 {\r
552 /*              case VK_RETURN:\r
553                         {\r
554                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
555                                 {\r
556                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
557                                         {\r
558                                                 PostMessage(WM_COMMAND, IDOK);\r
559                                         }\r
560                                         return TRUE;\r
561                                 }\r
562                         }\r
563                         break;\r
564 */              case VK_F5:\r
565                         {\r
566                                 Refresh();\r
567                         }\r
568                         break;\r
569                 }\r
570         }\r
571 \r
572 \r
573         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
574 }\r
575 \r
576 class CRefLeafListCompareFunc\r
577 {\r
578 public:\r
579         CRefLeafListCompareFunc(CListCtrl* pList, int col, bool desc):m_col(col),m_desc(desc),m_pList(pList){}\r
580 \r
581         static int CALLBACK StaticCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\r
582         {\r
583                 return ((CRefLeafListCompareFunc*)lParamSort)->Compare(lParam1,lParam2);\r
584         }\r
585 \r
586         int Compare(LPARAM lParam1, LPARAM lParam2)\r
587         {\r
588                 return Compare(\r
589                         (CShadowTree*)m_pList->GetItemData(lParam1), \r
590                         (CShadowTree*)m_pList->GetItemData(lParam2));\r
591         }\r
592 \r
593         int Compare(CShadowTree* pLeft, CShadowTree* pRight)\r
594         {\r
595                 int result=CompareNoDesc(pLeft,pRight);\r
596                 if(m_desc)\r
597                         return -result;\r
598                 return result;\r
599         }\r
600 \r
601         int CompareNoDesc(CShadowTree* pLeft, CShadowTree* pRight)\r
602         {\r
603                 switch(m_col)\r
604                 {\r
605                 case CBrowseRefsDlg::eCol_Name: return pLeft->GetRefName().CompareNoCase(pRight->GetRefName());\r
606                 case CBrowseRefsDlg::eCol_Date: return pLeft->m_csDate_Iso8601.CompareNoCase(pRight->m_csDate_Iso8601);\r
607                 case CBrowseRefsDlg::eCol_Msg:  return pLeft->m_csSubject.CompareNoCase(pRight->m_csSubject);\r
608                 case CBrowseRefsDlg::eCol_Hash: return pLeft->m_csRefHash.CompareNoCase(pRight->m_csRefHash);\r
609                 }\r
610                 return 0;\r
611         }\r
612 \r
613         int m_col;\r
614         bool m_desc;\r
615         CListCtrl* m_pList;\r
616 \r
617 \r
618 };\r
619 \r
620 \r
621 void CBrowseRefsDlg::OnLvnColumnclickListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
622 {\r
623         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
624         *pResult = 0;\r
625 \r
626         if(m_currSortCol == pNMLV->iSubItem)\r
627                 m_currSortDesc = !m_currSortDesc;\r
628         else\r
629         {\r
630                 m_currSortCol  = pNMLV->iSubItem;\r
631                 m_currSortDesc = false;\r
632         }\r
633 \r
634         CRefLeafListCompareFunc compareFunc(&m_ListRefLeafs, m_currSortCol, m_currSortDesc);\r
635         m_ListRefLeafs.SortItemsEx(&CRefLeafListCompareFunc::StaticCompare, (DWORD_PTR)&compareFunc);\r
636 \r
637         SetSortArrow(&m_ListRefLeafs,m_currSortCol,!m_currSortDesc);\r
638 }\r
639 \r
640 void CBrowseRefsDlg::OnDestroy()\r
641 {\r
642         m_pickedRef = GetSelectedRef(true);\r
643 \r
644         CResizableStandAloneDialog::OnDestroy();\r
645 }\r
646 \r
647 void CBrowseRefsDlg::OnNMDblclkListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
648 {\r
649         LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);\r
650         *pResult = 0;\r
651 \r
652         EndDialog(IDOK);\r
653 }\r
654 \r
655 CString CBrowseRefsDlg::PickRef(bool returnAsHash, CString initialRef)\r
656 {\r
657         CBrowseRefsDlg dlg(CString(),NULL);\r
658         \r
659         dlg.m_initialRef = initialRef;\r
660 \r
661         if(dlg.DoModal() != IDOK)\r
662                 return CString();\r
663 \r
664         return dlg.m_pickedRef;\r
665 }\r
666 \r