Author: gadamopoulos Date: Fri Jun 3 19:35:33 2016 New Revision: 71508 URL: http://svn.reactos.org/svn/reactos?rev=71508&view=rev Log: [BROWSEUI] - CExplorerBand: Implement populating the treeview. You can navigate the shell namespace but clicking on an item doesn't do anything yet. - Part of the work submitted by Sylvain Deverre. CExplorerBand::InsertItem was rewritten by me to be efficient. CORE-10838
Modified: trunk/reactos/dll/win32/browseui/explorerband.cpp trunk/reactos/dll/win32/browseui/explorerband.h Modified: trunk/reactos/dll/win32/browseui/explorerband.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/browseui/explorerband.cpp?rev=71508&r1=71507&r2=71508&view=diff ============================================================================== --- trunk/reactos/dll/win32/browseui/explorerband.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/win32/browseui/explorerband.cpp [iso-8859-1] Fri Jun 3 19:35:33 2016 @@ -1,4 +1,26 @@ +/* + * ReactOS Explorer + * + * Copyright 2016 Sylvain Deverre <deverre dot sylv at gmail dot com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include "precomp.h" +#include <commoncontrols.h> +#include <undocshell.h> #if 1 #undef UNIMPLEMENTED @@ -23,12 +45,267 @@ void CExplorerBand::InitializeExplorerBand() { - + // Init the treeview here + HRESULT hr; + LPITEMIDLIST pidl; + CComPtr<IWebBrowser2> browserService; + SHChangeNotifyEntry shcne; + + hr = SHGetDesktopFolder(&pDesktop); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidl); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + IImageList * piml; + hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml)); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + TreeView_SetImageList(m_hWnd, (HIMAGELIST)piml, TVSIL_NORMAL); + + // Insert the root node + HTREEITEM hItem = InsertItem(0, pDesktop, pidl, pidl, FALSE); + if (!hItem) + { + ERR("Failed to create root item\n"); + return; + } + + NodeInfo* pNodeInfo = GetNodeInfo(hItem); + + // Insert child nodes + InsertSubitems(hItem, pNodeInfo); + TreeView_Expand(m_hWnd, hItem, TVE_EXPAND); + + // Navigate to current folder position + //NavigateToCurrentFolder(); + + // Register shell notification + shcne.pidl = pidl; + shcne.fRecursive = TRUE; + shellRegID = SHChangeNotifyRegister( + m_hWnd, + SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt, + SHCNE_DISKEVENTS | SHCNE_RENAMEFOLDER | SHCNE_RMDIR | SHCNE_MKDIR, + WM_USER_SHELLEVENT, + 1, + &shcne); + if (!shellRegID) + { + ERR("Something went wrong, error %08x\n", GetLastError()); + } + // Register browser connection endpoint + hr = IUnknown_QueryService(pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &browserService)); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + hr = AtlAdvise(browserService, dynamic_cast<IDispatch*>(this), DIID_DWebBrowserEvents, &adviseCookie); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + ILFree(pidl); } void CExplorerBand::DestroyExplorerBand() { - + HRESULT hr; + CComPtr <IWebBrowser2> browserService; + + TRACE("Cleaning up explorer band ...\n"); + + hr = IUnknown_QueryService(pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &browserService)); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + hr = AtlUnadvise(browserService, DIID_DWebBrowserEvents, adviseCookie); + /* Remove all items of the treeview */ + RevokeDragDrop(m_hWnd); + TreeView_DeleteAllItems(m_hWnd); + pDesktop = NULL; + hRoot = NULL; + TRACE("Cleanup done !\n"); +} + +CExplorerBand::NodeInfo* CExplorerBand::GetNodeInfo(HTREEITEM hItem) +{ + TVITEM tvItem; + + tvItem.mask = TVIF_PARAM; + tvItem.hItem = hItem; + + if (!TreeView_GetItem(m_hWnd, &tvItem)) + return 0; + + return reinterpret_cast<NodeInfo*>(tvItem.lParam); +} + +// *** notifications handling *** +BOOL CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv) +{ + NodeInfo *pNodeInfo; + + if (pnmtv->action == TVE_COLLAPSE) { + if (pnmtv->itemNew.hItem == hRoot) + { + // Prenvent root from collapsing + pnmtv->itemNew.mask |= TVIF_STATE; + pnmtv->itemNew.stateMask |= TVIS_EXPANDED; + pnmtv->itemNew.state &= ~TVIS_EXPANDED; + pnmtv->action = TVE_EXPAND; + return TRUE; + } + } + if (pnmtv->action == TVE_EXPAND) { + // Grab our directory PIDL + pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem); + // We have it, let's try + if (pNodeInfo && !pNodeInfo->expanded) + if (!InsertSubitems(pnmtv->itemNew.hItem, pNodeInfo)) { + // remove subitem "+" since we failed to add subitems + TV_ITEM tvItem; + + tvItem.mask = TVIF_CHILDREN; + tvItem.hItem = pnmtv->itemNew.hItem; + tvItem.cChildren = 0; + + TreeView_SetItem(m_hWnd, &tvItem); + } + } + return FALSE; +} + +// *** Helper functions *** +HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort) +{ + TV_INSERTSTRUCT tvInsert; + HTREEITEM htiCreated; + + /* Get the attributes of the node */ + SFGAOF attrs = SFGAO_STREAM | SFGAO_HASSUBFOLDER; + HRESULT hr = psfParent->GetAttributesOf(1, &pEltRelative, &attrs); + if (FAILED_UNEXPECTEDLY(hr)) + return NULL; + + /* Ignore streams */ + if ((attrs & SFGAO_STREAM)) + { + TRACE("Ignoring stream\n"); + return NULL; + } + + /* Get the name of the node */ + WCHAR wszDisplayName[MAX_PATH]; + if (!ILGetDisplayNameEx(psfParent, pEltRelative, wszDisplayName, ILGDN_INFOLDER)) + { + ERR("Failed to get node name\n"); + return NULL; + } + + /* Get the icon of the node */ + INT iIcon = SHMapPIDLToSystemImageListIndex(psfParent, pEltRelative, NULL); + + NodeInfo* pChildInfo = new NodeInfo; + if (!pChildInfo) + { + ERR("Failed to allocate NodeInfo\n"); + return FALSE; + } + + // Store our node info + pChildInfo->absolutePidl = ILClone(pElt); + pChildInfo->relativePidl = ILClone(pEltRelative); + pChildInfo->expanded = FALSE; + + // Set up our treeview template + tvInsert.hParent = hParent; + tvInsert.hInsertAfter = TVI_LAST; + tvInsert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN; + tvInsert.item.cchTextMax = MAX_PATH; + tvInsert.item.pszText = wszDisplayName; + tvInsert.item.iImage = tvInsert.item.iSelectedImage = iIcon; + tvInsert.item.cChildren = (attrs & SFGAO_HASSUBFOLDER) ? 1 : 0; + tvInsert.item.lParam = (LPARAM)pChildInfo; + + htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert); + + return htiCreated; +} + +BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo) +{ + CComPtr<IEnumIDList> pEnumIDList; + LPITEMIDLIST pidlSub; + LPITEMIDLIST entry; + SHCONTF EnumFlags; + HRESULT hr; + ULONG fetched; + ULONG uItemCount; + CComPtr<IShellFolder> pFolder; + + entry = pNodeInfo->absolutePidl; + fetched = 1; + uItemCount = 0; + EnumFlags = SHCONTF_FOLDERS; + + hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidlSub); + if (!SUCCEEDED(hr)) + { + ERR("Can't get desktop PIDL !\n"); + return FALSE; + } + + if (!pDesktop->CompareIDs(NULL, pidlSub, entry)) + { + // We are the desktop, so use pDesktop as pFolder + pFolder = pDesktop; + } + else + { + // Get an IShellFolder of our pidl + hr = pDesktop->BindToObject(entry, NULL, IID_PPV_ARG(IShellFolder, &pFolder)); + if (!SUCCEEDED(hr)) + { + ILFree(pidlSub); + ERR("Can't bind folder to desktop !\n"); + return FALSE; + } + } + ILFree(pidlSub); + + // TODO: handle hidden folders according to settings ! + EnumFlags |= SHCONTF_INCLUDEHIDDEN; + + // Enum through objects + hr = pFolder->EnumObjects(NULL,EnumFlags,&pEnumIDList); + + // avoid broken IShellFolder implementations that return null pointer with success + if (!SUCCEEDED(hr) || !pEnumIDList) + { + ERR("Can't enum the folder !\n"); + return FALSE; + } + + /* Don't redraw while we add stuff into the tree */ + SendMessage(WM_SETREDRAW, FALSE, 0); + while(SUCCEEDED(pEnumIDList->Next(1, &pidlSub, &fetched)) && pidlSub && fetched) + { + LPITEMIDLIST pidlSubComplete; + pidlSubComplete = ILCombine(entry, pidlSub); + + if (InsertItem(hItem, pFolder, pidlSubComplete, pidlSub, FALSE)) + uItemCount++; + ILFree(pidlSubComplete); + ILFree(pidlSub); + } + pNodeInfo->expanded = TRUE; + + /* Now we can redraw */ + SendMessage(WM_SETREDRAW, TRUE, 0); + + return (uItemCount > 0) ? TRUE : FALSE; } // *** IOleWindow methods *** @@ -273,8 +550,19 @@ // *** IWinEventHandler methods *** HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult) { - UNIMPLEMENTED; - return E_NOTIMPL; + if (uMsg == WM_NOTIFY) + { + NMHDR *pNotifyHeader = (NMHDR*)lParam; + switch (pNotifyHeader->code) + { + case TVN_ITEMEXPANDING: + *theResult = OnTreeItemExpanding((LPNMTREEVIEW)lParam); + break; + default: + break; + } + } + return S_OK; } HRESULT STDMETHODCALLTYPE CExplorerBand::IsWindowOwner(HWND hWnd) Modified: trunk/reactos/dll/win32/browseui/explorerband.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/browseui/explorerband.h?rev=71508&r1=71507&r2=71508&view=diff ============================================================================== --- trunk/reactos/dll/win32/browseui/explorerband.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/browseui/explorerband.h [iso-8859-1] Fri Jun 3 19:35:33 2016 @@ -1,3 +1,23 @@ +/* + * ReactOS Explorer + * + * Copyright 2016 Sylvain Deverre <deverre dot sylv at gmail dot com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #pragma once #define WM_USER_SHELLEVENT WM_USER+88 @@ -32,14 +52,28 @@ // *** BaseBarSite information *** CComPtr<IUnknown> pSite; - + CComPtr<IShellFolder> pDesktop; + // *** tree explorer band stuff *** BOOL fVisible; BOOL bFocused; DWORD dwBandID; - + HIMAGELIST hImageList; + HTREEITEM hRoot; + + // *** notification cookies *** + DWORD adviseCookie; + ULONG shellRegID; + void InitializeExplorerBand(); void DestroyExplorerBand(); + + BOOL OnTreeItemExpanding(LPNMTREEVIEW pnmtv); + + // *** Helper functions *** + NodeInfo* GetNodeInfo(HTREEITEM hItem); + HTREEITEM InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort); + BOOL InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo); public: CExplorerBand();