OSDN Git Service

bf9ca63171e2a06885cfbbf689d07dabe3bdcdfd
[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 \r
97         m_RefTreeCtrl.DeleteAllItems();\r
98         m_TreeRoot.m_ShadowTree.clear();\r
99         m_TreeRoot.m_csName="Refs";\r
100         m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
101         m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
102 \r
103         CString allRefs;\r
104         g_Git.Run(L"git for-each-ref --format="\r
105                           L"%(refname)%04"\r
106                           L"%(objectname)%04"\r
107                           L"%(authordate:relative)%04"\r
108                           L"%(subject)%04"\r
109                           L"%(authorname)",\r
110                           &allRefs,CP_UTF8);\r
111 \r
112         int linePos=0;\r
113         CString singleRef;\r
114 \r
115         MAP_STRING_STRING refMap;\r
116 \r
117         //First sort on ref name\r
118         while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())\r
119         {\r
120                 int valuePos=0;\r
121                 CString refName=singleRef.Tokenize(L"\04",valuePos);\r
122                 CString refRest=singleRef.Mid(valuePos);\r
123                 refMap[refName]=refRest;\r
124         }\r
125 \r
126 \r
127 \r
128 //      for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
129 //              for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
130 //                      refName[*iterRefName]=iterRef->first;\r
131 \r
132         //Populate ref tree\r
133         for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
134         {\r
135                 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);\r
136                 CString values=iterRefMap->second;\r
137 \r
138                 int valuePos=0;\r
139                 treeLeaf.m_csRef=     values.Tokenize(L"\04",valuePos);\r
140                 treeLeaf.m_csDate=    values.Tokenize(L"\04",valuePos);\r
141                 treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);\r
142                 treeLeaf.m_csAuthor=  values.Tokenize(L"\04",valuePos);\r
143         }\r
144 \r
145         CString currHead;\r
146         g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);\r
147 \r
148         currHead.Trim(L"\r\n\t ");\r
149 \r
150         if(!SelectRef(currHead))\r
151                 //Probably not on a branch. Select root node.\r
152                 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
153 \r
154 }\r
155 \r
156 bool CBrowseRefsDlg::SelectRef(CString refName)\r
157 {\r
158         if(wcsnicmp(refName,L"refs/",5)!=0)\r
159                 return false; // Not a ref name\r
160 \r
161         CShadowTree& treeLeafHead=GetTreeNode(refName);\r
162         if(treeLeafHead.m_pParent==NULL)\r
163                 return false; //Weird... should not occur.\r
164 \r
165         //This is the current head.\r
166         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
167 \r
168         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
169         {\r
170                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
171                 if(pCurrShadowTree == &treeLeafHead)\r
172                 {\r
173                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
174                 }\r
175         }\r
176 \r
177         return true;\r
178 }\r
179 \r
180 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)\r
181 {\r
182         if(pTreePos==NULL)\r
183         {\r
184                 if(wcsnicmp(refName,L"refs/",5)==0)\r
185                         refName=refName.Mid(5);\r
186                 pTreePos=&m_TreeRoot;\r
187         }\r
188         if(refName.IsEmpty())\r
189                 return *pTreePos;//Found leaf\r
190 \r
191         CShadowTree* pNextTree=pTreePos->GetNextSub(refName);\r
192         if(pNextTree==NULL)\r
193         {\r
194                 //Should not occur when all ref-names are valid.\r
195                 ASSERT(FALSE);\r
196                 return *pTreePos;\r
197         }\r
198 \r
199         if(!refName.IsEmpty())\r
200         {\r
201                 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.\r
202                 //Leafs are for the list control.\r
203                 if(pNextTree->m_hTree==NULL)\r
204                 {\r
205                         //New tree. Create node in control.\r
206                         pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csName,pTreePos->m_hTree,NULL);\r
207                         m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
208                 }\r
209         }\r
210 \r
211         return GetTreeNode(refName,pNextTree);\r
212 }\r
213 \r
214 \r
215 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
216 {\r
217         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
218         *pResult = 0;\r
219 \r
220         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
221 }\r
222 \r
223 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
224 {\r
225         m_ListRefLeafs.DeleteAllItems();\r
226 \r
227         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
228         if(pTree==NULL)\r
229         {\r
230                 ASSERT(FALSE);\r
231                 return;\r
232         }\r
233         FillListCtrlForShadowTree(pTree,L"",true);\r
234 }\r
235 \r
236 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
237 {\r
238         if(pTree->IsLeaf())\r
239         {\r
240                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
241 \r
242                 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
243                 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csName);\r
244                 m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);\r
245                 m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);\r
246                 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRef);\r
247         }\r
248         else\r
249         {\r
250 \r
251                 CString csThisName;\r
252                 if(!isFirstLevel)\r
253                         csThisName=refNamePrefix+pTree->m_csName+L"/";\r
254                 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
255                 {\r
256                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
257                 }\r
258         }\r
259 }\r