OSDN Git Service

BrowseRefs: Removed unused confirm dialog
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / BrowseRefsDlg.cpp
index 25f77f2..915b5cf 100644 (file)
@@ -4,14 +4,20 @@
 #include "stdafx.h"\r
 #include "TortoiseProc.h"\r
 #include "BrowseRefsDlg.h"\r
-\r
+#include "LogDlg.h"\r
+#include "AddRemoteDlg.h"\r
+#include "CreateBranchTagDlg.h"\r
+#include "Settings\SettingGitRemote.h"\r
+#include "SinglePropSheetDlg.h"\r
+#include "MessageBox.h"\r
 \r
 // CBrowseRefsDlg dialog\r
 \r
 IMPLEMENT_DYNAMIC(CBrowseRefsDlg, CResizableStandAloneDialog)\r
 \r
-CBrowseRefsDlg::CBrowseRefsDlg(CWnd* pParent /*=NULL*/)\r
-       : CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent)\r
+CBrowseRefsDlg::CBrowseRefsDlg(CString cmdPath, CWnd* pParent /*=NULL*/)\r
+:      CResizableStandAloneDialog(CBrowseRefsDlg::IDD, pParent),\r
+       m_cmdPath(cmdPath)\r
 {\r
 \r
 }\r
@@ -31,6 +37,7 @@ void CBrowseRefsDlg::DoDataExchange(CDataExchange* pDX)
 BEGIN_MESSAGE_MAP(CBrowseRefsDlg, CResizableStandAloneDialog)\r
        ON_BN_CLICKED(IDOK, &CBrowseRefsDlg::OnBnClickedOk)\r
        ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_REF, &CBrowseRefsDlg::OnTvnSelchangedTreeRef)\r
+       ON_WM_CONTEXTMENU()\r
 END_MESSAGE_MAP()\r
 \r
 \r
@@ -57,13 +64,13 @@ BOOL CBrowseRefsDlg::OnInitDialog()
        AddAnchor(IDOK,BOTTOM_RIGHT);\r
        AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
 \r
-       Refresh();\r
+       Refresh(true);\r
 \r
 \r
        return TRUE;\r
 }\r
 \r
-CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)\r
+CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)\r
 {\r
        int posSlash=nameLeft.Find('/');\r
        CString nameSub;\r
@@ -80,23 +87,55 @@ CShadowTree* CShadowTree::GetNextSub(CString& nameLeft)
        if(nameSub.IsEmpty())\r
                return NULL;\r
 \r
+       if(!bCreateIfNotExist && m_ShadowTree.find(nameSub)==m_ShadowTree.end())\r
+               return NULL;\r
+\r
        CShadowTree& nextNode=m_ShadowTree[nameSub];\r
-       nextNode.m_csName=nameSub;\r
+       nextNode.m_csRefName=nameSub;\r
        nextNode.m_pParent=this;\r
        return &nextNode;\r
 }\r
 \r
 typedef std::map<CString,CString> MAP_STRING_STRING;\r
 \r
-void CBrowseRefsDlg::Refresh()\r
+void CBrowseRefsDlg::Refresh(bool bSelectCurHead)\r
 {\r
 //     m_RefMap.clear();\r
 //     g_Git.GetMapHashToFriendName(m_RefMap);\r
                \r
+       CString selectRef;\r
+       if(bSelectCurHead)\r
+       {\r
+               g_Git.Run(L"git symbolic-ref HEAD",&selectRef,CP_UTF8);\r
+               selectRef.Trim(L"\r\n\t ");\r
+       }\r
+       else\r
+       {\r
+               POSITION pos=m_ListRefLeafs.GetFirstSelectedItemPosition();\r
+               //List ctrl selection?\r
+               if(pos)\r
+               {\r
+                       CShadowTree* pTree=(CShadowTree*)m_ListRefLeafs.GetItemData(\r
+                                       m_ListRefLeafs.GetNextSelectedItem(pos));\r
+                       selectRef=pTree->GetRefName();\r
+               }\r
+               else\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
+               }\r
+       }\r
 \r
        m_RefTreeCtrl.DeleteAllItems();\r
+       m_ListRefLeafs.DeleteAllItems();\r
        m_TreeRoot.m_ShadowTree.clear();\r
-       m_TreeRoot.m_csName="Refs";\r
+       m_TreeRoot.m_csRefName="refs";\r
+//     m_TreeRoot.m_csShowName="Refs";\r
        m_TreeRoot.m_hTree=m_RefTreeCtrl.InsertItem(L"Refs",NULL,NULL);\r
        m_RefTreeCtrl.SetItemData(m_TreeRoot.m_hTree,(DWORD_PTR)&m_TreeRoot);\r
 \r
@@ -132,22 +171,18 @@ void CBrowseRefsDlg::Refresh()
        //Populate ref tree\r
        for(MAP_STRING_STRING::iterator iterRefMap=refMap.begin();iterRefMap!=refMap.end();++iterRefMap)\r
        {\r
-               CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first);\r
+               CShadowTree& treeLeaf=GetTreeNode(iterRefMap->first,NULL,true);\r
                CString values=iterRefMap->second;\r
 \r
                int valuePos=0;\r
-               treeLeaf.m_csRef=     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
        }\r
 \r
-       CString currHead;\r
-       g_Git.Run(L"git symbolic-ref HEAD",&currHead,CP_UTF8);\r
 \r
-       currHead.Trim(L"\r\n\t ");\r
-\r
-       if(!SelectRef(currHead))\r
+       if(selectRef.IsEmpty() || !SelectRef(selectRef))\r
                //Probably not on a branch. Select root node.\r
                m_RefTreeCtrl.Expand(m_TreeRoot.m_hTree,TVE_EXPAND);\r
 \r
@@ -158,7 +193,14 @@ bool CBrowseRefsDlg::SelectRef(CString refName)
        if(wcsnicmp(refName,L"refs/",5)!=0)\r
                return false; // Not a ref name\r
 \r
-       CShadowTree& treeLeafHead=GetTreeNode(refName);\r
+       CShadowTree& treeLeafHead=GetTreeNode(refName,NULL,false);\r
+       if(treeLeafHead.m_hTree != NULL)\r
+       {\r
+               //Not a leaf. Select tree node and return\r
+               m_RefTreeCtrl.Select(treeLeafHead.m_hTree,TVGN_CARET);\r
+               return true;\r
+       }\r
+\r
        if(treeLeafHead.m_pParent==NULL)\r
                return false; //Weird... should not occur.\r
 \r
@@ -171,13 +213,14 @@ bool CBrowseRefsDlg::SelectRef(CString refName)
                if(pCurrShadowTree == &treeLeafHead)\r
                {\r
                        m_ListRefLeafs.SetItemState(indexPos,LVIS_SELECTED,LVIS_SELECTED);\r
+                       m_ListRefLeafs.EnsureVisible(indexPos,FALSE);\r
                }\r
        }\r
 \r
        return true;\r
 }\r
 \r
-CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)\r
+CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos, bool bCreateIfNotExist)\r
 {\r
        if(pTreePos==NULL)\r
        {\r
@@ -188,11 +231,11 @@ CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)
        if(refName.IsEmpty())\r
                return *pTreePos;//Found leaf\r
 \r
-       CShadowTree* pNextTree=pTreePos->GetNextSub(refName);\r
+       CShadowTree* pNextTree=pTreePos->GetNextSub(refName,bCreateIfNotExist);\r
        if(pNextTree==NULL)\r
        {\r
-               //Should not occur when all ref-names are valid.\r
-               ASSERT(FALSE);\r
+               //Should not occur when all ref-names are valid and bCreateIfNotExist is true.\r
+               ASSERT(!bCreateIfNotExist);\r
                return *pTreePos;\r
        }\r
 \r
@@ -203,12 +246,12 @@ CShadowTree& CBrowseRefsDlg::GetTreeNode(CString refName, CShadowTree* pTreePos)
                if(pNextTree->m_hTree==NULL)\r
                {\r
                        //New tree. Create node in control.\r
-                       pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csName,pTreePos->m_hTree,NULL);\r
+                       pNextTree->m_hTree=m_RefTreeCtrl.InsertItem(pNextTree->m_csRefName,pTreePos->m_hTree,NULL);\r
                        m_RefTreeCtrl.SetItemData(pNextTree->m_hTree,(DWORD_PTR)pNextTree);\r
                }\r
        }\r
 \r
-       return GetTreeNode(refName,pNextTree);\r
+       return GetTreeNode(refName, pNextTree, bCreateIfNotExist);\r
 }\r
 \r
 \r
@@ -240,20 +283,255 @@ 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_csName);\r
-               m_ListRefLeafs.SetItemText(indexItem,1,refNamePrefix+pTree->m_csDate);\r
-               m_ListRefLeafs.SetItemText(indexItem,2,refNamePrefix+pTree->m_csSubject);\r
-               m_ListRefLeafs.SetItemText(indexItem,3,pTree->m_csRef);\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
        }\r
        else\r
        {\r
 \r
                CString csThisName;\r
                if(!isFirstLevel)\r
-                       csThisName=refNamePrefix+pTree->m_csName+L"/";\r
+                       csThisName=refNamePrefix+pTree->m_csRefName+L"/";\r
                for(CShadowTree::TShadowTreeMap::iterator itSubTree=pTree->m_ShadowTree.begin(); itSubTree!=pTree->m_ShadowTree.end(); ++itSubTree)\r
                {\r
                        FillListCtrlForShadowTree(&itSubTree->second,csThisName,false);\r
                }\r
        }\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
+       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
+       {\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
+               csMessage += branchToDelete;\r
+               csMessage += "</b>";\r
+\r
+               //Check if branch is fully merged in HEAD\r
+               CString branchHash = g_Git.GetHash(completeRefName);\r
+               CString commonAncestor;\r
+               CString cmd;\r
+               cmd.Format(L"git.exe merge-base HEAD %s",completeRefName);\r
+               g_Git.Run(cmd,&commonAncestor,CP_UTF8);\r
+\r
+               branchHash=branchHash.Left(40);\r
+               commonAncestor=commonAncestor.Left(40);\r
+               \r
+               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
+               }\r
+       }\r
+       else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
+       {\r
+               CString tagToDelete = completeRefName.Mid(10);\r
+               csTitle.Format(L"Confirm deletion of tag %s", tagToDelete);\r
+               csMessage += "tag:\r\n\r\n<b>";\r
+               csMessage += tagToDelete;\r
+               csMessage += "</b>";\r
+       }\r
+\r
+       return CMessageBox::Show(m_hWnd,csMessage,csTitle,MB_YESNO|mbIcon)==IDYES;\r
+\r
+}\r
+\r
+\r
+bool CBrowseRefsDlg::DoDeleteRef(CString completeRefName, bool bForce)\r
+{\r
+       if(wcsncmp(completeRefName,L"refs/heads",10)==0)\r
+       {\r
+               CString branchToDelete = completeRefName.Mid(11);\r
+               CString cmd;\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
+                       CString errorMsg;\r
+                       errorMsg.Format(L"Could not delete branch %s. Message from git:\r\n\r\n%s",branchToDelete,resultDummy);\r
+                       CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting branch",MB_OK|MB_ICONERROR);\r
+                       return false;\r
+               }\r
+       }\r
+       else if(wcsncmp(completeRefName,L"refs/tags",9)==0)\r
+       {\r
+               CString tagToDelete = completeRefName.Mid(10);\r
+               CString cmd;\r
+               cmd.Format(L"git.exe tag -d %s",tagToDelete);\r
+               CString resultDummy;\r
+               if(g_Git.Run(cmd,&resultDummy,CP_UTF8)!=0)\r
+               {\r
+                       CString errorMsg;\r
+                       errorMsg.Format(L"Could not delete tag %s. Message from git:\r\n\r\n%s",tagToDelete,resultDummy);\r
+                       CMessageBox::Show(m_hWnd,errorMsg,L"Error deleting tag",MB_OK|MB_ICONERROR);\r
+                       return false;\r
+               }\r
+       }\r
+       return true;\r
+}\r
+\r
+void CBrowseRefsDlg::OnContextMenu(CWnd* pWndFrom, CPoint point)\r
+{\r
+       if(pWndFrom==&m_RefTreeCtrl)       OnContextMenu_RefTreeCtrl(point);\r
+       else if(pWndFrom==&m_ListRefLeafs) OnContextMenu_ListRefLeafs(point);\r
+}\r
+\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
+               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
+               }\r
+               else if(pTree->IsFrom(L"refs/heads"))\r
+                       popupMenu.AppendMenu(MF_STRING,eCmd_CreateBranch,L"Create Branch");\r
+               else if(pTree->IsFrom(L"refs/tags"))\r
+                       popupMenu.AppendMenu(MF_STRING,eCmd_CreateTag,L"Create Tag");\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_AddRemote:\r
+               {\r
+                       CAddRemoteDlg(this).DoModal();\r
+                       Refresh();\r
+               }\r
+               break;\r
+       case eCmd_ManageRemotes:\r
+               {\r
+                       CSinglePropSheetDlg(L"Git Remote Settings",new CSettingGitRemote(m_cmdPath),this).DoModal();\r
+//                     CSettingGitRemote W_Remotes(m_cmdPath);\r
+//                     W_Remotes.DoModal();\r
+                       Refresh();\r
+               }\r
+               break;\r
+       case eCmd_CreateBranch:\r
+               {\r
+                       CCreateBranchTagDlg dlg(this);\r
+                       dlg.m_bIsTag=false;\r
+                       dlg.DoModal();\r
+                       Refresh();\r
+               }\r
+               break;\r
+       case eCmd_CreateTag:\r
+               {\r
+                       CCreateBranchTagDlg dlg(this);\r
+                       dlg.m_bIsTag=true;\r
+                       dlg.DoModal();\r
+                       Refresh();\r
+               }\r
+               break;\r
+       }\r
+}\r
+\r
+BOOL CBrowseRefsDlg::PreTranslateMessage(MSG* pMsg)\r
+{\r
+       if (pMsg->message == WM_KEYDOWN)\r
+       {\r
+               switch (pMsg->wParam)\r
+               {\r
+/*             case VK_RETURN:\r
+                       {\r
+                               if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
+                               {\r
+                                       if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
+                                       {\r
+                                               PostMessage(WM_COMMAND, IDOK);\r
+                                       }\r
+                                       return TRUE;\r
+                               }\r
+                       }\r
+                       break;\r
+*/             case VK_F5:\r
+                       {\r
+                               Refresh();\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+\r
+\r
+       return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
+}\r