explorerframe: Implement expansion of nodes.

This commit is contained in:
David Hedberg 2010-08-16 09:17:32 +02:00 committed by Alexandre Julliard
parent 6963f37253
commit 4ad1050eb5
2 changed files with 271 additions and 0 deletions

View File

@ -112,6 +112,32 @@ static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRo
return ret;
}
static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
{
HRESULT ret;
LONG refcount;
if(!This->pnstce) return S_OK;
refcount = IShellItem_AddRef(psi);
ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->pnstce, psi);
if(IShellItem_Release(psi) < refcount - 1)
ERR("ShellItem was released by client - please file a bug.\n");
return ret;
}
static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
{
HRESULT ret;
LONG refcount;
if(!This->pnstce) return S_OK;
refcount = IShellItem_AddRef(psi);
ret = INameSpaceTreeControlEvents_OnAfterExpand(This->pnstce, psi);
if(IShellItem_Release(psi) < refcount - 1)
ERR("ShellItem was released by client - please file a bug.\n");
return ret;
}
/*************************************************************************
* NamespaceTree helper functions
*/
@ -176,6 +202,25 @@ static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
return (IShellItem*)tvi.lParam;
}
/* Returns the root that the given treeitem belongs to. */
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;
}
static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
{
SHFILEINFOW sfi;
@ -212,6 +257,67 @@ static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
return hinserted;
}
/* Enumerates the children of the folder represented by hitem
* according to the settings for the root, and adds them to the
* treeview. Returns the number of children added. */
static UINT 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 *psf;
IEnumIDList *peidl;
UINT added = 0;
HRESULT hr;
hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
if(SUCCEEDED(hr))
{
hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
if(SUCCEEDED(hr))
{
hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
if(SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
IShellItem *psi;
ULONG fetched;
while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
{
hr = SHCreateShellItem(NULL, psf , pidl, &psi);
ILFree(pidl);
if(SUCCEEDED(hr))
{
if(insert_shellitem(This, psi, hitem, NULL))
{
events_OnItemAdded(This, psi, FALSE);
added++;
}
IShellItem_Release(psi);
}
else
ERR("SHCreateShellItem failed with 0x%08x\n", hr);
}
IEnumIDList_Release(peidl);
}
else
ERR("EnumObjects failed with 0x%08x\n", hr);
IShellFolder_Release(psf);
}
else
ERR("BindToHandler failed with 0x%08x\n", hr);
ILFree(pidl_parent);
}
else
ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
return added;
}
/*************************************************************************
* NamespaceTree window functions
*/
@ -358,6 +464,50 @@ static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
return TRUE;
}
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 */
if(!fill_sublevel(This, nmtv->itemNew.hItem))
{
TVITEMEXW tvi;
/* Failed to enumerate any 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 TRUE;
}
}
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)
{
@ -375,6 +525,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;

View File

@ -317,6 +317,43 @@ static INameSpaceTreeControlEventsImpl *create_nstc_events(void)
return This;
}
/*********************************************************************
* Event count checking
*/
static void ok_no_events_(INameSpaceTreeControlEventsImpl *impl,
const char *file, int line)
{
UINT i;
for(i = 0; i < LastEvent; i++)
{
ok_(file, line)
(!impl->count[i], "Got event %d, count %d\n", i, impl->count[i]);
impl->count[i] = 0;
}
}
#define ok_no_events(impl) \
ok_no_events_(impl, __FILE__, __LINE__)
#define ok_event_count_broken(impl, event, c, b) \
do { ok(impl->count[event] == c || broken(impl->count[event] == b), \
"Got event %d, count %d\n", event, impl->count[event]); \
impl->count[event] = 0; \
} while(0)
#define ok_event_count(impl, event, c) \
ok_event_count_broken(impl, event, c, -1)
#define ok_event_broken(impl, event) \
do { ok(impl->count[event] || broken(!impl->count[event]), \
"No event.\n"); \
impl->count[event] = 0; \
} while(0)
#define ok_event(impl, event) \
do { ok(impl->count[event], "No event %d.\n", event); \
impl->count[event] = 0; \
} while(0)
/* Process some messages */
static void process_msgs(void)
{
@ -403,6 +440,27 @@ static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
return lpszPath;
}
static HWND get_treeview_hwnd(INameSpaceTreeControl *pnstc)
{
IOleWindow *pow;
HRESULT hr;
HWND treeview = NULL;
hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleWindow, (void**)&pow);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
{
HWND host;
hr = IOleWindow_GetWindow(pow, &host);
ok(hr == S_OK, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
treeview = FindWindowExW(host, NULL, WC_TREEVIEWW, NULL);
IOleWindow_Release(pow);
}
return treeview;
}
/* Returns FALSE if the NamespaceTreeControl failed to be instantiated. */
static BOOL test_initialization(void)
{
@ -1053,6 +1111,7 @@ static void test_events(void)
IOleWindow *pow;
LPITEMIDLIST pidl_desktop;
DWORD cookie1, cookie2;
HWND hwnd_tv;
HRESULT hr;
UINT res;
@ -1074,6 +1133,7 @@ static void test_events(void)
/* Create two instances of INameSpaceTreeControlEvents */
pnstceimpl = create_nstc_events();
pnstce = (INameSpaceTreeControlEvents*)pnstceimpl;
ZeroMemory(&pnstceimpl->count, sizeof(UINT)*LastEvent);
pnstceimpl2 = create_nstc_events();
pnstce2 = (INameSpaceTreeControlEvents*)pnstceimpl2;
@ -1159,6 +1219,62 @@ static void test_events(void)
pnstceimpl->qi_called_count);
ok(pnstceimpl->ref == 1, "refcount was %d\n", pnstceimpl->ref);
/* Advise again.. */
pnstceimpl->qi_enable_events = 1;
pnstceimpl->qi_called_count = 0;
hr = INameSpaceTreeControl_TreeAdvise(pnstc, (IUnknown*)pnstce, &cookie2);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
ok(cookie2 == 1, "Cookie is %d\n", cookie2);
ok(cookie1 == cookie2, "Old cookie differs from old cookie.\n");
todo_wine
{
ok(pnstceimpl->qi_called_count == 7 || pnstceimpl->qi_called_count == 4 /* Vista */,
"QueryInterface called %d times.\n",
pnstceimpl->qi_called_count);
}
ok(pnstceimpl->ref == 2, "refcount was %d\n", pnstceimpl->ref);
/* Initialize the control */
hr = INameSpaceTreeControl_Initialize(pnstc, hwnd, NULL, 0);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
ok_no_events(pnstceimpl);
hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop,
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, 0, NULL);
ok(hr == S_OK, "Got (0x%08x)\n", hr);
process_msgs();
ok_event_count_broken(pnstceimpl, OnItemAdded, 1, 0 /* Vista */);
ok_event_count(pnstceimpl, OnGetDefaultIconIndex, 0);
ok_no_events(pnstceimpl);
hwnd_tv = get_treeview_hwnd(pnstc);
ok(hwnd_tv != NULL, "Failed to get hwnd_tv HWND.\n");
if(hwnd_tv)
{
HTREEITEM hroot;
/* Test On*Expand */
hroot = (HTREEITEM)SendMessageW(hwnd_tv, TVM_GETNEXTITEM, TVGN_ROOT, 0);
SendMessage(hwnd_tv, TVM_EXPAND, TVE_EXPAND, (LPARAM)hroot);
process_msgs();
ok_event_count(pnstceimpl, OnBeforeExpand, 1);
ok_event_count(pnstceimpl, OnAfterExpand, 1);
ok_event_broken(pnstceimpl, OnItemAdded); /* No event on Vista */
todo_wine ok_event_count(pnstceimpl, OnSelectionChanged, 1);
ok_no_events(pnstceimpl);
SendMessage(hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hroot);
process_msgs();
ok_no_events(pnstceimpl);
SendMessage(hwnd_tv, TVM_EXPAND, TVE_EXPAND, (LPARAM)hroot);
process_msgs();
ok_no_events(pnstceimpl);
}
else
skip("Skipping some tests.\n");
hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
process_msgs();
ok(hr == S_OK, "Got 0x%08x\n", hr);
hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleWindow, (void**)&pow);
ok(hr == S_OK, "Got 0x%08x\n", hr);
@ -1171,6 +1287,9 @@ static void test_events(void)
IOleWindow_Release(pow);
}
hr = INameSpaceTreeControl_TreeUnadvise(pnstc, cookie2);
ok(hr == S_OK, "Got 0x%08x\n", hr);
res = INameSpaceTreeControl_Release(pnstc);
ok(!res, "res was %d!\n", res);