mirror of
https://github.com/reactos/reactos.git
synced 2025-06-01 15:38:37 +00:00
[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 svn path=/trunk/; revision=71508
This commit is contained in:
parent
0d6d9c18cc
commit
25917dcb89
2 changed files with 326 additions and 4 deletions
|
@ -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 "precomp.h"
|
||||||
|
#include <commoncontrols.h>
|
||||||
|
#include <undocshell.h>
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
#undef UNIMPLEMENTED
|
#undef UNIMPLEMENTED
|
||||||
|
@ -23,12 +45,267 @@ CExplorerBand::~CExplorerBand()
|
||||||
|
|
||||||
void CExplorerBand::InitializeExplorerBand()
|
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()
|
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 ***
|
// *** IOleWindow methods ***
|
||||||
|
@ -273,8 +550,19 @@ HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
||||||
// *** IWinEventHandler methods ***
|
// *** IWinEventHandler methods ***
|
||||||
HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
|
HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
if (uMsg == WM_NOTIFY)
|
||||||
return E_NOTIMPL;
|
{
|
||||||
|
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)
|
HRESULT STDMETHODCALLTYPE CExplorerBand::IsWindowOwner(HWND hWnd)
|
||||||
|
|
|
@ -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
|
#pragma once
|
||||||
|
|
||||||
#define WM_USER_SHELLEVENT WM_USER+88
|
#define WM_USER_SHELLEVENT WM_USER+88
|
||||||
|
@ -32,15 +52,29 @@ private:
|
||||||
|
|
||||||
// *** BaseBarSite information ***
|
// *** BaseBarSite information ***
|
||||||
CComPtr<IUnknown> pSite;
|
CComPtr<IUnknown> pSite;
|
||||||
|
CComPtr<IShellFolder> pDesktop;
|
||||||
|
|
||||||
// *** tree explorer band stuff ***
|
// *** tree explorer band stuff ***
|
||||||
BOOL fVisible;
|
BOOL fVisible;
|
||||||
BOOL bFocused;
|
BOOL bFocused;
|
||||||
DWORD dwBandID;
|
DWORD dwBandID;
|
||||||
|
HIMAGELIST hImageList;
|
||||||
|
HTREEITEM hRoot;
|
||||||
|
|
||||||
|
// *** notification cookies ***
|
||||||
|
DWORD adviseCookie;
|
||||||
|
ULONG shellRegID;
|
||||||
|
|
||||||
void InitializeExplorerBand();
|
void InitializeExplorerBand();
|
||||||
void DestroyExplorerBand();
|
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:
|
public:
|
||||||
CExplorerBand();
|
CExplorerBand();
|
||||||
virtual ~CExplorerBand();
|
virtual ~CExplorerBand();
|
||||||
|
|
Loading…
Reference in a new issue