#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
+ m_pickRef_Kind(gPickRef_All)\r
{\r
\r
}\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
AddAnchor(IDOK,BOTTOM_RIGHT);\r
AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
\r
- Refresh(true);\r
+ Refresh(m_initialRef);\r
\r
\r
- return TRUE;\r
+ m_ListRefLeafs.SetFocus();\r
+ return FALSE;\r
}\r
\r
CShadowTree* CShadowTree::GetNextSub(CString& nameLeft, bool bCreateIfNotExist)\r
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)\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
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
\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
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
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
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
class CRefLeafListCompareFunc\r
{\r
public:\r
- CRefLeafListCompareFunc(CListCtrl* pList, int col):m_col(col),m_pList(pList){}\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
\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
- break;\r
case CBrowseRefsDlg::eCol_Date: return pLeft->m_csDate_Iso8601.CompareNoCase(pRight->m_csDate_Iso8601);\r
- break;\r
case CBrowseRefsDlg::eCol_Msg: return pLeft->m_csSubject.CompareNoCase(pRight->m_csSubject);\r
- break;\r
case CBrowseRefsDlg::eCol_Hash: return pLeft->m_csRefHash.CompareNoCase(pRight->m_csRefHash);\r
- break;\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
- CRefLeafListCompareFunc compareFunc(&m_ListRefLeafs,pNMLV->iSubItem);\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, int pickRef_Kind)\r
+{\r
+ CBrowseRefsDlg dlg(CString(),NULL);\r
+ \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(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