[PATCH 8/8] explorerframe/nstc: Implement expanding of nodes.

David Hedberg david.hedberg at gmail.com
Thu Jul 29 14:26:07 CDT 2010


---
 dlls/explorerframe/nstc.c |  160 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/dlls/explorerframe/nstc.c b/dlls/explorerframe/nstc.c
index a6793b0..ce04fa3 100644
--- a/dlls/explorerframe/nstc.c
+++ b/dlls/explorerframe/nstc.c
@@ -95,6 +95,22 @@ static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRo
         This->pnstce, psi, fIsRoot);
 }
 
+static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
+{
+    if(!This->pnstce)
+        return S_OK;
+    return INameSpaceTreeControlEvents_OnBeforeExpand(
+        This->pnstce, psi);
+}
+
+static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
+{
+    if(!This->pnstce)
+        return S_OK;
+    return INameSpaceTreeControlEvents_OnAfterExpand(
+        This->pnstce, psi);
+}
+
 /*************************************************************************
  * NamespaceTree helper functions
  */
@@ -157,6 +173,25 @@ static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
     return (IShellItem*)tvi.lParam;
 }
 
+static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
+{
+    HTREEITEM tmp, hroot = hitem;
+    nstc_root *root;
+
+    /* Work our way up the hierarchy */
+    for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
+        tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
+                                      TVGN_PARENT, (LPARAM)hroot);
+
+    /* Search through the list of roots for a match */
+    LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
+        if(root->htreeitem == hroot)
+            break;
+
+    TRACE("root is %p\n", root);
+    return root;
+}
+
 /* From brsfolder.c */
 static int GetIcon(LPCITEMIDLIST lpi, UINT extra_flags)
 {
@@ -222,6 +257,86 @@ static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
     return hinserted;
 }
 
+static void fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
+{
+    IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
+    nstc_root *root = root_for_treeitem(This, hitem);
+    LPITEMIDLIST pidl_parent;
+    IShellFolder *psfDesktop, *psf;
+    IEnumIDList *peidl;
+    HRESULT hres;
+
+    hres = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
+    if(FAILED(hres))
+    {
+        ERR("Failed to get pidl. \n");
+        return;
+    }
+
+    /* Bind to the ShellFolder for the item */
+    SHGetDesktopFolder(&psfDesktop);
+    hres = IShellFolder_BindToObject(psfDesktop, pidl_parent, NULL,
+                                     &IID_IShellFolder, (void**)&psf);
+    if(FAILED(hres))
+    {
+        LPITEMIDLIST pidl_desktop;
+        /* Check if the folder is the desktop folder */
+        SHGetIDListFromObject((IUnknown*)psfDesktop, &pidl_desktop);
+        if(ILIsEqual(pidl_desktop, pidl_parent))
+        {
+            psf = psfDesktop;
+            ILFree(pidl_desktop);
+            IShellFolder_AddRef(psf);
+        }
+        else
+        {
+            ERR("Failed to bind to ShellFolder.\n");
+            ILFree(pidl_desktop);
+            ILFree(pidl_parent);
+            IShellFolder_Release(psfDesktop);
+            return;
+        }
+    }
+    ILFree(pidl_parent);
+    IShellFolder_Release(psfDesktop);
+
+    /* Enumerate the objects in accordance with the settings for this root */
+    hres = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
+    if(SUCCEEDED(hres))
+    {
+        LPITEMIDLIST pidl;
+        IShellItem *psi;
+        ULONG fetched;
+
+        while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
+        {
+            hres = SHCreateShellItem(NULL, psf , pidl, &psi);
+            ILFree(pidl);
+            if(SUCCEEDED(hres))
+            {
+                if(insert_shellitem(This, psi, hitem, NULL))
+                    events_OnItemAdded(This, psi, FALSE);
+
+                IShellItem_Release(psi);
+            }
+            else
+            {
+                TRACE("Failed to create a shellitem.\n");
+            }
+        }
+        IEnumIDList_Release(peidl);
+    }
+    else
+    {
+        ERR("Failed to get IEnumIDList (%x)\n", hres);
+        return;
+    }
+
+    IShellFolder_Release(psf);
+
+    return;
+}
+
 /*************************************************************************
  * NamespaceTree Window Functions
  */
@@ -336,6 +451,49 @@ static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
     return FALSE;
 }
 
+static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
+{
+    return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
+}
+
+static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
+{
+    NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
+    IShellItem *psi;
+    TRACE("%p\n", This);
+
+    psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
+    events_OnBeforeExpand(This, psi);
+
+    if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
+    {
+        /* The node has no children, try to find some */
+        fill_sublevel(This, nmtv->itemNew.hItem);
+
+        if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
+        {
+            TVITEMEXW tvi;
+            /* Still no children, remove the expando (if any). */
+            tvi.hItem = nmtv->itemNew.hItem;
+            tvi.mask = TVIF_CHILDREN;
+            tvi.cChildren = 0;
+            SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
+        }
+    }
+    return FALSE;
+}
+
+static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
+{
+    NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
+    IShellItem *psi;
+    TRACE("%p\n", This);
+
+    psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
+    events_OnAfterExpand(This, psi);
+    return TRUE;
+}
+
 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
                                       WPARAM wParam, LPARAM lParam)
 {
@@ -353,6 +511,8 @@ static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
         {
         case TVN_DELETEITEMW:     return on_tvn_deleteitemw(This, lParam);
         case TVN_GETDISPINFOW:    return on_tvn_getdispinfow(This, lParam);
+        case TVN_ITEMEXPANDINGW:  return on_tvn_itemexpandingw(This, lParam);
+        case TVN_ITEMEXPANDEDW:   return on_tvn_itemexpandedw(This, lParam);
         default:                  break;
         }
         break;
-- 
1.7.2




More information about the wine-patches mailing list