OSDN Git Service

BrowseRefs: Share property sheet for remote management
[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 #include "AddRemoteDlg.h"\r
9 #include "CreateBranchTagDlg.h"\r
10 #include "Settings\SettingGitRemote.h"\r
11 #include "SinglePropSheetDlg.h"\r
12 \r
13 \r
14 // CBrowseRefsDlg dialog\r
15 \r
16 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
17 \r
18 CBrowseRefsDlg::CBrowseRefsDlg(CString cmdPath, CWnd* pParent /*=NULL*/)\r
19 :       CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent),\r
20         m_cmdPath(cmdPath)\r
21 {\r
22 \r
23 }\r
24 \r
25 CBrowseRefsDlg::~CBrowseRefsDlg()\r
26 {\r
27 }\r
28 \r
29 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)\r
30 {\r
31         CDialog::DoDataExchange(pDX);\r
32         DDX_Control(pDX, IDC_TREE_REF,                  m_RefTreeCtrl);\r
33         DDX_Control(pDX, IDC_LIST_REF_LEAFS,    m_ListRefLeafs);\r
34 }\r
35 \r
36 \r
37 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)\r
38         ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
39         ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
40         ON_WM_CONTEXTMENU()\r
41 END_MESSAGE_MAP()\r
42 \r
43 \r
44 // CBrowseRefsDlg message handlers\r
45 \r
46 void CBrowseRefsDlg::OnBnClickedOk()\r
47 {\r
48         OnOK();\r
49 }\r
50 \r
51 BOOL CBrowseRefsDlg::OnInitDialog()\r
52 {\r
53         CResizableStandAloneDialog::OnInitDialog();\r
54 \r
55         AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
56         AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
57 \r
58         m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);\r
59         m_ListRefLeafs.InsertColumn(0,L"Name",0,150);\r
60         m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);\r
61         m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);\r
62         m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);\r
63 \r
64         AddAnchor(IDOK,BOTTOM_RIGHT);\r
65         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
66 \r
67         Refresh();\r
68 \r
69 \r
70         return TRUE;\r
71 }\r
72 \r
73 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)\r
74 {\r
75         int posSlash=nameLeft.Find('/');\r
76         CString nameSub;\r
77         if(posSlash<0)\r
78         {\r
79                 nameSub=nameLeft;\r
80                 nameLeft.Empty();//Nothing left\r
81         }\r
82         else\r
83         {\r
84                 nameSub=nameLeft.Left(posSlash);\r
85                 nameLeft=nameLeft.Mid(posSlash+1);\r
86         }\r
87         if(nameSub.IsEmpty())\r
88                 return NULL;\r
89 \r
90         CShadowTree& nextNode=m_ShadowTree[nameSub];\r
91         nextNode.m_csRefName=nameSub;\r
92         nextNode.m_pParent=this;\r
93         return &nextNode;\r
94 }\r
95 \r
96 typedef std::map<CString,CString> MAP_STRING_STRING;\r
97 \r
98 void CBrowseRefsDlg::Refresh()\r
99 {\r
100 //      m_RefMap.clear();\r
101 //      g_Git.GetMapHashToFriendName(m_RefMap);\r
102                 \r
103 \r
104         m_RefTreeCtrl.DeleteAllItems();\r
105         m_TreeRoot.m_ShadowTree.clear();\r
106         m_TreeRoot.m_csRefName="refs";\r
107 //      m_TreeRoot.m_csShowName="Refs";\r
108         m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
109         m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
110 \r
111         CString allRefs;\r
112         g_Git.Run(L"git for-each-ref --format="\r
113                           L"%(refname)%04"\r
114                           L"%(objectname)%04"\r
115                           L"%(authordate:relative)%04"\r
116                           L"%(subject)%04"\r
117                           L"%(authorname)",\r
118                           &allRefs,CP_UTF8);\r
119 \r
120         int linePos=0;\r
121         CString singleRef;\r
122 \r
123         MAP_STRING_STRING refMap;\r
124 \r
125         //First sort on ref name\r
126         while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())\r
127         {\r
128                 int valuePos=0;\r
129                 CString refName=singleRef.Tokenize(L"\04",valuePos);\r
130                 CString refRest=singleRef.Mid(valuePos);\r
131                 refMap[refName]=refRest;\r
132         }\r
133 \r
134 \r
135 \r
136 //      for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
137 //              for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
138 //                      refName[*iterRefName]=iterRef->first;\r
139 \r
140         //Populate ref tree\r
141         for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
142         {\r
143                 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);\r
144                 CString values=iterRefMap->second;\r
145 \r
146                 int valuePos=0;\r
147                 treeLeaf.m_csRefHash= values.Tokenize(L"\04",valuePos);\r
148                 treeLeaf.m_csDate=    values.Tokenize(L"\04",valuePos);\r
149                 treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);\r
150                 treeLeaf.m_csAuthor=  values.Tokenize(L"\04",valuePos);\r
151         }\r
152 \r
153         CString currHead;\r
154         g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);\r
155 \r
156         currHead.Trim(L"\r\n\t ");\r
157 \r
158         if(!SelectRef(currHead))\r
159                 //Probably not on a branch. Select root node.\r
160                 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
161 \r
162 }\r
163 \r
164 bool CBrowseRefsDlg::SelectRef(CString refName)\r
165 {\r
166         if(wcsnicmp(refName,L"refs/",5)!=0)\r
167                 return false; // Not a ref name\r
168 \r
169         CShadowTree& treeLeafHead=GetTreeNode(refName);\r
170         if(treeLeafHead.m_pParent==NULL)\r
171                 return false; //Weird... should not occur.\r
172 \r
173         //This is the current head.\r
174         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
175 \r
176         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
177         {\r
178                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
179                 if(pCurrShadowTree == &treeLeafHead)\r
180                 {\r
181                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
182                 }\r
183         }\r
184 \r
185         return true;\r
186 }\r
187 \r
188 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)\r
189 {\r
190         if(pTreePos==NULL)\r
191         {\r
192                 if(wcsnicmp(refName,L"refs/",5)==0)\r
193                         refName=refName.Mid(5);\r
194                 pTreePos=&m_TreeRoot;\r
195         }\r
196         if(refName.IsEmpty())\r
197                 return *pTreePos;//Found leaf\r
198 \r
199         CShadowTree* pNextTree=pTreePos->GetNextSub(refName);\r
200         if(pNextTree==NULL)\r
201         {\r
202                 //Should not occur when all ref-names are valid.\r
203                 ASSERT(FALSE);\r
204                 return *pTreePos;\r
205         }\r
206 \r
207         if(!refName.IsEmpty())\r
208         {\r
209                 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.\r
210                 //Leafs are for the list control.\r
211                 if(pNextTree->m_hTree==NULL)\r
212                 {\r
213                         //New tree. Create node in control.\r
214                         pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);\r
215                         m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
216                 }\r
217         }\r
218 \r
219         return GetTreeNode(refName,pNextTree);\r
220 }\r
221 \r
222 \r
223 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
224 {\r
225         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
226         *pResult = 0;\r
227 \r
228         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
229 }\r
230 \r
231 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
232 {\r
233         m_ListRefLeafs.DeleteAllItems();\r
234 \r
235         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
236         if(pTree==NULL)\r
237         {\r
238                 ASSERT(FALSE);\r
239                 return;\r
240         }\r
241         FillListCtrlForShadowTree(pTree,L"",true);\r
242 }\r
243 \r
244 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
245 {\r
246         if(pTree->IsLeaf())\r
247         {\r
248                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
249 \r
250                 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
251                 m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csRefName);\r
252                 m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);\r
253                 m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);\r
254                 m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRefHash);\r
255         }\r
256         else\r
257         {\r
258 \r
259                 CString csThisName;\r
260                 if(!isFirstLevel)\r
261                         csThisName=refNamePrefix+pTree->m_csRefName+L"/";\r
262                 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
263                 {\r
264                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
265                 }\r
266         }\r
267 }\r
268 \r
269 void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)\r
270 {\r
271 \r
272         CPoint clientPoint=point;\r
273         m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
274 \r
275         int selectedItemCount=m_ListRefLeafs.GetSelectedCount();\r
276 \r
277 \r
278         std::vector<CShadowTree*> selectedTrees;\r
279         selectedTrees.reserve(selectedItemCount);\r
280         POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
281         while(pos)\r
282         {\r
283                 selectedTrees.push_back(\r
284                         (CShadowTree*)m_ListRefLeafs.GetItemData(\r
285                                 m_ListRefLeafs.GetNextSelectedItem(pos)));\r
286         }\r
287 \r
288         CMenu popupMenu;\r
289         popupMenu.CreatePopupMenu();\r
290 \r
291         if(selectedItemCount==1)\r
292         {\r
293                 popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
294 \r
295 //              CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
296 //              if(pTree==NULL)\r
297 //                      return;\r
298         }\r
299 \r
300 \r
301         eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
302         switch(cmd)\r
303         {\r
304         case eCmd_ViewLog:\r
305                 {\r
306                         CLogDlg dlg;\r
307                         dlg.SetStartRef(selectedTrees[0]->m_csRefHash);\r
308                         dlg.DoModal();\r
309                 }\r
310                 break;\r
311         }\r
312 }\r
313 \r
314 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)\r
315 {\r
316         if(pWndFrom==&m_RefTreeCtrl)       OnContextMenu_RefTreeCtrl(point);\r
317         else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);\r
318 }\r
319 \r
320 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)\r
321 {\r
322         CMenu popupMenu;\r
323         popupMenu.CreatePopupMenu();\r
324 \r
325         CPoint clientPoint=point;\r
326         m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
327 \r
328         HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);\r
329         if(hTreeItem!=NULL)\r
330         {\r
331                 m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);\r
332                 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreeItem);\r
333                 if(pTree->IsFrom(L"refs/remotes"))\r
334                 {\r
335 //                      popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");\r
336                         popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");\r
337                 }\r
338                 else if(pTree->IsFrom(L"refs/heads"))\r
339                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
340                 else if(pTree->IsFrom(L"refs/tags"))\r
341                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\r
342         }\r
343 \r
344         eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
345         switch(cmd)\r
346         {\r
347         case eCmd_AddRemote:\r
348                 {\r
349                         CAddRemoteDlg(this).DoModal();\r
350                         Refresh();\r
351                 }\r
352                 break;\r
353         case eCmd_ManageRemotes:\r
354                 {\r
355                         CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();\r
356 //                      CSettingGitRemote W_Remotes(m_cmdPath);\r
357 //                      W_Remotes.DoModal();\r
358                 }\r
359                 break;\r
360         case eCmd_CreateBranch:\r
361                 {\r
362                         CCreateBranchTagDlg dlg(this);\r
363                         dlg.m_bIsTag=false;\r
364                         dlg.DoModal();\r
365                         Refresh();\r
366                 }\r
367                 break;\r
368         case eCmd_CreateTag:\r
369                 {\r
370                         CCreateBranchTagDlg dlg(this);\r
371                         dlg.m_bIsTag=true;\r
372                         dlg.DoModal();\r
373                         Refresh();\r
374                 }\r
375                 break;\r
376         }\r
377 }\r
378 \r
379 BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)\r
380 {\r
381         if (pMsg->message == WM_KEYDOWN)\r
382         {\r
383                 switch (pMsg->wParam)\r
384                 {\r
385 /*              case VK_RETURN:\r
386                         {\r
387                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
388                                 {\r
389                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
390                                         {\r
391                                                 PostMessage(WM_COMMAND, IDOK);\r
392                                         }\r
393                                         return TRUE;\r
394                                 }\r
395                         }\r
396                         break;\r
397 */              case VK_F5:\r
398                         {\r
399                                 Refresh();\r
400                         }\r
401                         break;\r
402                 }\r
403         }\r
404 \r
405 \r
406         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
407 }\r