OSDN Git Service

BrowseRefs: Made the dialog usable for picking a ref
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / BrowseRefsDlg.cpp
index 6707fea..c6862b0 100644 (file)
 #include "SinglePropSheetDlg.h"\r
 #include "MessageBox.h"\r
 \r
+void SetSortArrow(CListCtrl * control, int nColumn, bool bAscending)\r
+{\r
+       if (control == NULL)\r
+               return;\r
+       // set the sort arrow\r
+       CHeaderCtrl * pHeader = control->GetHeaderCtrl();\r
+       HDITEM HeaderItem = {0};\r
+       HeaderItem.mask = HDI_FORMAT;\r
+       for (int i=0; i<pHeader->GetItemCount(); ++i)\r
+       {\r
+               pHeader->GetItem(i, &HeaderItem);\r
+               HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
+               pHeader->SetItem(i, &HeaderItem);\r
+       }\r
+       if (nColumn >= 0)\r
+       {\r
+               pHeader->GetItem(nColumn, &HeaderItem);\r
+               HeaderItem.fmt |= (bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
+               pHeader->SetItem(nColumn, &HeaderItem);\r
+       }\r
+}\r
+\r
 // CBrowseRefsDlg dialog\r
 \r
 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
 \r
 CBrowseRefsDlg::CBrowseRefsDlg(CString cmdPath, CWnd* pParent /*=NULL*/)\r
 :      CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent),\r
-       m_cmdPath(cmdPath)\r
+       m_cmdPath(cmdPath),\r
+       m_currSortCol(-1),\r
+       m_currSortDesc(false),\r
+       m_initialRef(L"HEAD")\r
 {\r
 \r
 }\r
@@ -38,6 +63,9 @@ BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)
        ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
        ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
        ON_WM_CONTEXTMENU()\r
+       ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnLvnColumnclickListRefLeafs)\r
+       ON_WM_DESTROY()\r
+       ON_NOTIFY(NM_DBLCLK, IDC_LIST_REF_LEAFS, &CBrowseRefsDlg::OnNMDblclkListRefLeafs)\r
 END_MESSAGE_MAP()\r
 \r
 \r
@@ -56,15 +84,15 @@ BOOL CBrowseRefsDlg::OnInitDialog()
        AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
 \r
        m_ListRefLeafs.SetExtendedStyle(m_ListRefLeafs.GetExtendedStyle()|LVS_EX_FULLROWSELECT);\r
-       m_ListRefLeafs.InsertColumn(0,L"Name",0,150);\r
-       m_ListRefLeafs.InsertColumn(1,L"Date Last Commit",0,100);\r
-       m_ListRefLeafs.InsertColumn(2,L"Last Commit",0,300);\r
-       m_ListRefLeafs.InsertColumn(3,L"Hash",0,80);\r
+       m_ListRefLeafs.InsertColumn(eCol_Name,  L"Name",0,150);\r
+       m_ListRefLeafs.InsertColumn(eCol_Date,  L"Date Last Commit",0,100);\r
+       m_ListRefLeafs.InsertColumn(eCol_Msg,   L"Last Commit",0,300);\r
+       m_ListRefLeafs.InsertColumn(eCol_Hash,  L"Hash",0,80);\r
 \r
        AddAnchor(IDOK,BOTTOM_RIGHT);\r
        AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
 \r
-       Refresh(true);\r
+       Refresh(m_initialRef);\r
 \r
 \r
        return TRUE;\r
@@ -98,38 +126,48 @@ CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)
 \r
 typedef std::map<CString,CString> MAP_STRING_STRING;\r
 \r
-void CBrowseRefsDlg::Refresh(bool bSelectCurHead)\r
+CString CBrowseRefsDlg::GetSelectedRef(bool onlyIfLeaf)\r
 {\r
-//     m_RefMap.clear();\r
-//     g_Git.GetMapHashToFriendName(m_RefMap);\r
-               \r
-       CString selectRef;\r
-       if(bSelectCurHead)\r
+       POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
+       //List ctrl selection?\r
+       if(pos)\r
        {\r
-               g_Git.Run(L"git symbolic-ref HEAD",&selectRef,CP_UTF8);\r
-               selectRef.Trim(L"\r\n\t ");\r
+               //A leaf is selected\r
+               CShadowTree* pTree=(CShadowTree*)m_ListRefLeafs.GetItemData(\r
+                               m_ListRefLeafs.GetNextSelectedItem(pos));\r
+               return pTree->GetRefName();\r
        }\r
-       else\r
+       else if(!onlyIfLeaf)\r
        {\r
-               POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
-               //List ctrl selection?\r
-               if(pos)\r
+               //Tree ctrl selection?\r
+               HTREEITEM hTree=m_RefTreeCtrl.GetSelectedItem();\r
+               if(hTree!=NULL)\r
                {\r
-                       CShadowTree* pTree=(CShadowTree*)m_ListRefLeafs.GetItemData(\r
-                                       m_ListRefLeafs.GetNextSelectedItem(pos));\r
-                       selectRef=pTree->GetRefName();\r
+                       CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTree);\r
+                       return pTree->GetRefName();\r
                }\r
-               else\r
+       }\r
+       return CString();//None\r
+}\r
+\r
+void CBrowseRefsDlg::Refresh(CString selectRef)\r
+{\r
+//     m_RefMap.clear();\r
+//     g_Git.GetMapHashToFriendName(m_RefMap);\r
+               \r
+       if(!selectRef.IsEmpty())\r
+       {\r
+               if(selectRef == "HEAD")\r
                {\r
-                       //Tree ctrl selection?\r
-                       HTREEITEM hTree=m_RefTreeCtrl.GetSelectedItem();\r
-                       if(hTree!=NULL)\r
-                       {\r
-                               CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTree);\r
-                               selectRef=pTree->GetRefName();\r
-                       }\r
+                       selectRef.Empty();\r
+                       g_Git.Run(L"git symbolic-ref HEAD",&selectRef,CP_UTF8);\r
+                       selectRef.Trim(L"\r\n\t ");\r
                }\r
        }\r
+       else\r
+       {\r
+               selectRef = GetSelectedRef(false);\r
+       }\r
 \r
        m_RefTreeCtrl.DeleteAllItems();\r
        m_ListRefLeafs.DeleteAllItems();\r
@@ -145,7 +183,8 @@ void CBrowseRefsDlg::Refresh(bool bSelectCurHead)
                          L"%(objectname)%04"\r
                          L"%(authordate:relative)%04"\r
                          L"%(subject)%04"\r
-                         L"%(authorname)",\r
+                         L"%(authorname)%04"\r
+                         L"%(authordate:iso8601)",\r
                          &allRefs,CP_UTF8);\r
 \r
        int linePos=0;\r
@@ -175,10 +214,11 @@ void CBrowseRefsDlg::Refresh(bool bSelectCurHead)
                CString values=iterRefMap->second;\r
 \r
                int valuePos=0;\r
-               treeLeaf.m_csRefHash= values.Tokenize(L"\04",valuePos);\r
-               treeLeaf.m_csDate=    values.Tokenize(L"\04",valuePos);\r
-               treeLeaf.m_csSubject= values.Tokenize(L"\04",valuePos);\r
-               treeLeaf.m_csAuthor=  values.Tokenize(L"\04",valuePos);\r
+               treeLeaf.m_csRefHash=           values.Tokenize(L"\04",valuePos);\r
+               treeLeaf.m_csDate=                      values.Tokenize(L"\04",valuePos);\r
+               treeLeaf.m_csSubject=           values.Tokenize(L"\04",valuePos);\r
+               treeLeaf.m_csAuthor=            values.Tokenize(L"\04",valuePos);\r
+               treeLeaf.m_csDate_Iso8601=      values.Tokenize(L"\04",valuePos);\r
        }\r
 \r
 \r
@@ -266,6 +306,9 @@ void CBrowseRefsDlg::OnTvnSelchangedTreeRef(NMHDR *pNMHDR, LRESULT *pResult)
 void CBrowseRefsDlg::FillListCtrlForTreeNode(HTREEITEM treeNode)\r
 {\r
        m_ListRefLeafs.DeleteAllItems();\r
+       m_currSortCol = -1;\r
+       m_currSortDesc = false;\r
+       SetSortArrow(&m_ListRefLeafs,-1,false);\r
 \r
        CShadowTree* pTree=(CShadowTree*)(m_RefTreeCtrl.GetItemData(treeNode));\r
        if(pTree==NULL)\r
@@ -283,10 +326,10 @@ void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNa
                int indexItem=m_ListRefLeafs.InsertItem(m_ListRefLeafs.GetItemCount(),L"");\r
 \r
                m_ListRefLeafs.SetItemData(indexItem,(DWORD_PTR)pTree);\r
-               m_ListRefLeafs.SetItemText(indexItem,0,refNamePrefix+pTree->m_csRefName);\r
-               m_ListRefLeafs.SetItemText(indexItem,1,pTree->m_csDate);\r
-               m_ListRefLeafs.SetItemText(indexItem,2,pTree->m_csSubject);\r
-               m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRefHash);\r
+               m_ListRefLeafs.SetItemText(indexItem,eCol_Name, refNamePrefix+pTree->m_csRefName);\r
+               m_ListRefLeafs.SetItemText(indexItem,eCol_Date, pTree->m_csDate);\r
+               m_ListRefLeafs.SetItemText(indexItem,eCol_Msg,  pTree->m_csSubject);\r
+               m_ListRefLeafs.SetItemText(indexItem,eCol_Hash, pTree->m_csRefHash);\r
        }\r
        else\r
        {\r
@@ -301,67 +344,6 @@ void CBrowseRefsDlg::FillListCtrlForShadowTree(CShadowTree* pTree, CString refNa
        }\r
 }\r
 \r
-void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)\r
-{\r
-\r
-       CPoint clientPoint=point;\r
-       m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
-\r
-\r
-       std::vector<CShadowTree*> selectedTrees;\r
-       selectedTrees.reserve(m_ListRefLeafs.GetSelectedCount());\r
-       POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
-       while(pos)\r
-       {\r
-               selectedTrees.push_back(\r
-                       (CShadowTree*)m_ListRefLeafs.GetItemData(\r
-                               m_ListRefLeafs.GetNextSelectedItem(pos)));\r
-       }\r
-\r
-       CMenu popupMenu;\r
-       popupMenu.CreatePopupMenu();\r
-\r
-       if(selectedTrees.size()==1)\r
-       {\r
-               popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
-               if(selectedTrees[0]->IsFrom(L"refs/heads"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");\r
-               else if(selectedTrees[0]->IsFrom(L"refs/tags"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");\r
-\r
-//             CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
-//             if(pTree==NULL)\r
-//                     return;\r
-       }\r
-\r
-\r
-       eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
-       switch(cmd)\r
-       {\r
-       case eCmd_ViewLog:\r
-               {\r
-                       CLogDlg dlg;\r
-                       dlg.SetStartRef(selectedTrees[0]->m_csRefHash);\r
-                       dlg.DoModal();\r
-               }\r
-               break;\r
-       case eCmd_DeleteBranch:\r
-               {\r
-                       if(ConfirmDeleteRef(selectedTrees[0]->GetRefName()))\r
-                               DoDeleteRef(selectedTrees[0]->GetRefName(), true);\r
-                       Refresh();\r
-               }\r
-               break;\r
-       case eCmd_DeleteTag:\r
-               {\r
-                       if(ConfirmDeleteRef(selectedTrees[0]->GetRefName()))\r
-                               DoDeleteRef(selectedTrees[0]->GetRefName(), true);\r
-                       Refresh();\r
-               }\r
-               break;\r
-       }\r
-}\r
-\r
 bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)\r
 {\r
        CString csMessage;\r
@@ -448,21 +430,58 @@ void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)
 \r
 void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)\r
 {\r
-       CMenu popupMenu;\r
-       popupMenu.CreatePopupMenu();\r
-\r
        CPoint clientPoint=point;\r
        m_RefTreeCtrl.ScreenToClient(&clientPoint);\r
 \r
        HTREEITEM hTreeItem=m_RefTreeCtrl.HitTest(clientPoint);\r
        if(hTreeItem!=NULL)\r
-       {\r
                m_RefTreeCtrl.Select(hTreeItem,TVGN_CARET);\r
-               CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreeItem);\r
+\r
+       ShowContextMenu(point,hTreeItem,VectorPShadowTree());\r
+}\r
+\r
+\r
+void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)\r
+{\r
+       std::vector<CShadowTree*> selectedLeafs;\r
+       selectedLeafs.reserve(m_ListRefLeafs.GetSelectedCount());\r
+       POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
+       while(pos)\r
+       {\r
+               selectedLeafs.push_back(\r
+                       (CShadowTree*)m_ListRefLeafs.GetItemData(\r
+                               m_ListRefLeafs.GetNextSelectedItem(pos)));\r
+       }\r
+\r
+       ShowContextMenu(point,m_RefTreeCtrl.GetSelectedItem(),selectedLeafs);\r
+}\r
+\r
+void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)\r
+{\r
+       CMenu popupMenu;\r
+       popupMenu.CreatePopupMenu();\r
+\r
+       if(selectedLeafs.size()==1)\r
+       {\r
+               popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
+               if(selectedLeafs[0]->IsFrom(L"refs/heads"))\r
+                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");\r
+               else if(selectedLeafs[0]->IsFrom(L"refs/tags"))\r
+                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");\r
+\r
+//             CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
+//             if(pTree==NULL)\r
+//                     return;\r
+       }\r
+\r
+       if(hTreePos!=NULL)\r
+       {\r
+               CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreePos);\r
                if(pTree->IsFrom(L"refs/remotes"))\r
                {\r
 //                     popupMenu.AppendMenu(MF_STRING,eCmd_AddRemote,L"Add Remote");\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");\r
+                       if(!m_cmdPath.IsEmpty())\r
+                               popupMenu.AppendMenu(MF_STRING,eCmd_ManageRemotes,L"Manage Remotes");\r
                }\r
                else if(pTree->IsFrom(L"refs/heads"))\r
                        popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
@@ -470,9 +489,31 @@ void CBrowseRefsDlg::OnContextMenu_RefTreeCtrl(CPoint point)
                        popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\r
        }\r
 \r
+\r
        eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);\r
        switch(cmd)\r
        {\r
+       case eCmd_ViewLog:\r
+               {\r
+                       CLogDlg dlg;\r
+                       dlg.SetStartRef(selectedLeafs[0]->m_csRefHash);\r
+                       dlg.DoModal();\r
+               }\r
+               break;\r
+       case eCmd_DeleteBranch:\r
+               {\r
+                       if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
+                               DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
+                       Refresh();\r
+               }\r
+               break;\r
+       case eCmd_DeleteTag:\r
+               {\r
+                       if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
+                               DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
+                       Refresh();\r
+               }\r
+               break;\r
        case eCmd_AddRemote:\r
                {\r
                        CAddRemoteDlg(this).DoModal();\r
@@ -531,3 +572,95 @@ BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)
 \r
        return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
 }\r
+\r
+class CRefLeafListCompareFunc\r
+{\r
+public:\r
+       CRefLeafListCompareFunc(CListCtrl* pList, int col, bool desc):m_col(col),m_desc(desc),m_pList(pList){}\r
+\r
+       static int CALLBACK StaticCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\r
+       {\r
+               return ((CRefLeafListCompareFunc*)lParamSort)->Compare(lParam1,lParam2);\r
+       }\r
+\r
+       int Compare(LPARAM lParam1, LPARAM lParam2)\r
+       {\r
+               return Compare(\r
+                       (CShadowTree*)m_pList->GetItemData(lParam1), \r
+                       (CShadowTree*)m_pList->GetItemData(lParam2));\r
+       }\r
+\r
+       int Compare(CShadowTree* pLeft, CShadowTree* pRight)\r
+       {\r
+               int result=CompareNoDesc(pLeft,pRight);\r
+               if(m_desc)\r
+                       return -result;\r
+               return result;\r
+       }\r
+\r
+       int CompareNoDesc(CShadowTree* pLeft, CShadowTree* pRight)\r
+       {\r
+               switch(m_col)\r
+               {\r
+               case CBrowseRefsDlg::eCol_Name: return pLeft->GetRefName().CompareNoCase(pRight->GetRefName());\r
+               case CBrowseRefsDlg::eCol_Date: return pLeft->m_csDate_Iso8601.CompareNoCase(pRight->m_csDate_Iso8601);\r
+               case CBrowseRefsDlg::eCol_Msg:  return pLeft->m_csSubject.CompareNoCase(pRight->m_csSubject);\r
+               case CBrowseRefsDlg::eCol_Hash: return pLeft->m_csRefHash.CompareNoCase(pRight->m_csRefHash);\r
+               }\r
+               return 0;\r
+       }\r
+\r
+       int m_col;\r
+       bool m_desc;\r
+       CListCtrl* m_pList;\r
+\r
+\r
+};\r
+\r
+\r
+void CBrowseRefsDlg::OnLvnColumnclickListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
+       *pResult = 0;\r
+\r
+       if(m_currSortCol == pNMLV->iSubItem)\r
+               m_currSortDesc = !m_currSortDesc;\r
+       else\r
+       {\r
+               m_currSortCol  = pNMLV->iSubItem;\r
+               m_currSortDesc = false;\r
+       }\r
+\r
+       CRefLeafListCompareFunc compareFunc(&m_ListRefLeafs, m_currSortCol, m_currSortDesc);\r
+       m_ListRefLeafs.SortItemsEx(&CRefLeafListCompareFunc::StaticCompare, (DWORD_PTR)&compareFunc);\r
+\r
+       SetSortArrow(&m_ListRefLeafs,m_currSortCol,!m_currSortDesc);\r
+}\r
+\r
+void CBrowseRefsDlg::OnDestroy()\r
+{\r
+       m_pickedRef = GetSelectedRef(true);\r
+\r
+       CResizableStandAloneDialog::OnDestroy();\r
+}\r
+\r
+void CBrowseRefsDlg::OnNMDblclkListRefLeafs(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);\r
+       *pResult = 0;\r
+\r
+       EndDialog(IDOK);\r
+}\r
+\r
+CString CBrowseRefsDlg::PickRef(bool returnAsHash, CString initialRef)\r
+{\r
+       CBrowseRefsDlg dlg(CString(),NULL);\r
+       \r
+       dlg.m_initialRef = initialRef;\r
+\r
+       if(dlg.DoModal() != IDOK)\r
+               return CString();\r
+\r
+       return dlg.m_pickedRef;\r
+}\r
+\r