[BROWSEUI]

- CExplorerBand: Implement showing the context menu on right click.
- Part of the work submitted by Sylvain Deverre.
CORE-10838

svn path=/trunk/; revision=72004
This commit is contained in:
Giannis Adamopoulos 2016-07-26 15:09:04 +00:00
parent 0c47416f5d
commit 37a1045d72
2 changed files with 201 additions and 3 deletions

View file

@ -142,6 +142,33 @@ CExplorerBand::NodeInfo* CExplorerBand::GetNodeInfo(HTREEITEM hItem)
return reinterpret_cast<NodeInfo*>(tvItem.lParam);
}
HRESULT CExplorerBand::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
{
CComPtr<IOleWindow> pBrowserOleWnd;
CMINVOKECOMMANDINFO cmi;
HWND browserWnd;
HRESULT hr;
hr = IUnknown_QueryService(pSite, SID_SShellBrowser, IID_PPV_ARG(IOleWindow, &pBrowserOleWnd));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pBrowserOleWnd->GetWindow(&browserWnd);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
ZeroMemory(&cmi, sizeof(cmi));
cmi.cbSize = sizeof(cmi);
cmi.lpVerb = MAKEINTRESOURCEA(nCmd);
cmi.hwnd = browserWnd;
if (GetKeyState(VK_SHIFT) & 0x8000)
cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
if (GetKeyState(VK_CONTROL) & 0x8000)
cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
return menu->InvokeCommand(&cmi);
}
HRESULT CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto)
{
CComPtr<IShellBrowser> pBrowserService;
@ -197,17 +224,111 @@ void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
{
NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
UpdateBrowser(pNodeInfo->absolutePidl);
/* Prevents navigation if selection is initiated inside the band */
if (bNavigating)
return;
UpdateBrowser(pNodeInfo->absolutePidl);
SetFocus();
// Expand the node
//TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
}
// *** ATL event handlers ***
LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
HTREEITEM item;
NodeInfo *info;
HMENU treeMenu;
WORD x;
WORD y;
CComPtr<IShellFolder> pFolder;
CComPtr<IContextMenu> contextMenu;
HRESULT hr;
UINT uCommand;
LPITEMIDLIST pidlChild;
treeMenu = NULL;
item = TreeView_GetSelection(m_hWnd);
bHandled = TRUE;
if (!item)
{
goto Cleanup;
}
x = LOWORD(lParam);
y = HIWORD(lParam);
if (x == -1 && y == -1)
{
// TODO: grab position of tree item and position it correctly
}
info = GetNodeInfo(item);
if (!info)
{
ERR("No node data, something has gone wrong !\n");
goto Cleanup;
}
hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pFolder),
(LPCITEMIDLIST*)&pidlChild);
if (!SUCCEEDED(hr))
{
ERR("Can't bind to folder!\n");
goto Cleanup;
}
hr = pFolder->GetUIObjectOf(m_hWnd, 1, (LPCITEMIDLIST*)&pidlChild, IID_IContextMenu,
NULL, reinterpret_cast<void**>(&contextMenu));
if (!SUCCEEDED(hr))
{
ERR("Can't get IContextMenu interface\n");
goto Cleanup;
}
treeMenu = CreatePopupMenu();
hr = contextMenu->QueryContextMenu(treeMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST,
CMF_EXPLORE);
if (!SUCCEEDED(hr))
{
WARN("Can't get context menu for item\n");
DestroyMenu(treeMenu);
goto Cleanup;
}
uCommand = TrackPopupMenu(treeMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
x, y, 0, m_hWnd, NULL);
ExecuteCommand(contextMenu, uCommand);
Cleanup:
if (treeMenu)
DestroyMenu(treeMenu);
bNavigating = TRUE;
TreeView_SelectItem(m_hWnd, oldSelected);
bNavigating = FALSE;
return TRUE;
}
LRESULT CExplorerBand::ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
bHandled = FALSE;
if (uMsg == WM_RBUTTONDOWN)
{
TVHITTESTINFO info;
info.pt.x = LOWORD(lParam);
info.pt.y = HIWORD(lParam);
info.flags = TVHT_ONITEM;
info.hItem = NULL;
// Save the current location
oldSelected = TreeView_GetSelection(m_hWnd);
// Move to the item selected by the treeview (don't change right pane)
TreeView_HitTest(m_hWnd, &info);
bNavigating = TRUE;
TreeView_SelectItem(m_hWnd, info.hItem);
bNavigating = FALSE;
}
return FALSE; /* let the wndproc process the message */
}
// *** Helper functions ***
HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort)
{
@ -723,6 +844,7 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
// *** IWinEventHandler methods ***
HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
{
BOOL bHandled;
if (uMsg == WM_NOTIFY)
{
NMHDR *pNotifyHeader = (NMHDR*)lParam;
@ -734,6 +856,74 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM
case TVN_SELCHANGED:
OnSelectionChanged((LPNMTREEVIEW)lParam);
break;
case NM_RCLICK:
OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(), bHandled);
*theResult = 1;
break;
case TVN_BEGINLABELEDITW:
{
// TODO: put this in a function ? (mostly copypasta from CDefView)
DWORD dwAttr = SFGAO_CANRENAME;
LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
CComPtr<IShellFolder> pParent;
LPCITEMIDLIST pChild;
HRESULT hr;
*theResult = 1;
NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
if (!info)
return E_FAIL;
hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent), &pChild);
if (!SUCCEEDED(hr) || !pParent.p)
return E_FAIL;
hr = pParent->GetAttributesOf(1, &pChild, &dwAttr);
if (SUCCEEDED(hr) && (dwAttr & SFGAO_CANRENAME))
*theResult = 0;
return S_OK;
}
case TVN_ENDLABELEDITW:
{
LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
HRESULT hr;
*theResult = 0;
if (dispInfo->item.pszText)
{
LPITEMIDLIST pidlNew;
CComPtr<IShellFolder> pParent;
LPCITEMIDLIST pidlChild;
hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent), &pidlChild);
if (!SUCCEEDED(hr) || !pParent.p)
return E_FAIL;
hr = pParent->SetNameOf(0, pidlChild, dispInfo->item.pszText, SHGDN_INFOLDER, &pidlNew);
if(SUCCEEDED(hr) && pidlNew)
{
CComPtr<IPersistFolder2> pPersist;
LPITEMIDLIST pidlParent, pidlNewAbs;
hr = pParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pPersist));
if(!SUCCEEDED(hr))
return E_FAIL;
hr = pPersist->GetCurFolder(&pidlParent);
if(!SUCCEEDED(hr))
return E_FAIL;
pidlNewAbs = ILCombine(pidlParent, pidlNew);
// Navigate to our new location
UpdateBrowser(pidlNewAbs);
ILFree(pidlNewAbs);
ILFree(pidlNew);
*theResult = 1;
}
return S_OK;
}
}
default:
break;
}

View file

@ -61,6 +61,7 @@ private:
DWORD dwBandID;
HIMAGELIST hImageList;
HTREEITEM hRoot;
HTREEITEM oldSelected;
// *** notification cookies ***
DWORD adviseCookie;
@ -68,10 +69,15 @@ private:
void InitializeExplorerBand();
void DestroyExplorerBand();
HRESULT ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd);
BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv);
void OnSelectionChanged(LPNMTREEVIEW pnmtv);
// *** ATL event handlers ***
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
LRESULT ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
// *** Helper functions ***
NodeInfo* GetNodeInfo(HTREEITEM hItem);
HRESULT UpdateBrowser(LPITEMIDLIST pidlGoto);
@ -174,6 +180,8 @@ public:
END_COM_MAP()
BEGIN_MSG_MAP(CExplorerBand)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_RBUTTONDOWN, ContextMenuHack)
END_MSG_MAP()
};