Commit f87891c3 authored by David Hedberg's avatar David Hedberg Committed by Alexandre Julliard

explorerframe: Implement InsertRoot and AppendRoot.

parent 94dfbcaa
......@@ -4,7 +4,7 @@ TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = explorerframe.dll
IMPORTS = uuid shell32 user32
IMPORTS = uuid ole32 shell32 user32
C_SRCS = \
explorerframe_main.c \
......
......@@ -27,13 +27,25 @@
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "shellapi.h"
#include "wine/list.h"
#include "wine/debug.h"
#include "explorerframe_main.h"
WINE_DEFAULT_DEBUG_CHANNEL(nstc);
typedef struct nstc_root {
IShellItem *psi;
HTREEITEM htreeitem;
SHCONTF enum_flags;
NSTCROOTSTYLE root_style;
IShellItemFilter *pif;
struct list entry;
} nstc_root;
typedef struct {
const INameSpaceTreeControl2Vtbl *lpVtbl;
const IOleWindowVtbl *lpowVtbl;
......@@ -44,6 +56,7 @@ typedef struct {
NSTCSTYLE style;
NSTCSTYLE2 style2;
struct list roots;
INameSpaceTreeControlEvents *pnstce;
} NSTC2Impl;
......@@ -57,6 +70,22 @@ static const DWORD unsupported_styles2 =
NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
/*************************************************************************
* NamespaceTree event wrappers
*/
static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
{
HRESULT ret;
LONG refcount;
if(!This->pnstce) return S_OK;
refcount = IShellItem_AddRef(psi);
ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
if(IShellItem_Release(psi) < refcount - 1)
ERR("ShellItem was released by client - please file a bug.\n");
return ret;
}
/*************************************************************************
* NamespaceTree helper functions
*/
static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
......@@ -106,6 +135,34 @@ static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
return old_style^*new_style;
}
/* Insert a shellitem into the given place in the tree and return the
resulting treeitem. */
static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
HTREEITEM hParent, HTREEITEM hInsertAfter)
{
TVINSERTSTRUCTW tvins;
TVITEMEXW *tvi = &tvins.u.itemex;
HTREEITEM hinserted;
TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
tvi->cChildren = I_CHILDRENCALLBACK;
tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
tvi->pszText = LPSTR_TEXTCALLBACKW;
/* Every treeitem contains a pointer to the corresponding ShellItem. */
tvi->lParam = (LPARAM)psi;
tvins.hParent = hParent;
tvins.hInsertAfter = hInsertAfter;
hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
(LPARAM)(LPTVINSERTSTRUCTW)&tvins);
if(hinserted)
IShellItem_AddRef(psi);
return hinserted;
}
/*************************************************************************
* NamespaceTree window functions
*/
......@@ -365,8 +422,59 @@ static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
IShellItemFilter *pif)
{
NSTC2Impl *This = (NSTC2Impl*)iface;
FIXME("stub, %p, %p, %x, %x, %p\n", This, psiRoot, grfEnumFlags, grfRootStyle, pif);
return E_NOTIMPL;
nstc_root *new_root;
struct list *add_after_entry;
HTREEITEM add_after_hitem;
UINT i;
TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
if(!new_root)
return E_OUTOFMEMORY;
new_root->psi = psiRoot;
new_root->enum_flags = grfEnumFlags;
new_root->root_style = grfRootStyle;
new_root->pif = pif;
/* We want to keep the roots in the internal list and in the
* treeview in the same order. */
add_after_entry = &This->roots;
for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
add_after_entry = list_next(&This->roots, add_after_entry);
if(add_after_entry == &This->roots)
add_after_hitem = TVI_FIRST;
else
add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
if(!new_root->htreeitem)
{
WARN("Failed to add the root.\n");
HeapFree(GetProcessHeap(), 0, new_root);
return E_FAIL;
}
list_add_after(add_after_entry, &new_root->entry);
events_OnItemAdded(This, psiRoot, TRUE);
if(grfRootStyle & NSTCRS_HIDDEN)
{
TVITEMEXW tvi;
tvi.mask = TVIF_STATEEX;
tvi.uStateEx = TVIS_EX_FLAT;
tvi.hItem = new_root->htreeitem;
SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
}
if(grfRootStyle & NSTCRS_EXPANDED)
SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
(LPARAM)new_root->htreeitem);
return S_OK;
}
static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
......@@ -376,9 +484,13 @@ static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
IShellItemFilter *pif)
{
NSTC2Impl *This = (NSTC2Impl*)iface;
FIXME("stub, %p, %p, %x, %x, %p\n",
UINT root_count;
TRACE("%p, %p, %x, %x, %p\n",
This, psiRoot, grfEnumFlags, grfRootStyle, pif);
return E_NOTIMPL;
root_count = list_count(&This->roots);
return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
}
static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
......@@ -702,6 +814,8 @@ HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void
nstc->lpVtbl = &vt_INameSpaceTreeControl2;
nstc->lpowVtbl = &vt_IOleWindow;
list_init(&nstc->roots);
ret = INameSpaceTreeControl_QueryInterface((INameSpaceTreeControl*)nstc, riid, ppv);
INameSpaceTreeControl_Release((INameSpaceTreeControl*)nstc);
......
......@@ -315,6 +315,35 @@ static INameSpaceTreeControlEventsImpl *create_nstc_events(void)
return This;
}
/* Process some messages */
static void process_msgs(void)
{
MSG msg;
BOOL got_msg;
do {
got_msg = FALSE;
Sleep(100);
while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
got_msg = TRUE;
}
} while(got_msg);
/* There seem to be a timer that sometimes fires after about
500ms, we need to wait for it. Failing to wait can result in
seemingly sporadic selection change events. (Timer ID is 87,
sending WM_TIMER manually does not seem to help us.) */
Sleep(500);
while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/* Returns FALSE if the NamespaceTreeControl failed to be instantiated. */
static BOOL test_initialization(void)
{
......@@ -470,15 +499,52 @@ static void test_basics(void)
{
INameSpaceTreeControl *pnstc;
INameSpaceTreeControl2 *pnstc2;
IShellFolder *psfdesktop;
IShellItem *psidesktop, *psidesktop2;
IOleWindow *pow;
LPITEMIDLIST pidl_desktop;
HRESULT hr;
UINT i, res;
RECT rc;
/* These should exist on platforms supporting the NSTC */
ok(pSHCreateShellItem != NULL, "No SHCreateShellItem.\n");
ok(pSHGetIDListFromObject != NULL, "No SHCreateShellItem.\n");
/* Create ShellItems for testing. */
SHGetDesktopFolder(&psfdesktop);
hr = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl_desktop);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
{
hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psidesktop);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
{
hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psidesktop2);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(FAILED(hr)) IShellItem_Release(psidesktop);
}
ILFree(pidl_desktop);
}
ok(psidesktop != psidesktop2, "psidesktop == psidesktop2\n");
IShellFolder_Release(psfdesktop);
if(FAILED(hr))
{
win_skip("Test setup failed.\n");
return;
}
hr = CoCreateInstance(&CLSID_NamespaceTreeControl, NULL, CLSCTX_INPROC_SERVER,
&IID_INameSpaceTreeControl, (void**)&pnstc);
ok(hr == S_OK, "Failed to initialize control (0x%08x)\n", hr);
/* Some tests on an uninitialized control */
hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_NONFOLDERS, 0, NULL);
ok(hr == E_FAIL, "Got (0x%08x)\n", hr);
process_msgs();
/* Initialize the control */
rc.top = rc.left = 0; rc.right = rc.bottom = 200;
hr = INameSpaceTreeControl_Initialize(pnstc, hwnd, &rc, 0);
......@@ -697,6 +763,37 @@ static void test_basics(void)
skip("INameSpaceTreeControl2 missing.\n");
}
/* Append / Insert root */
if(0)
{
/* Crashes under Windows 7 */
hr = INameSpaceTreeControl_AppendRoot(pnstc, NULL, SHCONTF_FOLDERS, 0, NULL);
hr = INameSpaceTreeControl_InsertRoot(pnstc, 0, NULL, SHCONTF_FOLDERS, 0, NULL);
}
/* Note the usage of psidesktop and psidesktop2 */
hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop2, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
process_msgs();
hr = INameSpaceTreeControl_InsertRoot(pnstc, 0, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_InsertRoot(pnstc, -1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_InsertRoot(pnstc, -1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_InsertRoot(pnstc, 50, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
hr = INameSpaceTreeControl_InsertRoot(pnstc, 1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
IShellItem_Release(psidesktop);
IShellItem_Release(psidesktop2);
hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleWindow, (void**)&pow);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment