1 // BrowseRefsDlg.cpp : implementation file
\r
5 #include "TortoiseProc.h"
\r
6 #include "BrowseRefsDlg.h"
\r
9 // CBrowseRefsDlg dialog
\r
11 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)
\r
13 CBrowseRefsDlg::CBrowseRefsDlg(CWnd* pParent /*=NULL*/)
\r
14 : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent)
\r
19 CBrowseRefsDlg::~CBrowseRefsDlg()
\r
23 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)
\r
25 CDialog::DoDataExchange(pDX);
\r
26 DDX_Control(pDX, IDC_TREE_REF, m_RefTreeCtrl);
\r
27 DDX_Control(pDX, IDC_LIST_REF_LEAFS, m_ListRefLeafs);
\r
31 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)
\r
32 ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)
\r
33 ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)
\r
37 // CBrowseRefsDlg message handlers
\r
39 void CBrowseRefsDlg::OnBnClickedOk()
\r
44 BOOL CBrowseRefsDlg::OnInitDialog()
\r
46 CResizableStandAloneDialog::OnInitDialog();
\r
48 AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);
\r
49 AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);
\r
51 m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
\r
52 m_ListRefLeafs.InsertColumn(0,L"Name",0,150);
\r
53 m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);
\r
54 m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);
\r
55 m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);
\r
57 AddAnchor(IDOK,BOTTOM_RIGHT);
\r
58 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
\r
66 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)
\r
68 int posSlash=nameLeft.Find('/');
\r
73 nameLeft.Empty();//Nothing left
\r
77 nameSub=nameLeft.Left(posSlash);
\r
78 nameLeft=nameLeft.Mid(posSlash+1);
\r
80 if(nameSub.IsEmpty())
\r
83 CShadowTree& nextNode=m_ShadowTree[nameSub];
\r
84 nextNode.m_csName=nameSub;
\r
85 nextNode.m_pParent=this;
\r
89 typedef std::map<CString,CString> MAP_STRING_STRING;
\r
91 void CBrowseRefsDlg::Refresh()
\r
94 g_Git.GetMapHashToFriendName(m_RefMap);
\r
96 m_RefTreeCtrl.DeleteAllItems();
\r
97 m_TreeRoot.m_ShadowTree.clear();
\r
98 m_TreeRoot.m_csName="Refs";
\r
99 m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);
\r
100 m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);
\r
103 MAP_STRING_STRING refName;
\r
105 //First sort on ref name
\r
106 for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)
\r
107 for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)
\r
108 refName[*iterRefName]=iterRef->first;
\r
110 //Populate ref tree
\r
111 for(MAP_STRING_STRING::iterator iterRefName=refName.begin();iterRefName!=refName.end();++iterRefName)
\r
113 CShadowTree& treeLeaf=GetTreeNode(iterRefName->first);
\r
114 treeLeaf.m_csRef=iterRefName->second;
\r
118 g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);
\r
120 currHead.Trim(L"\r\n\t ");
\r
122 if(!SelectRef(currHead))
\r
123 //Probably not on a branch. Select root node.
\r
124 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);
\r
128 bool CBrowseRefsDlg::SelectRef(CString refName)
\r
130 if(wcsnicmp(refName,L"refs/",5)!=0)
\r
131 return false; // Not a ref name
\r
133 CShadowTree& treeLeafHead=GetTreeNode(refName);
\r
134 if(treeLeafHead.m_pParent==NULL)
\r
135 return false; //Weird... should not occur.
\r
137 //This is the current head.
\r
138 m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);
\r
140 for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)
\r
142 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);
\r
143 if(pCurrShadowTree == &treeLeafHead)
\r
145 m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);
\r
152 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)
\r
156 if(wcsnicmp(refName,L"refs/",5)==0)
\r
157 refName=refName.Mid(5);
\r
158 pTreePos=&m_TreeRoot;
\r
160 if(refName.IsEmpty())
\r
161 return *pTreePos;//Found leaf
\r
163 CShadowTree* pNextTree=pTreePos->GetNextSub(refName);
\r
164 if(pNextTree==NULL)
\r
166 //Should not occur when all ref-names are valid.
\r
171 if(!refName.IsEmpty())
\r
173 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.
\r
174 //Leafs are for the list control.
\r
175 if(pNextTree->m_hTree==NULL)
\r
177 //New tree. Create node in control.
\r
178 pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csName,pTreePos->m_hTree,NULL);
\r
179 m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);
\r
183 return GetTreeNode(refName,pNextTree);
\r
187 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)
\r
189 LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
\r
192 FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);
\r
195 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)
\r
197 m_ListRefLeafs.DeleteAllItems();
\r
199 CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));
\r
205 FillListCtrlForShadowTree(pTree,L"",true);
\r
208 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)
\r
210 if(pTree->IsLeaf())
\r
212 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");
\r
214 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);
\r
215 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csName);
\r
216 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRef);
\r
221 CString csThisName;
\r
223 csThisName=refNamePrefix+pTree->m_csName+L"/";
\r
224 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)
\r
226 FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);
\r