OSDN Git Service

BrowseRefs: Sorting: Also backward sorting
[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 "AppUtils.h"\r
10 #include "Settings\SettingGitRemote.h"\r
11 #include "SinglePropSheetDlg.h"\r
12 #include "MessageBox.h"\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         m_currSortCol(-1),\r
22         m_currSortDesc(false)\r
23 {\r
24 \r
25 }\r
26 \r
27 CBrowseRefsDlg::~CBrowseRefsDlg()\r
28 {\r
29 }\r
30 \r
31 void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)\r
32 {\r
33         CDialog::DoDataExchange(pDX);\r
34         DDX_Control(pDX, IDC_TREE_REF,                  m_RefTreeCtrl);\r
35         DDX_Control(pDX, IDC_LIST_REF_LEAFS,    m_ListRefLeafs);\r
36 }\r
37 \r
38 \r
39 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)\r
40         ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
41         ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
42         ON_WM_CONTEXTMENU()\r
43         ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnLvnColumnclickListRefLeafs)\r
44 END_MESSAGE_MAP()\r
45 \r
46 \r
47 // CBrowseRefsDlg message handlers\r
48 \r
49 void CBrowseRefsDlg::OnBnClickedOk()\r
50 {\r
51         OnOK();\r
52 }\r
53 \r
54 BOOL CBrowseRefsDlg::OnInitDialog()\r
55 {\r
56         CResizableStandAloneDialog::OnInitDialog();\r
57 \r
58         AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
59         AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
60 \r
61         m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);\r
62         m_ListRefLeafs.InsertColumn(eCol_Name,  L"Name",0,150);\r
63         m_ListRefLeafs.InsertColumn(eCol_Date,  L"Date Last Commit",0,100);\r
64         m_ListRefLeafs.InsertColumn(eCol_Msg,   L"Last Commit",0,300);\r
65         m_ListRefLeafs.InsertColumn(eCol_Hash,  L"Hash",0,80);\r
66 \r
67         AddAnchor(IDOK,BOTTOM_RIGHT);\r
68         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
69 \r
70         Refresh(true);\r
71 \r
72 \r
73         return TRUE;\r
74 }\r
75 \r
76 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)\r
77 {\r
78         int posSlash=nameLeft.Find('/');\r
79         CString nameSub;\r
80         if(posSlash<0)\r
81         {\r
82                 nameSub=nameLeft;\r
83                 nameLeft.Empty();//Nothing left\r
84         }\r
85         else\r
86         {\r
87                 nameSub=nameLeft.Left(posSlash);\r
88                 nameLeft=nameLeft.Mid(posSlash+1);\r
89         }\r
90         if(nameSub.IsEmpty())\r
91                 return NULL;\r
92 \r
93         if(!bCreateIfNotExist && m_ShadowTree.find(nameSub)==m_ShadowTree.end())\r
94                 return NULL;\r
95 \r
96         CShadowTree& nextNode=m_ShadowTree[nameSub];\r
97         nextNode.m_csRefName=nameSub;\r
98         nextNode.m_pParent=this;\r
99         return &nextNode;\r
100 }\r
101 \r
102 typedef std::map<CString,CString> MAP_STRING_STRING;\r
103 \r
104 void CBrowseRefsDlg::Refresh(bool bSelectCurHead)\r
105 {\r
106 //      m_RefMap.clear();\r
107 //      g_Git.GetMapHashToFriendName(m_RefMap);\r
108                 \r
109         CString selectRef;\r
110         if(bSelectCurHead)\r
111         {\r
112                 g_Git.Run(L"git symbolic-ref HEAD",&selectRef,CP_UTF8);\r
113                 selectRef.Trim(L"\r\n\t ");\r
114         }\r
115         else\r
116         {\r
117                 POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
118                 //List ctrl selection?\r
119                 if(pos)\r
120                 {\r
121                         CShadowTree* pTree=(CShadowTree*)m_ListRefLeafs.GetItemData(\r
122                                         m_ListRefLeafs.GetNextSelectedItem(pos));\r
123                         selectRef=pTree->GetRefName();\r
124                 }\r
125                 else\r
126                 {\r
127                         //Tree ctrl selection?\r
128                         HTREEITEM hTree=m_RefTreeCtrl.GetSelectedItem();\r
129                         if(hTree!=NULL)\r
130                         {\r
131                                 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTree);\r
132                                 selectRef=pTree->GetRefName();\r
133                         }\r
134                 }\r
135         }\r
136 \r
137         m_RefTreeCtrl.DeleteAllItems();\r
138         m_ListRefLeafs.DeleteAllItems();\r
139         m_TreeRoot.m_ShadowTree.clear();\r
140         m_TreeRoot.m_csRefName="refs";\r
141 //      m_TreeRoot.m_csShowName="Refs";\r
142         m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
143         m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
144 \r
145         CString allRefs;\r
146         g_Git.Run(L"git for-each-ref --format="\r
147                           L"%(refname)%04"\r
148                           L"%(objectname)%04"\r
149                           L"%(authordate:relative)%04"\r
150                           L"%(subject)%04"\r
151                           L"%(authorname)%04"\r
152                           L"%(authordate:iso8601)",\r
153                           &allRefs,CP_UTF8);\r
154 \r
155         int linePos=0;\r
156         CString singleRef;\r
157 \r
158         MAP_STRING_STRING refMap;\r
159 \r
160         //First sort on ref name\r
161         while(!(singleRef=allRefs.Tokenize(L"\r\n",linePos)).IsEmpty())\r
162         {\r
163                 int valuePos=0;\r
164                 CString refName=singleRef.Tokenize(L"\04",valuePos);\r
165                 CString refRest=singleRef.Mid(valuePos);\r
166                 refMap[refName]=refRest;\r
167         }\r
168 \r
169 \r
170 \r
171 //      for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
172 //              for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
173 //                      refName[*iterRefName]=iterRef->first;\r
174 \r
175         //Populate ref tree\r
176         for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
177         {\r
178                 CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first,NULL,true);\r
179                 CString values=iterRefMap->second;\r
180 \r
181                 int valuePos=0;\r
182                 treeLeaf.m_csRefHash=           values.Tokenize(L"\04",valuePos);\r
183                 treeLeaf.m_csDate=                      values.Tokenize(L"\04",valuePos);\r
184                 treeLeaf.m_csSubject=           values.Tokenize(L"\04",valuePos);\r
185                 treeLeaf.m_csAuthor=            values.Tokenize(L"\04",valuePos);\r
186                 treeLeaf.m_csDate_Iso8601=      values.Tokenize(L"\04",valuePos);\r
187         }\r
188 \r
189 \r
190         if(selectRef.IsEmpty() || !SelectRef(selectRef))\r
191                 //Probably not on a branch. Select root node.\r
192                 m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
193 \r
194 }\r
195 \r
196 bool CBrowseRefsDlg::SelectRef(CString refName)\r
197 {\r
198         if(wcsnicmp(refName,L"refs/",5)!=0)\r
199                 return false; // Not a ref name\r
200 \r
201         CShadowTree& treeLeafHead=GetTreeNode(refName,NULL,false);\r
202         if(treeLeafHead.m_hTree != NULL)\r
203         {\r
204                 //Not a leaf. Select tree node and return\r
205                 m_RefTreeCtrl.Select(treeLeafHead.m_hTree,TVGN_CARET);\r
206                 return true;\r
207         }\r
208 \r
209         if(treeLeafHead.m_pParent==NULL)\r
210                 return false; //Weird... should not occur.\r
211 \r
212         //This is the current head.\r
213         m_RefTreeCtrl.Select(treeLeafHead.m_pParent->m_hTree,TVGN_CARET);\r
214 \r
215         for(int indexPos = 0; indexPos < m_ListRefLeafs.GetItemCount(); ++indexPos)\r
216         {\r
217                 CShadowTree* pCurrShadowTree = (CShadowTree*)m_ListRefLeafs.GetItemData(indexPos);\r
218                 if(pCurrShadowTree == &treeLeafHead)\r
219                 {\r
220                         m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
221                         m_ListRefLeafs.EnsureVisible(indexPos,FALSE);\r
222                 }\r
223         }\r
224 \r
225         return true;\r
226 }\r
227 \r
228 CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos, bool bCreateIfNotExist)\r
229 {\r
230         if(pTreePos==NULL)\r
231         {\r
232                 if(wcsnicmp(refName,L"refs/",5)==0)\r
233                         refName=refName.Mid(5);\r
234                 pTreePos=&m_TreeRoot;\r
235         }\r
236         if(refName.IsEmpty())\r
237                 return *pTreePos;//Found leaf\r
238 \r
239         CShadowTree* pNextTree=pTreePos->GetNextSub(refName,bCreateIfNotExist);\r
240         if(pNextTree==NULL)\r
241         {\r
242                 //Should not occur when all ref-names are valid and bCreateIfNotExist is true.\r
243                 ASSERT(!bCreateIfNotExist);\r
244                 return *pTreePos;\r
245         }\r
246 \r
247         if(!refName.IsEmpty())\r
248         {\r
249                 //When the refName is not empty, this node is not a leaf, so lets add it to the tree control.\r
250                 //Leafs are for the list control.\r
251                 if(pNextTree->m_hTree==NULL)\r
252                 {\r
253                         //New tree. Create node in control.\r
254                         pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);\r
255                         m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
256                 }\r
257         }\r
258 \r
259         return GetTreeNode(refName, pNextTree, bCreateIfNotExist);\r
260 }\r
261 \r
262 \r
263 void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)\r
264 {\r
265         LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);\r
266         *pResult = 0;\r
267 \r
268         FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);\r
269 }\r
270 \r
271 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
272 {\r
273         m_ListRefLeafs.DeleteAllItems();\r
274 \r
275         CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
276         if(pTree==NULL)\r
277         {\r
278                 ASSERT(FALSE);\r
279                 return;\r
280         }\r
281         FillListCtrlForShadowTree(pTree,L"",true);\r
282 }\r
283 \r
284 void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNamePrefix, bool isFirstLevel)\r
285 {\r
286         if(pTree->IsLeaf())\r
287         {\r
288                 int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
289 \r
290                 m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
291                 m_ListRefLeafs.SetItemText(indexItem,eCol_Name, refNamePrefix+pTree->m_csRefName);\r
292                 m_ListRefLeafs.SetItemText(indexItem,eCol_Date, pTree->m_csDate);\r
293                 m_ListRefLeafs.SetItemText(indexItem,eCol_Msg,  pTree->m_csSubject);\r
294                 m_ListRefLeafs.SetItemText(indexItem,eCol_Hash, pTree->m_csRefHash);\r
295         }\r
296         else\r
297         {\r
298 \r
299                 CString csThisName;\r
300                 if(!isFirstLevel)\r
301                         csThisName=refNamePrefix+pTree->m_csRefName+L"/";\r
302                 for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
303                 {\r
304                         FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
305                 }\r
306         }\r
307 }\r
308 \r
309 bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)\r
310 {\r
311         CString csMessage;\r
312         CString csTitle;\r
313 \r
314         UINT mbIcon=MB_ICONQUESTION;\r
315         csMessage=L"Are you sure you want to delete the ";\r
316         if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
317         {\r
318                 CString branchToDelete = completeRefName.Mid(11);\r
319                 csTitle.Format(L"Confirm deletion of branch %s", branchToDelete);\r
320                 csMessage += "branch:\r\n\r\n<b>";\r
321                 csMessage += branchToDelete;\r
322                 csMessage += "</b>";\r
323 \r
324                 //Check if branch is fully merged in HEAD\r
325                 CString branchHash = g_Git.GetHash(completeRefName);\r
326                 CString commonAncestor;\r
327                 CString cmd;\r
328                 cmd.Format(L"git.exe merge-base HEAD %s",completeRefName);\r
329                 g_Git.Run(cmd,&commonAncestor,CP_UTF8);\r
330 \r
331                 branchHash=branchHash.Left(40);\r
332                 commonAncestor=commonAncestor.Left(40);\r
333                 \r
334                 if(commonAncestor != branchHash)\r
335                 {\r
336                         csMessage += L"\r\n\r\n<b>Warning:\r\nThis branch is not fully merged into HEAD.</b>";\r
337                         mbIcon=MB_ICONWARNING;\r
338                 }\r
339         }\r
340         else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
341         {\r
342                 CString tagToDelete = completeRefName.Mid(10);\r
343                 csTitle.Format(L"Confirm deletion of tag %s", tagToDelete);\r
344                 csMessage += "tag:\r\n\r\n<b>";\r
345                 csMessage += tagToDelete;\r
346                 csMessage += "</b>";\r
347         }\r
348 \r
349         return CMessageBox::Show(m_hWnd,csMessage,csTitle,MB_YESNO|mbIcon)==IDYES;\r
350 \r
351 }\r
352 \r
353 \r
354 bool CBrowseRefsDlg::DoDeleteRef(CString completeRefName, bool bForce)\r
355 {\r
356         if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
357         {\r
358                 CString branchToDelete = completeRefName.Mid(11);\r
359                 CString cmd;\r
360                 cmd.Format(L"git.exe branch -%c %s",bForce?L'D':L'd',branchToDelete);\r
361                 CString resultDummy;\r
362                 if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
363                 {\r
364                         CString errorMsg;\r
365                         errorMsg.Format(L"Could not delete branch %s. Message from git:\r\n\r\n%s",branchToDelete,resultDummy);\r
366                         CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting branch",MB_OK|MB_ICONERROR);\r
367                         return false;\r
368                 }\r
369         }\r
370         else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
371         {\r
372                 CString tagToDelete = completeRefName.Mid(10);\r
373                 CString cmd;\r
374                 cmd.Format(L"git.exe tag -d %s",tagToDelete);\r
375                 CString resultDummy;\r
376                 if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
377                 {\r
378                         CString errorMsg;\r
379                         errorMsg.Format(L"Could not delete tag %s. Message from git:\r\n\r\n%s",tagToDelete,resultDummy);\r
380                         CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting tag",MB_OK|MB_ICONERROR);\r
381                         return false;\r
382                 }\r
383         }\r
384         return true;\r
385 }\r
386 \r
387 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)\r
388 {\r
389         if(pWndFrom==&m_RefTreeCtrl)       OnContextMenu_RefTreeCtrl(point);\r
390         else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);\r
391 }\r
392 \r
393 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)\r
394 {\r
395         CPoint clientPoint=point;\r
396         m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
397 \r
398         HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);\r
399         if(hTreeItem!=NULL)\r
400                 m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);\r
401 \r
402         ShowContextMenu(point,hTreeItem,VectorPShadowTree());\r
403 }\r
404 \r
405 \r
406 void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)\r
407 {\r
408         std::vector<CShadowTree*> selectedLeafs;\r
409         selectedLeafs.reserve(m_ListRefLeafs.GetSelectedCount());\r
410         POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
411         while(pos)\r
412         {\r
413                 selectedLeafs.push_back(\r
414                         (CShadowTree*)m_ListRefLeafs.GetItemData(\r
415                                 m_ListRefLeafs.GetNextSelectedItem(pos)));\r
416         }\r
417 \r
418         ShowContextMenu(point,m_RefTreeCtrl.GetSelectedItem(),selectedLeafs);\r
419 }\r
420 \r
421 void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)\r
422 {\r
423         CMenu popupMenu;\r
424         popupMenu.CreatePopupMenu();\r
425 \r
426         if(selectedLeafs.size()==1)\r
427         {\r
428                 popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
429                 if(selectedLeafs[0]->IsFrom(L"refs/heads"))\r
430                         popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");\r
431                 else if(selectedLeafs[0]->IsFrom(L"refs/tags"))\r
432                         popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");\r
433 \r
434 //              CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
435 //              if(pTree==NULL)\r
436 //                      return;\r
437         }\r
438 \r
439         if(hTreePos!=NULL)\r
440         {\r
441                 CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreePos);\r
442                 if(pTree->IsFrom(L"refs/remotes"))\r
443                 {\r
444 //                      popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");\r
445                         popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");\r
446                 }\r
447                 else if(pTree->IsFrom(L"refs/heads"))\r
448                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
449                 else if(pTree->IsFrom(L"refs/tags"))\r
450                         popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\r
451         }\r
452 \r
453 \r
454         eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
455         switch(cmd)\r
456         {\r
457         case eCmd_ViewLog:\r
458                 {\r
459                         CLogDlg dlg;\r
460                         dlg.SetStartRef(selectedLeafs[0]->m_csRefHash);\r
461                         dlg.DoModal();\r
462                 }\r
463                 break;\r
464         case eCmd_DeleteBranch:\r
465                 {\r
466                         if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
467                                 DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
468                         Refresh();\r
469                 }\r
470                 break;\r
471         case eCmd_DeleteTag:\r
472                 {\r
473                         if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
474                                 DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
475                         Refresh();\r
476                 }\r
477                 break;\r
478         case eCmd_AddRemote:\r
479                 {\r
480                         CAddRemoteDlg(this).DoModal();\r
481                         Refresh();\r
482                 }\r
483                 break;\r
484         case eCmd_ManageRemotes:\r
485                 {\r
486                         CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();\r
487 //                      CSettingGitRemote W_Remotes(m_cmdPath);\r
488 //                      W_Remotes.DoModal();\r
489                         Refresh();\r
490                 }\r
491                 break;\r
492         case eCmd_CreateBranch:\r
493                 {\r
494                         CAppUtils::CreateBranchTag(false);\r
495                         Refresh();\r
496                 }\r
497                 break;\r
498         case eCmd_CreateTag:\r
499                 {\r
500                         CAppUtils::CreateBranchTag(true);\r
501                         Refresh();\r
502                 }\r
503                 break;\r
504         }\r
505 }\r
506 \r
507 BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)\r
508 {\r
509         if (pMsg->message == WM_KEYDOWN)\r
510         {\r
511                 switch (pMsg->wParam)\r
512                 {\r
513 /*              case VK_RETURN:\r
514                         {\r
515                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
516                                 {\r
517                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
518                                         {\r
519                                                 PostMessage(WM_COMMAND, IDOK);\r
520                                         }\r
521                                         return TRUE;\r
522                                 }\r
523                         }\r
524                         break;\r
525 */              case VK_F5:\r
526                         {\r
527                                 Refresh();\r
528                         }\r
529                         break;\r
530                 }\r
531         }\r
532 \r
533 \r
534         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
535 }\r
536 \r
537 class CRefLeafListCompareFunc\r
538 {\r
539 public:\r
540         CRefLeafListCompareFunc(CListCtrl* pList, int col, bool desc):m_col(col),m_desc(desc),m_pList(pList){}\r
541 \r
542         static int CALLBACK StaticCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\r
543         {\r
544                 return ((CRefLeafListCompareFunc*)lParamSort)->Compare(lParam1,lParam2);\r
545         }\r
546 \r
547         int Compare(LPARAM lParam1, LPARAM lParam2)\r
548         {\r
549                 return Compare(\r
550                         (CShadowTree*)m_pList->GetItemData(lParam1), \r
551                         (CShadowTree*)m_pList->GetItemData(lParam2));\r
552         }\r
553 \r
554         int Compare(CShadowTree* pLeft, CShadowTree* pRight)\r
555         {\r
556                 int result=CompareNoDesc(pLeft,pRight);\r
557                 if(m_desc)\r
558                         return -result;\r
559                 return result;\r
560         }\r
561 \r
562         int CompareNoDesc(CShadowTree* pLeft, CShadowTree* pRight)\r
563         {\r
564                 switch(m_col)\r
565                 {\r
566                 case CBrowseRefsDlg::eCol_Name: return pLeft->GetRefName().CompareNoCase(pRight->GetRefName());\r
567                 case CBrowseRefsDlg::eCol_Date: return pLeft->m_csDate_Iso8601.CompareNoCase(pRight->m_csDate_Iso8601);\r
568                 case CBrowseRefsDlg::eCol_Msg:  return pLeft->m_csSubject.CompareNoCase(pRight->m_csSubject);\r
569                 case CBrowseRefsDlg::eCol_Hash: return pLeft->m_csRefHash.CompareNoCase(pRight->m_csRefHash);\r
570                 }\r
571                 return 0;\r
572         }\r
573 \r
574         int m_col;\r
575         bool m_desc;\r
576         CListCtrl* m_pList;\r
577 \r
578 \r
579 };\r
580 \r
581 void CBrowseRefsDlg::OnLvnColumnclickListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
582 {\r
583         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
584         *pResult = 0;\r
585 \r
586         if(m_currSortCol == pNMLV->iSubItem)\r
587                 m_currSortDesc = !m_currSortDesc;\r
588         else\r
589         {\r
590                 m_currSortCol  = pNMLV->iSubItem;\r
591                 m_currSortDesc = false;\r
592         }\r
593 \r
594         CRefLeafListCompareFunc compareFunc(&m_ListRefLeafs, m_currSortCol, m_currSortDesc);\r
595         m_ListRefLeafs.SortItemsEx(&CRefLeafListCompareFunc::StaticCompare, (DWORD_PTR)&compareFunc);\r
596 }\r