OSDN Git Service

Continued work on BrowserRefsDlg
[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 #include "LogDlg.h"\r
8 \r
9 \r
10 // CBrowseRefsDlg dialog\r
11 \r
12 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
13 \r
14 CBrowseRefsDlg::CBrowseRefsDlg(CWnd* pParent /*=NULL*/)\r
15         : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent)\r
16 {\r
17 \r
18 }\r
19 \r
20 CBrowseRefsDlg::~CBrowseRefsDlg()\r
21 {\r
22 }\r
23 \r
24 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)\r
25 {\r
26         CDialog::DoDataExchange(pDX);\r
27         DDX_Control(pDX, IDC_TREE_REF,                  m_RefTreeCtrl);\r
28         DDX_Control(pDX, IDC_LIST_REF_LEAFS,    m_ListRefLeafs);\r
29 }\r
30 \r
31 \r
32 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)\r
33         ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
34         ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
35         ON_NOTIFY(NM_RCLICK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnNMRClickListRefLeafs)\r
36 END_MESSAGE_MAP()\r
37 \r
38 \r
39 // CBrowseRefsDlg message handlers\r
40 \r
41 void CBrowseRefsDlg::OnBnClickedOk()\r
42 {\r
43         OnOK();\r
44 }\r
45 \r
46 BOOL CBrowseRefsDlg::OnInitDialog()\r
47 {\r
48         CResizableStandAloneDialog::OnInitDialog();\r
49 \r
50         AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
51         AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
52 \r
53         m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);\r
54         m_ListRefLeafs.InsertColumn(0,L"Name",0,150);\r
55         m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);\r
56         m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);\r
57         m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);\r
58 \r
59         AddAnchor(IDOK,BOTTOM_RIGHT);\r
60         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
61 \r
62         Refresh();\r
63 \r
64 \r
65         return TRUE;\r
66 }\r
67 \r
68 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)\r
69 {\r
70         int posSlash=nameLeft.Find('/');\r
71         CString nameSub;\r
72         if(posSlash<0)\r
73         {\r
74                 nameSub=nameLeft;\r
75                 nameLeft.Empty();//Nothing left\r
76         }\r
77         else\r
78         {\r
79                 nameSub=nameLeft.Left(posSlash);\r
80                 nameLeft=nameLeft.Mid(posSlash+1);\r
81         }\r
82         if(nameSub.IsEmpty())\r
83                 return NULL;\r
84 \r
85         CShadowTree& nextNode=m_ShadowTree[nameSub];\r
86         nextNode.m_csName=nameSub;\r
87         nextNode.m_pParent=this;\r
88         return &nextNode;\r
89 }\r
90 \r
91 typedef std::map<CString,CString> MAP_STRING_STRING;\r
92 \r
93 void CBrowseRefsDlg::Refresh()\r
94 {\r
95 //      m_RefMap.clear();\r
96 //      g_Git.GetMapHashToFriendName(m_RefMap);\r
97                 \r
98 \r
99         m_RefTreeCtrl.DeleteAllItems();\r
100         m_TreeRoot.m_ShadowTree.clear();\r
101         m_TreeRoot.m_csName="Refs";\r
102         m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
103         m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
104 \r
105         CString allRefs;\r
106         g_Git.Run(L"git for-each-ref --format="\r
107                           L"%(refname)%04"\r
108                           L"%(objectname)%04"\r
109                           L"%(authordate:relative)%04"\r
110                           L"%(subject)%04"\r
111                           L"%(authorname)",\r
112                           &allRefs,CP_UTF8);\r
113 \r
114         int linePos=0;\r
115         CString singleRef;\r
116 \r
117         MAP_STRING_STRING refMap;\r
118 \r
119         //First sort on ref name\r
120         while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())\r
121         {\r
122                 int valuePos=0;\r
123                 CString refName=singleRef.Tokenize(L"\04",valuePos);\r
124                 CString refRest=singleRef.Mid(valuePos);\r
125                 refMap[refName]=refRest;\r
126         }\r
127 \r
128 \r
129 \r
130 //      for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
131 //              for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
132 //                      refName[*iterRefName]=iterRef->first;\r
133 \r
134         //Populate ref tree\r
135         for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
136         {\r
137                 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);\r
138                 CString values=iterRefMap->second;\r
139 \r
140                 int valuePos=0;\r
141                 treeLeaf.m_csRef=     values.Tokenize(L"\04",valuePos);\r
142                 treeLeaf.m_csDate=    values.Tokenize(L"\04",valuePos);\r
143                 treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);\r
144                 treeLeaf.m_csAuthor=  values.Tokenize(L"\04",valuePos);\r
145         }\r
146 \r
147         CString currHead;\r
148         g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);\r
149 \r
150         currHead.Trim(L"\r\n\t ");\r
151 \r
152         if(!SelectRef(currHead))\r
153                 //Probably not on a branch. Select root node.\r
154                 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
155 \r
156 }\r
157 \r
158 bool CBrowseRefsDlg::SelectRef(CString refName)\r
159 {\r
160         if(wcsnicmp(refName,L"refs/",5)!=0)\r
161                 return false; // Not a ref name\r
162 \r
163         CShadowTree& treeLeafHead=GetTreeNode(refName);\r
164         if(treeLeafHead.m_pParent==NULL)\r
165                 return false; //Weird... should not occur.\r
166 \r
167         //This is the current head.\r
168         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
169 \r
170         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
171         {\r
172                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
173                 if(pCurrShadowTree == &treeLeafHead)\r
174                 {\r
175                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
176                 }\r
177         }\r
178 \r
179         return true;\r
180 }\r
181 \r
182 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)\r
183 {\r
184         if(pTreePos==NULL)\r
185         {\r
186                 if(wcsnicmp(refName,L"refs/",5)==0)\r
187                         refName=refName.Mid(5);\r
188                 pTreePos=&m_TreeRoot;\r
189         }\r
190         if(refName.IsEmpty())\r
191                 return *pTreePos;//Found leaf\r
192 \r
193         CShadowTree* pNextTree=pTreePos->GetNextSub(refName);\r
194         if(pNextTree==NULL)\r
195         {\r
196                 //Should not occur when all ref-names are valid.\r
197                 ASSERT(FALSE);\r
198                 return *pTreePos;\r
199         }\r
200 \r
201         if(!refName.IsEmpty())\r
202         {\r
203                 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.\r
204                 //Leafs are for the list control.\r
205                 if(pNextTree->m_hTree==NULL)\r
206                 {\r
207                         //New tree. Create node in control.\r
208                         pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csName,pTreePos->m_hTree,NULL);\r
209                         m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
210                 }\r
211         }\r
212 \r
213         return GetTreeNode(refName,pNextTree);\r
214 }\r
215 \r
216 \r
217 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
218 {\r
219         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
220         *pResult = 0;\r
221 \r
222         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
223 }\r
224 \r
225 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
226 {\r
227         m_ListRefLeafs.DeleteAllItems();\r
228 \r
229         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
230         if(pTree==NULL)\r
231         {\r
232                 ASSERT(FALSE);\r
233                 return;\r
234         }\r
235         FillListCtrlForShadowTree(pTree,L"",true);\r
236 }\r
237 \r
238 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
239 {\r
240         if(pTree->IsLeaf())\r
241         {\r
242                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
243 \r
244                 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
245                 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csName);\r
246                 m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);\r
247                 m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);\r
248                 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRef);\r
249         }\r
250         else\r
251         {\r
252 \r
253                 CString csThisName;\r
254                 if(!isFirstLevel)\r
255                         csThisName=refNamePrefix+pTree->m_csName+L"/";\r
256                 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
257                 {\r
258                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
259                 }\r
260         }\r
261 }\r
262 \r
263 void CBrowseRefsDlg::OnNMRClickListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
264 {\r
265         LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);\r
266         *pResult = 0;\r
267 \r
268         CMenu popupMenu;\r
269         popupMenu.CreatePopupMenu();\r
270         popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
271 \r
272         CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
273         if(pTree==NULL)\r
274                 return;\r
275 \r
276 \r
277         const MSG* pCurrMsg=GetCurrentMessage();\r
278         eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, pCurrMsg->pt.x, pCurrMsg->pt.y, this, 0);\r
279         switch(cmd)\r
280         {\r
281         case eCmd_ViewLog:\r
282                 {\r
283                         CLogDlg dlg;\r
284                         theApp.m_pMainWnd = &dlg;\r
285                         dlg.SetParams("", "", pTree->m_csRef, "", "");\r
286                         dlg.DoModal();\r
287                 }\r
288                 break;\r
289         }\r
290 }\r