OSDN Git Service

BrowseRefDlg: Select current HEAD
[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 \r
8 \r
9 // CBrowseRefsDlg dialog\r
10 \r
11 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
12 \r
13 CBrowseRefsDlg::CBrowseRefsDlg(CWnd* pParent /*=NULL*/)\r
14         : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent)\r
15 {\r
16 \r
17 }\r
18 \r
19 CBrowseRefsDlg::~CBrowseRefsDlg()\r
20 {\r
21 }\r
22 \r
23 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)\r
24 {\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
28 }\r
29 \r
30 \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
34 END_MESSAGE_MAP()\r
35 \r
36 \r
37 // CBrowseRefsDlg message handlers\r
38 \r
39 void CBrowseRefsDlg::OnBnClickedOk()\r
40 {\r
41         OnOK();\r
42 }\r
43 \r
44 BOOL CBrowseRefsDlg::OnInitDialog()\r
45 {\r
46         CResizableStandAloneDialog::OnInitDialog();\r
47 \r
48         AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
49         AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
50 \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
56 \r
57         AddAnchor(IDOK,BOTTOM_RIGHT);\r
58         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
59 \r
60         Refresh();\r
61 \r
62 \r
63         return TRUE;\r
64 }\r
65 \r
66 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)\r
67 {\r
68         int posSlash=nameLeft.Find('/');\r
69         CString nameSub;\r
70         if(posSlash<0)\r
71         {\r
72                 nameSub=nameLeft;\r
73                 nameLeft.Empty();//Nothing left\r
74         }\r
75         else\r
76         {\r
77                 nameSub=nameLeft.Left(posSlash);\r
78                 nameLeft=nameLeft.Mid(posSlash+1);\r
79         }\r
80         if(nameSub.IsEmpty())\r
81                 return NULL;\r
82 \r
83         CShadowTree& nextNode=m_ShadowTree[nameSub];\r
84         nextNode.m_csName=nameSub;\r
85         nextNode.m_pParent=this;\r
86         return &nextNode;\r
87 }\r
88 \r
89 typedef std::map<CString,CString> MAP_STRING_STRING;\r
90 \r
91 void CBrowseRefsDlg::Refresh()\r
92 {\r
93         m_RefMap.clear();\r
94         g_Git.GetMapHashToFriendName(m_RefMap);\r
95 \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
101 \r
102 \r
103         MAP_STRING_STRING refName;\r
104 \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
109 \r
110         //Populate ref tree\r
111         for(MAP_STRING_STRING::iterator iterRefName=refName.begin();iterRefName!=refName.end();++iterRefName)\r
112         {\r
113                 CShadowTree& treeLeaf=GetTreeNode(iterRefName->first);\r
114                 treeLeaf.m_csRef=iterRefName->second;\r
115         }\r
116 \r
117         CString currHead;\r
118         g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);\r
119 \r
120         currHead.Trim(L"\r\n\t ");\r
121 \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
125 \r
126 }\r
127 \r
128 bool CBrowseRefsDlg::SelectRef(CString refName)\r
129 {\r
130         if(wcsnicmp(refName,L"refs/",5)!=0)\r
131                 return false; // Not a ref name\r
132 \r
133         CShadowTree& treeLeafHead=GetTreeNode(refName);\r
134         if(treeLeafHead.m_pParent==NULL)\r
135                 return false; //Weird... should not occur.\r
136 \r
137         //This is the current head.\r
138         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
139 \r
140         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
141         {\r
142                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
143                 if(pCurrShadowTree == &treeLeafHead)\r
144                 {\r
145                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
146                 }\r
147         }\r
148 \r
149         return true;\r
150 }\r
151 \r
152 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)\r
153 {\r
154         if(pTreePos==NULL)\r
155         {\r
156                 if(wcsnicmp(refName,L"refs/",5)==0)\r
157                         refName=refName.Mid(5);\r
158                 pTreePos=&m_TreeRoot;\r
159         }\r
160         if(refName.IsEmpty())\r
161                 return *pTreePos;//Found leaf\r
162 \r
163         CShadowTree* pNextTree=pTreePos->GetNextSub(refName);\r
164         if(pNextTree==NULL)\r
165         {\r
166                 //Should not occur when all ref-names are valid.\r
167                 ASSERT(FALSE);\r
168                 return *pTreePos;\r
169         }\r
170 \r
171         if(!refName.IsEmpty())\r
172         {\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
176                 {\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
180                 }\r
181         }\r
182 \r
183         return GetTreeNode(refName,pNextTree);\r
184 }\r
185 \r
186 \r
187 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
188 {\r
189         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
190         *pResult = 0;\r
191 \r
192         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
193 }\r
194 \r
195 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
196 {\r
197         m_ListRefLeafs.DeleteAllItems();\r
198 \r
199         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
200         if(pTree==NULL)\r
201         {\r
202                 ASSERT(FALSE);\r
203                 return;\r
204         }\r
205         FillListCtrlForShadowTree(pTree,L"",true);\r
206 }\r
207 \r
208 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
209 {\r
210         if(pTree->IsLeaf())\r
211         {\r
212                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
213 \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
217         }\r
218         else\r
219         {\r
220 \r
221                 CString csThisName;\r
222                 if(!isFirstLevel)\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
225                 {\r
226                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
227                 }\r
228         }\r
229 }\r