[BROWSEUI]
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Tue, 26 Jul 2016 15:09:04 +0000 (15:09 +0000)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Tue, 26 Jul 2016 15:09:04 +0000 (15:09 +0000)
- CExplorerBand: Implement showing the context menu on right click.
- Part of the work submitted by Sylvain Deverre.
CORE-10838

svn path=/trunk/; revision=72004

reactos/dll/win32/browseui/explorerband.cpp
reactos/dll/win32/browseui/explorerband.h

index 0e36405..4e6c3c4 100644 (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;
         }
index c3522c5..0c5a8fc 100644 (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);
@@ -141,7 +147,7 @@ public:
     virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
     virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
     virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
-    
+
     // *** IDropTarget methods ***
     virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect);
     virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect);
@@ -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()
 };