1 // BrowseRefsDlg.cpp : implementation file
\r
5 #include "TortoiseProc.h"
\r
6 #include "BrowseRefsDlg.h"
\r
8 #include "AddRemoteDlg.h"
\r
9 #include "CreateBranchTagDlg.h"
\r
10 #include "Settings\SettingGitRemote.h"
\r
11 #include "SinglePropSheetDlg.h"
\r
12 #include "ConfirmDelRefDlg.h"
\r
15 // CBrowseRefsDlg dialog
\r
17 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)
\r
19 CBrowseRefsDlg::CBrowseRefsDlg(CString cmdPath, CWnd* pParent /*=NULL*/)
\r
20 : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent),
\r
26 CBrowseRefsDlg::~CBrowseRefsDlg()
\r
30 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)
\r
32 CDialog::DoDataExchange(pDX);
\r
33 DDX_Control(pDX, IDC_TREE_REF, m_RefTreeCtrl);
\r
34 DDX_Control(pDX, IDC_LIST_REF_LEAFS, m_ListRefLeafs);
\r
38 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)
\r
39 ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)
\r
40 ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)
\r
45 // CBrowseRefsDlg message handlers
\r
47 void CBrowseRefsDlg::OnBnClickedOk()
\r
52 BOOL CBrowseRefsDlg::OnInitDialog()
\r
54 CResizableStandAloneDialog::OnInitDialog();
\r
56 AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);
\r
57 AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);
\r
59 m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
\r
60 m_ListRefLeafs.InsertColumn(0,L"Name",0,150);
\r
61 m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);
\r
62 m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);
\r
63 m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);
\r
65 AddAnchor(IDOK,BOTTOM_RIGHT);
\r
66 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
\r
74 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)
\r
76 int posSlash=nameLeft.Find('/');
\r
81 nameLeft.Empty();//Nothing left
\r
85 nameSub=nameLeft.Left(posSlash);
\r
86 nameLeft=nameLeft.Mid(posSlash+1);
\r
88 if(nameSub.IsEmpty())
\r
91 CShadowTree& nextNode=m_ShadowTree[nameSub];
\r
92 nextNode.m_csRefName=nameSub;
\r
93 nextNode.m_pParent=this;
\r
97 typedef std::map<CString,CString> MAP_STRING_STRING;
\r
99 void CBrowseRefsDlg::Refresh()
\r
101 // m_RefMap.clear();
\r
102 // g_Git.GetMapHashToFriendName(m_RefMap);
\r
105 m_RefTreeCtrl.DeleteAllItems();
\r
106 m_TreeRoot.m_ShadowTree.clear();
\r
107 m_TreeRoot.m_csRefName="refs";
\r
108 // m_TreeRoot.m_csShowName="Refs";
\r
109 m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);
\r
110 m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);
\r
113 g_Git.Run(L"git for-each-ref --format="
\r
115 L"%(objectname)%04"
\r
116 L"%(authordate:relative)%04"
\r
124 MAP_STRING_STRING refMap;
\r
126 //First sort on ref name
\r
127 while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())
\r
130 CString refName=singleRef.Tokenize(L"\04",valuePos);
\r
131 CString refRest=singleRef.Mid(valuePos);
\r
132 refMap[refName]=refRest;
\r
137 // for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)
\r
138 // for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)
\r
139 // refName[*iterRefName]=iterRef->first;
\r
141 //Populate ref tree
\r
142 for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)
\r
144 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);
\r
145 CString values=iterRefMap->second;
\r
148 treeLeaf.m_csRefHash= values.Tokenize(L"\04",valuePos);
\r
149 treeLeaf.m_csDate= values.Tokenize(L"\04",valuePos);
\r
150 treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);
\r
151 treeLeaf.m_csAuthor= values.Tokenize(L"\04",valuePos);
\r
155 g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);
\r
157 currHead.Trim(L"\r\n\t ");
\r
159 if(!SelectRef(currHead))
\r
160 //Probably not on a branch. Select root node.
\r
161 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);
\r
165 bool CBrowseRefsDlg::SelectRef(CString refName)
\r
167 if(wcsnicmp(refName,L"refs/",5)!=0)
\r
168 return false; // Not a ref name
\r
170 CShadowTree& treeLeafHead=GetTreeNode(refName);
\r
171 if(treeLeafHead.m_pParent==NULL)
\r
172 return false; //Weird... should not occur.
\r
174 //This is the current head.
\r
175 m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);
\r
177 for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)
\r
179 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);
\r
180 if(pCurrShadowTree == &treeLeafHead)
\r
182 m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);
\r
189 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)
\r
193 if(wcsnicmp(refName,L"refs/",5)==0)
\r
194 refName=refName.Mid(5);
\r
195 pTreePos=&m_TreeRoot;
\r
197 if(refName.IsEmpty())
\r
198 return *pTreePos;//Found leaf
\r
200 CShadowTree* pNextTree=pTreePos->GetNextSub(refName);
\r
201 if(pNextTree==NULL)
\r
203 //Should not occur when all ref-names are valid.
\r
208 if(!refName.IsEmpty())
\r
210 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.
\r
211 //Leafs are for the list control.
\r
212 if(pNextTree->m_hTree==NULL)
\r
214 //New tree. Create node in control.
\r
215 pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);
\r
216 m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);
\r
220 return GetTreeNode(refName,pNextTree);
\r
224 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)
\r
226 LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
\r
229 FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);
\r
232 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)
\r
234 m_ListRefLeafs.DeleteAllItems();
\r
236 CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));
\r
242 FillListCtrlForShadowTree(pTree,L"",true);
\r
245 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)
\r
247 if(pTree->IsLeaf())
\r
249 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");
\r
251 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);
\r
252 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csRefName);
\r
253 m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);
\r
254 m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);
\r
255 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRefHash);
\r
260 CString csThisName;
\r
262 csThisName=refNamePrefix+pTree->m_csRefName+L"/";
\r
263 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)
\r
265 FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);
\r
270 void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)
\r
273 CPoint clientPoint=point;
\r
274 m_RefTreeCtrl.ScreenToClient(&clientPoint);
\r
277 std::vector<CShadowTree*> selectedTrees;
\r
278 selectedTrees.reserve(m_ListRefLeafs.GetSelectedCount());
\r
279 POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();
\r
282 selectedTrees.push_back(
\r
283 (CShadowTree*)m_ListRefLeafs.GetItemData(
\r
284 m_ListRefLeafs.GetNextSelectedItem(pos)));
\r
288 popupMenu.CreatePopupMenu();
\r
290 if(selectedTrees.size()==1)
\r
292 popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");
\r
293 if(selectedTrees[0]->IsFrom(L"refs/heads"))
\r
294 popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");
\r
295 else if(selectedTrees[0]->IsFrom(L"refs/tags"))
\r
296 popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");
\r
298 // CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);
\r
304 eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
\r
310 dlg.SetStartRef(selectedTrees[0]->m_csRefHash);
\r
314 case eCmd_DeleteBranch:
\r
316 CConfirmDelRefDlg(selectedTrees[0]->GetRefName(),this).DoModal();
\r
320 case eCmd_DeleteTag:
\r
322 CConfirmDelRefDlg(selectedTrees[0]->GetRefName(),this).DoModal();
\r
329 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)
\r
331 if(pWndFrom==&m_RefTreeCtrl) OnContextMenu_RefTreeCtrl(point);
\r
332 else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);
\r
335 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)
\r
338 popupMenu.CreatePopupMenu();
\r
340 CPoint clientPoint=point;
\r
341 m_RefTreeCtrl.ScreenToClient(&clientPoint);
\r
343 HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);
\r
344 if(hTreeItem!=NULL)
\r
346 m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);
\r
347 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreeItem);
\r
348 if(pTree->IsFrom(L"refs/remotes"))
\r
350 // popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");
\r
351 popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");
\r
353 else if(pTree->IsFrom(L"refs/heads"))
\r
354 popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");
\r
355 else if(pTree->IsFrom(L"refs/tags"))
\r
356 popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");
\r
359 eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
\r
362 case eCmd_AddRemote:
\r
364 CAddRemoteDlg(this).DoModal();
\r
368 case eCmd_ManageRemotes:
\r
370 CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();
\r
371 // CSettingGitRemote W_Remotes(m_cmdPath);
\r
372 // W_Remotes.DoModal();
\r
376 case eCmd_CreateBranch:
\r
378 CCreateBranchTagDlg dlg(this);
\r
379 dlg.m_bIsTag=false;
\r
384 case eCmd_CreateTag:
\r
386 CCreateBranchTagDlg dlg(this);
\r
395 BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)
\r
397 if (pMsg->message == WM_KEYDOWN)
\r
399 switch (pMsg->wParam)
\r
403 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
\r
405 if ( GetDlgItem(IDOK)->IsWindowEnabled() )
\r
407 PostMessage(WM_COMMAND, IDOK);
\r
422 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
\r