BrowseRefsDlg: Added F5 shortcut for refresh
[TortoiseGit.git] / src / TortoiseProc / BrowseRefsDlg.cpp
blob487f008bb6732b66fa4d1d9fa01301797acea3cb
1 // BrowseRefsDlg.cpp : implementation file
2 //
4 #include "stdafx.h"
5 #include "TortoiseProc.h"
6 #include "BrowseRefsDlg.h"
7 #include "LogDlg.h"
8 #include "AddRemoteDlg.h"
9 #include "CreateBranchTagDlg.h"
12 // CBrowseRefsDlg dialog
14 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)
16 CBrowseRefsDlg::CBrowseRefsDlg(CWnd* pParent /*=NULL*/)
17 : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent)
22 CBrowseRefsDlg::~CBrowseRefsDlg()
26 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)
28 CDialog::DoDataExchange(pDX);
29 DDX_Control(pDX, IDC_TREE_REF, m_RefTreeCtrl);
30 DDX_Control(pDX, IDC_LIST_REF_LEAFS, m_ListRefLeafs);
34 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)
35 ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)
36 ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)
37 ON_WM_CONTEXTMENU()
38 END_MESSAGE_MAP()
41 // CBrowseRefsDlg message handlers
43 void CBrowseRefsDlg::OnBnClickedOk()
45 OnOK();
48 BOOL CBrowseRefsDlg::OnInitDialog()
50 CResizableStandAloneDialog::OnInitDialog();
52 AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);
53 AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);
55 m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
56 m_ListRefLeafs.InsertColumn(0,L"Name",0,150);
57 m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);
58 m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);
59 m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);
61 AddAnchor(IDOK,BOTTOM_RIGHT);
62 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
64 Refresh();
67 return TRUE;
70 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)
72 int posSlash=nameLeft.Find('/');
73 CString nameSub;
74 if(posSlash<0)
76 nameSub=nameLeft;
77 nameLeft.Empty();//Nothing left
79 else
81 nameSub=nameLeft.Left(posSlash);
82 nameLeft=nameLeft.Mid(posSlash+1);
84 if(nameSub.IsEmpty())
85 return NULL;
87 CShadowTree& nextNode=m_ShadowTree[nameSub];
88 nextNode.m_csRefName=nameSub;
89 nextNode.m_pParent=this;
90 return &nextNode;
93 typedef std::map<CString,CString> MAP_STRING_STRING;
95 void CBrowseRefsDlg::Refresh()
97 // m_RefMap.clear();
98 // g_Git.GetMapHashToFriendName(m_RefMap);
101 m_RefTreeCtrl.DeleteAllItems();
102 m_TreeRoot.m_ShadowTree.clear();
103 m_TreeRoot.m_csRefName="refs";
104 // m_TreeRoot.m_csShowName="Refs";
105 m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);
106 m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);
108 CString allRefs;
109 g_Git.Run(L"git for-each-ref --format="
110 L"%(refname)%04"
111 L"%(objectname)%04"
112 L"%(authordate:relative)%04"
113 L"%(subject)%04"
114 L"%(authorname)",
115 &allRefs,CP_UTF8);
117 int linePos=0;
118 CString singleRef;
120 MAP_STRING_STRING refMap;
122 //First sort on ref name
123 while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())
125 int valuePos=0;
126 CString refName=singleRef.Tokenize(L"\04",valuePos);
127 CString refRest=singleRef.Mid(valuePos);
128 refMap[refName]=refRest;
133 // for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)
134 // for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)
135 // refName[*iterRefName]=iterRef->first;
137 //Populate ref tree
138 for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)
140 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);
141 CString values=iterRefMap->second;
143 int valuePos=0;
144 treeLeaf.m_csRefHash= values.Tokenize(L"\04",valuePos);
145 treeLeaf.m_csDate= values.Tokenize(L"\04",valuePos);
146 treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);
147 treeLeaf.m_csAuthor= values.Tokenize(L"\04",valuePos);
150 CString currHead;
151 g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);
153 currHead.Trim(L"\r\n\t ");
155 if(!SelectRef(currHead))
156 //Probably not on a branch. Select root node.
157 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);
161 bool CBrowseRefsDlg::SelectRef(CString refName)
163 if(wcsnicmp(refName,L"refs/",5)!=0)
164 return false; // Not a ref name
166 CShadowTree& treeLeafHead=GetTreeNode(refName);
167 if(treeLeafHead.m_pParent==NULL)
168 return false; //Weird... should not occur.
170 //This is the current head.
171 m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);
173 for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)
175 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);
176 if(pCurrShadowTree == &treeLeafHead)
178 m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);
182 return true;
185 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)
187 if(pTreePos==NULL)
189 if(wcsnicmp(refName,L"refs/",5)==0)
190 refName=refName.Mid(5);
191 pTreePos=&m_TreeRoot;
193 if(refName.IsEmpty())
194 return *pTreePos;//Found leaf
196 CShadowTree* pNextTree=pTreePos->GetNextSub(refName);
197 if(pNextTree==NULL)
199 //Should not occur when all ref-names are valid.
200 ASSERT(FALSE);
201 return *pTreePos;
204 if(!refName.IsEmpty())
206 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.
207 //Leafs are for the list control.
208 if(pNextTree->m_hTree==NULL)
210 //New tree. Create node in control.
211 pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);
212 m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);
216 return GetTreeNode(refName,pNextTree);
220 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)
222 LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
223 *pResult = 0;
225 FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);
228 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)
230 m_ListRefLeafs.DeleteAllItems();
232 CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));
233 if(pTree==NULL)
235 ASSERT(FALSE);
236 return;
238 FillListCtrlForShadowTree(pTree,L"",true);
241 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)
243 if(pTree->IsLeaf())
245 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");
247 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);
248 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csRefName);
249 m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);
250 m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);
251 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRefHash);
253 else
256 CString csThisName;
257 if(!isFirstLevel)
258 csThisName=refNamePrefix+pTree->m_csRefName+L"/";
259 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)
261 FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);
266 void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)
269 CPoint clientPoint=point;
270 m_RefTreeCtrl.ScreenToClient(&clientPoint);
272 int selectedItemCount=m_ListRefLeafs.GetSelectedCount();
275 std::vector<CShadowTree*> selectedTrees;
276 selectedTrees.reserve(selectedItemCount);
277 POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();
278 while(pos)
280 selectedTrees.push_back(
281 (CShadowTree*)m_ListRefLeafs.GetItemData(
282 m_ListRefLeafs.GetNextSelectedItem(pos)));
285 CMenu popupMenu;
286 popupMenu.CreatePopupMenu();
288 if(selectedItemCount==1)
290 popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");
292 // CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);
293 // if(pTree==NULL)
294 // return;
298 eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
299 switch(cmd)
301 case eCmd_ViewLog:
303 CLogDlg dlg;
304 dlg.SetStartRef(selectedTrees[0]->m_csRefHash);
305 dlg.DoModal();
307 break;
311 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)
313 if(pWndFrom==&m_RefTreeCtrl) OnContextMenu_RefTreeCtrl(point);
314 else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);
317 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)
319 CMenu popupMenu;
320 popupMenu.CreatePopupMenu();
322 CPoint clientPoint=point;
323 m_RefTreeCtrl.ScreenToClient(&clientPoint);
325 HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);
326 if(hTreeItem!=NULL)
328 m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);
329 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreeItem);
330 if(pTree->IsFrom(L"refs/remotes"))
331 popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");
332 else if(pTree->IsFrom(L"refs/heads"))
333 popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");
334 else if(pTree->IsFrom(L"refs/tags"))
335 popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");
338 eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
339 switch(cmd)
341 case eCmd_AddRemote:
343 CAddRemoteDlg(this).DoModal();
344 Refresh();
346 break;
347 case eCmd_CreateBranch:
349 CCreateBranchTagDlg dlg(this);
350 dlg.m_bIsTag=false;
351 dlg.DoModal();
352 Refresh();
354 break;
355 case eCmd_CreateTag:
357 CCreateBranchTagDlg dlg(this);
358 dlg.m_bIsTag=true;
359 dlg.DoModal();
360 Refresh();
362 break;
366 BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)
368 if (pMsg->message == WM_KEYDOWN)
370 switch (pMsg->wParam)
372 /* case VK_RETURN:
374 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
376 if ( GetDlgItem(IDOK)->IsWindowEnabled() )
378 PostMessage(WM_COMMAND, IDOK);
380 return TRUE;
383 break;
384 */ case VK_F5:
386 Refresh();
388 break;
393 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);