OSDN Git Service

BrowseRefs: Simplified some code
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / BrowseRefsDlg.cpp
index 051de43..6666a72 100644 (file)
 #include "Settings\SettingGitRemote.h"\r
 #include "SinglePropSheetDlg.h"\r
 #include "MessageBox.h"\r
+#include "RefLogDlg.h"\r
+#include "IconMenu.h"\r
+#include "FileDiffDlg.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
@@ -17,7 +42,11 @@ IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)
 \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
+       m_pickRef_Kind(gPickRef_All)\r
 {\r
 \r
 }\r
@@ -38,6 +67,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
@@ -54,20 +86,24 @@ BOOL CBrowseRefsDlg::OnInitDialog()
 \r
        AddAnchor(IDC_TREE_REF, TOP_LEFT, BOTTOM_LEFT);\r
        AddAnchor(IDC_LIST_REF_LEAFS, TOP_LEFT, BOTTOM_RIGHT);\r
+       AddAnchor(IDHELP, 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
+       EnableSaveRestore(L"BrowseRefs");\r
 \r
 \r
-       return TRUE;\r
+       m_ListRefLeafs.SetFocus();\r
+       return FALSE;\r
 }\r
 \r
 CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)\r
@@ -96,40 +132,76 @@ CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)
        return &nextNode;\r
 }\r
 \r
+CShadowTree* CShadowTree::FindLeaf(CString partialRefName)\r
+{\r
+       if(IsLeaf())\r
+       {\r
+               if(m_csRefName.GetLength() > partialRefName.GetLength())\r
+                       return NULL;\r
+               if(partialRefName.Right(m_csRefName.GetLength()) == m_csRefName)\r
+               {\r
+                       //Match of leaf name. Try match on total name.\r
+                       CString totalRefName = GetRefName();\r
+                       if(totalRefName.Right(partialRefName.GetLength()) == partialRefName)\r
+                               return this; //Also match. Found.\r
+               }\r
+       }\r
+       else\r
+       {\r
+               //Not a leaf. Search all nodes.\r
+               for(TShadowTreeMap::iterator itShadowTree = m_ShadowTree.begin(); itShadowTree != m_ShadowTree.end(); ++itShadowTree)\r
+               {\r
+                       CShadowTree* pSubtree = itShadowTree->second.FindLeaf(partialRefName);\r
+                       if(pSubtree != NULL)\r
+                               return pSubtree; //Found\r
+               }\r
+       }\r
+       return NULL;//Not found\r
+}\r
+\r
+\r
 typedef std::map<CString,CString> MAP_STRING_STRING;\r
 \r
-void CBrowseRefsDlg::Refresh(bool bSelectCurHead)\r
+CString CBrowseRefsDlg::GetSelectedRef(bool onlyIfLeaf, bool pickFirstSelIfMultiSel)\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 && (pickFirstSelIfMultiSel || m_ListRefLeafs.GetSelectedCount() == 1))\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 = g_Git.GetSymbolicRef(selectRef, false);\r
                }\r
        }\r
+       else\r
+       {\r
+               selectRef = GetSelectedRef(false, true);\r
+       }\r
 \r
        m_RefTreeCtrl.DeleteAllItems();\r
        m_ListRefLeafs.DeleteAllItems();\r
@@ -145,7 +217,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
@@ -159,37 +232,46 @@ void CBrowseRefsDlg::Refresh(bool bSelectCurHead)
                int valuePos=0;\r
                CString refName=singleRef.Tokenize(L"\04",valuePos);\r
                CString refRest=singleRef.Mid(valuePos);\r
-               refMap[refName]=refRest;\r
-       }\r
 \r
+               //Use ref based on m_pickRef_Kind\r
+               if(wcsncmp(refName,L"refs/heads",10)==0 && !(m_pickRef_Kind & gPickRef_Head) )\r
+                       continue; //Skip\r
+               if(wcsncmp(refName,L"refs/tags",9)==0 && !(m_pickRef_Kind & gPickRef_Tag) )\r
+                       continue; //Skip\r
+               if(wcsncmp(refName,L"refs/remotes",12)==0 && !(m_pickRef_Kind & gPickRef_Remote) )\r
+                       continue; //Skip\r
+\r
+               refMap[refName] = refRest; //Use\r
+       }\r
 \r
 \r
-//     for(MAP_HASH_NAME::iterator iterRef=m_RefMap.begin();iterRef!=m_RefMap.end();++iterRef)\r
-//             for(STRING_VECTOR::iterator iterRefName=iterRef->second.begin();iterRefName!=iterRef->second.end();++iterRefName)\r
-//                     refName[*iterRefName]=iterRef->first;\r
 \r
        //Populate ref tree\r
        for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
        {\r
                CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first,NULL,true);\r
                CString values=iterRefMap->second;\r
+               values.Replace(L"\04" L"\04",L"\04 \04");//Workaround Tokenize problem (treating 2 tokens as one)\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
-       if(selectRef.IsEmpty() || !SelectRef(selectRef))\r
+       if(selectRef.IsEmpty() || !SelectRef(selectRef, false))\r
                //Probably not on a branch. Select root node.\r
                m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
 \r
 }\r
 \r
-bool CBrowseRefsDlg::SelectRef(CString refName)\r
+bool CBrowseRefsDlg::SelectRef(CString refName, bool bExactMatch)\r
 {\r
+       if(!bExactMatch)\r
+               refName = GetFullRefName(refName);\r
        if(wcsnicmp(refName,L"refs/",5)!=0)\r
                return false; // Not a ref name\r
 \r
@@ -266,6 +348,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 +368,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
@@ -307,14 +392,24 @@ bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)
        CString csTitle;\r
 \r
        UINT mbIcon=MB_ICONQUESTION;\r
-       csMessage=L"Are you sure you want to delete the ";\r
-       if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
+       csMessage = L"Are you sure you want to delete the ";\r
+\r
+       bool bIsRemoteBranch = false;\r
+       bool bIsBranch = false;\r
+       if              (wcsncmp(completeRefName, L"refs/remotes",12)==0)       {bIsBranch = true; bIsRemoteBranch = true;}\r
+       else if (wcsncmp(completeRefName, L"refs/heads",10)==0)         {bIsBranch = true;}\r
+\r
+       if(bIsBranch)\r
        {\r
-               CString branchToDelete = completeRefName.Mid(11);\r
-               csTitle.Format(L"Confirm deletion of branch %s", branchToDelete);\r
-               csMessage += "branch:\r\n\r\n<b>";\r
+               CString branchToDelete = completeRefName.Mid(bIsRemoteBranch ? 13 : 11);\r
+               csTitle.Format(L"Confirm deletion of %sbranch %s", \r
+                       bIsRemoteBranch? L"remote ": L"", \r
+                       branchToDelete);\r
+               if(bIsRemoteBranch)\r
+                       csMessage += L"<ct=0x0000FF><i>remote</i></ct> "; \r
+               csMessage += L"branch:\r\n\r\n<b>";\r
                csMessage += branchToDelete;\r
-               csMessage += "</b>";\r
+               csMessage += L"</b>";\r
 \r
                //Check if branch is fully merged in HEAD\r
                CString branchHash = g_Git.GetHash(completeRefName);\r
@@ -329,7 +424,12 @@ bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)
                if(commonAncestor != branchHash)\r
                {\r
                        csMessage += L"\r\n\r\n<b>Warning:\r\nThis branch is not fully merged into HEAD.</b>";\r
-                       mbIcon=MB_ICONWARNING;\r
+                       mbIcon = MB_ICONWARNING;\r
+               }\r
+               if(bIsRemoteBranch)\r
+               {\r
+                       csMessage += L"\r\n\r\n<b>Warning:\r\nThis action will remove the branch on the remote.</b>";\r
+                       mbIcon = MB_ICONWARNING;\r
                }\r
        }\r
        else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
@@ -348,11 +448,26 @@ bool CBrowseRefsDlg::ConfirmDeleteRef(CString completeRefName)
 \r
 bool CBrowseRefsDlg::DoDeleteRef(CString completeRefName, bool bForce)\r
 {\r
-       if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
+       bool bIsRemoteBranch = false;\r
+       bool bIsBranch = false;\r
+       if              (wcsncmp(completeRefName, L"refs/remotes",12)==0)       {bIsBranch = true; bIsRemoteBranch = true;}\r
+       else if (wcsncmp(completeRefName, L"refs/heads",10)==0)         {bIsBranch = true;}\r
+\r
+       if(bIsBranch)\r
        {\r
-               CString branchToDelete = completeRefName.Mid(11);\r
+               CString branchToDelete = completeRefName.Mid(bIsRemoteBranch ? 13 : 11);\r
                CString cmd;\r
-               cmd.Format(L"git.exe branch -%c %s",bForce?L'D':L'd',branchToDelete);\r
+               if(bIsRemoteBranch)\r
+               {\r
+                       int slash = branchToDelete.Find(L'/');\r
+                       if(slash < 0)\r
+                               return false;\r
+                       CString remoteName = branchToDelete.Left(slash);\r
+                       CString remoteBranchToDelete = branchToDelete.Mid(slash + 1);\r
+                       cmd.Format(L"git.exe push \"%s\" :%s", remoteName, remoteBranchToDelete);\r
+               }\r
+               else\r
+                       cmd.Format(L"git.exe branch -%c %s",bForce?L'D':L'd',branchToDelete);\r
                CString resultDummy;\r
                if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
                {\r
@@ -379,6 +494,15 @@ bool CBrowseRefsDlg::DoDeleteRef(CString completeRefName, bool bForce)
        return true;\r
 }\r
 \r
+CString CBrowseRefsDlg::GetFullRefName(CString partialRefName)\r
+{\r
+       CShadowTree* pLeaf = m_TreeRoot.FindLeaf(partialRefName);\r
+       if(pLeaf == NULL)\r
+               return CString();\r
+       return pLeaf->GetRefName();\r
+}\r
+\r
+\r
 void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)\r
 {\r
        if(pWndFrom==&m_RefTreeCtrl)       OnContextMenu_RefTreeCtrl(point);\r
@@ -415,21 +539,54 @@ void CBrowseRefsDlg::OnContextMenu_ListRefLeafs(CPoint point)
 \r
 void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)\r
 {\r
-       CMenu popupMenu;\r
+       CIconMenu popupMenu;\r
        popupMenu.CreatePopupMenu();\r
 \r
+       bool bAddSeparator = false;\r
        if(selectedLeafs.size()==1)\r
        {\r
-               popupMenu.AppendMenu(MF_STRING,eCmd_ViewLog,L"View log");\r
+               bAddSeparator = true;\r
+\r
+               bool bShowReflogOption = false;\r
+               bool bShowDeleteBranchOption = false;\r
+               bool bShowDeleteTagOption = false;\r
+               bool bShowDeleteRemoteBranchOption = false;\r
+\r
                if(selectedLeafs[0]->IsFrom(L"refs/heads"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteBranch,L"Delete Branch");\r
+               {\r
+                       bShowReflogOption = true;\r
+                       bShowDeleteBranchOption = true;\r
+               }\r
+               else if(selectedLeafs[0]->IsFrom(L"refs/remotes"))\r
+               {\r
+                       bShowReflogOption = true;\r
+                       bShowDeleteRemoteBranchOption = true;\r
+               }\r
                else if(selectedLeafs[0]->IsFrom(L"refs/tags"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_DeleteTag,L"Delete Tag");\r
+               {\r
+                       bShowDeleteTagOption = true;\r
+               }\r
+\r
+                                                                                       popupMenu.AppendMenuIcon(eCmd_ViewLog, L"Show Log", IDI_LOG);\r
+               if(bShowReflogOption)                           popupMenu.AppendMenuIcon(eCmd_ShowReflog, L"Show Reflog", IDI_LOG);\r
+               if(bShowDeleteTagOption)                        popupMenu.AppendMenuIcon(eCmd_DeleteTag, L"Delete Tag", IDI_DELETE);\r
+               if(bShowDeleteBranchOption)                     popupMenu.AppendMenuIcon(eCmd_DeleteBranch, L"Delete Branch", IDI_DELETE);\r
+               if(bShowDeleteRemoteBranchOption)       popupMenu.AppendMenuIcon(eCmd_DeleteRemoteBranch, L"Delete Remote Branch", IDI_DELETE);\r
+\r
+\r
 \r
 //             CShadowTree* pTree = (CShadowTree*)m_ListRefLeafs.GetItemData(pNMHDR->idFrom);\r
 //             if(pTree==NULL)\r
 //                     return;\r
        }\r
+       else if(selectedLeafs.size() == 2)\r
+       {\r
+               bAddSeparator = true;\r
+               \r
+               popupMenu.AppendMenuIcon(eCmd_Diff, L"Diff These Commits", IDI_DIFF);\r
+       }\r
+\r
+       if(bAddSeparator) popupMenu.AppendMenu(MF_SEPARATOR);\r
 \r
        if(hTreePos!=NULL)\r
        {\r
@@ -437,12 +594,12 @@ void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPSh
                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
+                       popupMenu.AppendMenuIcon(eCmd_ManageRemotes, L"Manage Remotes", IDI_SETTINGS);\r
                }\r
                else if(pTree->IsFrom(L"refs/heads"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
+                       popupMenu.AppendMenuIcon(eCmd_CreateBranch, L"Create Branch", IDI_COPY);\r
                else if(pTree->IsFrom(L"refs/tags"))\r
-                       popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\r
+                       popupMenu.AppendMenuIcon(eCmd_CreateTag, L"Create Tag", IDI_TAG);\r
        }\r
 \r
 \r
@@ -452,11 +609,12 @@ void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPSh
        case eCmd_ViewLog:\r
                {\r
                        CLogDlg dlg;\r
-                       dlg.SetStartRef(selectedLeafs[0]->m_csRefHash);\r
+                       dlg.SetStartRef(selectedLeafs[0]->GetRefName());\r
                        dlg.DoModal();\r
                }\r
                break;\r
        case eCmd_DeleteBranch:\r
+       case eCmd_DeleteRemoteBranch:\r
                {\r
                        if(ConfirmDeleteRef(selectedLeafs[0]->GetRefName()))\r
                                DoDeleteRef(selectedLeafs[0]->GetRefName(), true);\r
@@ -470,6 +628,13 @@ void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPSh
                        Refresh();\r
                }\r
                break;\r
+       case eCmd_ShowReflog:\r
+               {\r
+                       CRefLogDlg refLogDlg(this);\r
+                       refLogDlg.m_CurrentBranch = selectedLeafs[0]->GetRefName();\r
+                       refLogDlg.DoModal();\r
+               }\r
+               break;\r
        case eCmd_AddRemote:\r
                {\r
                        CAddRemoteDlg(this).DoModal();\r
@@ -478,7 +643,7 @@ void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPSh
                break;\r
        case eCmd_ManageRemotes:\r
                {\r
-                       CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();\r
+                       CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(g_Git.m_CurrentDir),this).DoModal();\r
 //                     CSettingGitRemote W_Remotes(m_cmdPath);\r
 //                     W_Remotes.DoModal();\r
                        Refresh();\r
@@ -496,6 +661,16 @@ void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPSh
                        Refresh();\r
                }\r
                break;\r
+       case eCmd_Diff:\r
+               {\r
+                       CFileDiffDlg dlg;\r
+                       dlg.SetDiff(\r
+                               NULL, \r
+                               selectedLeafs[0]->m_csRefHash, \r
+                               selectedLeafs[1]->m_csRefHash);\r
+                       dlg.DoModal();\r
+               }\r
+               break;\r
        }\r
 }\r
 \r
@@ -528,3 +703,132 @@ 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, false);\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, int pickRef_Kind)\r
+{\r
+       CBrowseRefsDlg dlg(CString(),NULL);\r
+       \r
+       if(initialRef.IsEmpty())\r
+               initialRef = L"HEAD";\r
+       dlg.m_initialRef = initialRef;\r
+       dlg.m_pickRef_Kind = pickRef_Kind;\r
+\r
+       if(dlg.DoModal() != IDOK)\r
+               return CString();\r
+\r
+       return dlg.m_pickedRef;\r
+}\r
+\r
+bool CBrowseRefsDlg::PickRefForCombo(CComboBoxEx* pComboBox, int pickRef_Kind)\r
+{\r
+       CString origRef;\r
+       pComboBox->GetLBText(pComboBox->GetCurSel(), origRef);\r
+       CString resultRef = PickRef(false,origRef,pickRef_Kind);\r
+       if(resultRef.IsEmpty())\r
+               return false;\r
+       if(wcsncmp(resultRef,L"refs/",5)==0)\r
+               resultRef = resultRef.Mid(5);\r
+//     if(wcsncmp(resultRef,L"heads/",6)==0)\r
+//             resultRef = resultRef.Mid(6);\r
+\r
+       //Find closest match of choice in combobox\r
+       int ixFound = -1;\r
+       int matchLength = 0;\r
+       CString comboRefName;\r
+       for(int i = 0; i < pComboBox->GetCount(); ++i)\r
+       {\r
+               pComboBox->GetLBText(i, comboRefName);\r
+               if(comboRefName.Find(L'/') < 0 && !comboRefName.IsEmpty())\r
+                       comboRefName.Insert(0,L"heads/"); // If combo contains single level ref name, it is usualy from 'heads/'\r
+               if(matchLength < comboRefName.GetLength() && resultRef.Right(comboRefName.GetLength()) == comboRefName)\r
+               {\r
+                       matchLength = comboRefName.GetLength();\r
+                       ixFound = i;\r
+               }\r
+       }\r
+       if(ixFound >= 0)\r
+               pComboBox->SetCurSel(ixFound);\r
+       else\r
+               ASSERT(FALSE);//No match found. So either pickRef_Kind is wrong or the combobox does not contain the ref specified in the picker (which it should unless the repo has changed before creating the CBrowseRef dialog)\r
+\r
+       return true;\r
+}\r