TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / explorerframe / nstc.c
blob87a72005f4fed0fc5a799b0c2b069610bb2f1b2f
1 /*
2 * NamespaceTreeControl implementation.
4 * Copyright 2010 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "shellapi.h"
32 #include "wine/list.h"
33 #include "wine/debug.h"
35 #include "explorerframe_main.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
39 typedef struct nstc_root {
40 IShellItem *psi;
41 HTREEITEM htreeitem;
42 SHCONTF enum_flags;
43 NSTCROOTSTYLE root_style;
44 IShellItemFilter *pif;
45 struct list entry;
46 } nstc_root;
48 typedef struct {
49 INameSpaceTreeControl2 INameSpaceTreeControl2_iface;
50 IOleWindow IOleWindow_iface;
51 LONG ref;
53 HWND hwnd_main;
54 HWND hwnd_tv;
56 WNDPROC tv_oldwndproc;
58 NSTCSTYLE style;
59 NSTCSTYLE2 style2;
60 struct list roots;
62 INameSpaceTreeControlCustomDraw *customdraw;
63 INameSpaceTreeControlDropHandler *dragdrop;
64 INameSpaceTreeControlEvents *events;
65 } NSTC2Impl;
67 static const DWORD unsupported_styles =
68 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
69 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
70 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
71 static const DWORD unsupported_styles2 =
72 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
73 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
75 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
77 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
80 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
82 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
85 /* Forward declarations */
86 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
88 /*************************************************************************
89 * NamespaceTree event wrappers
91 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
92 int *piDefaultIcon, int *piOpenIcon)
94 HRESULT ret;
95 LONG refcount;
96 if(!This->events) return E_NOTIMPL;
98 refcount = IShellItem_AddRef(psi);
99 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->events, psi, piDefaultIcon, piOpenIcon);
100 if(IShellItem_Release(psi) < refcount - 1)
101 ERR("ShellItem was released by client - please file a bug.\n");
102 return ret;
105 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
107 HRESULT ret;
108 LONG refcount;
109 if(!This->events) return S_OK;
111 refcount = IShellItem_AddRef(psi);
112 ret = INameSpaceTreeControlEvents_OnItemAdded(This->events, psi, fIsRoot);
113 if(IShellItem_Release(psi) < refcount - 1)
114 ERR("ShellItem was released by client - please file a bug.\n");
115 return ret;
118 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
120 HRESULT ret;
121 LONG refcount;
122 if(!This->events) return S_OK;
124 refcount = IShellItem_AddRef(psi);
125 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->events, psi, fIsRoot);
126 if(IShellItem_Release(psi) < refcount - 1)
127 ERR("ShellItem was released by client - please file a bug.\n");
128 return ret;
131 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
133 HRESULT ret;
134 LONG refcount;
135 if(!This->events) return S_OK;
137 refcount = IShellItem_AddRef(psi);
138 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->events, psi);
139 if(IShellItem_Release(psi) < refcount - 1)
140 ERR("ShellItem was released by client - please file a bug.\n");
141 return ret;
144 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
146 HRESULT ret;
147 LONG refcount;
148 if(!This->events) return S_OK;
150 refcount = IShellItem_AddRef(psi);
151 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->events, psi);
152 if(IShellItem_Release(psi) < refcount - 1)
153 ERR("ShellItem was released by client - please file a bug.\n");
154 return ret;
157 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
158 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
160 HRESULT ret;
161 LONG refcount;
162 if(!This->events) return S_OK;
164 refcount = IShellItem_AddRef(psi);
165 ret = INameSpaceTreeControlEvents_OnItemClick(This->events, psi, nstceHitTest, nstceClickType);
166 if(IShellItem_Release(psi) < refcount - 1)
167 ERR("ShellItem was released by client - please file a bug.\n");
168 return ret;
171 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
173 if(!This->events) return S_OK;
175 return INameSpaceTreeControlEvents_OnSelectionChanged(This->events, psia);
178 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
180 if(!This->events) return S_OK;
182 return INameSpaceTreeControlEvents_OnKeyboardInput(This->events, uMsg, wParam, lParam);
185 /*************************************************************************
186 * NamespaceTree helper functions
188 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
189 NSTCSTYLE nstcs_mask, DWORD *new_style)
191 DWORD old_style, tv_mask = 0;
192 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
194 if(This->hwnd_tv)
195 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
196 else
197 old_style = /* The default */
198 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
199 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
200 TVS_EDITLABELS | TVS_TRACKSELECT;
202 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
203 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
204 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
205 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
206 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
207 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
208 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
209 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
210 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
211 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
212 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
214 *new_style = 0;
216 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
217 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
218 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
219 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
220 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
221 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
222 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
223 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
224 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
225 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
226 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
228 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
230 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
232 return old_style^*new_style;
235 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
237 TVITEMEXW tvi;
239 tvi.mask = TVIF_PARAM;
240 tvi.lParam = 0;
241 tvi.hItem = hitem;
243 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
245 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
246 return (IShellItem*)tvi.lParam;
249 /* Returns the root that the given treeitem belongs to. */
250 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
252 HTREEITEM tmp, hroot = hitem;
253 nstc_root *root;
255 /* Work our way up the hierarchy */
256 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
257 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
259 /* Search through the list of roots for a match */
260 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
261 if(root->htreeitem == hroot)
262 break;
264 TRACE("root is %p\n", root);
265 return root;
268 /* Find a shellitem in the tree, starting from the given node. */
269 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
270 IShellItem *psi)
272 IShellItem *psi_node;
273 HTREEITEM next, result = NULL;
274 HRESULT hr;
275 int cmpo;
276 TRACE("%p, %p, %p\n", This, node, psi);
278 /* Check this node */
279 psi_node = shellitem_from_treeitem(This, node);
280 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
281 if(hr == S_OK)
282 return node;
284 /* Any children? */
285 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
286 TVGN_CHILD, (LPARAM)node);
287 if(next)
289 result = search_for_shellitem(This, next, psi);
290 if(result) return result;
293 /* Try our next sibling. */
294 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
295 TVGN_NEXT, (LPARAM)node);
296 if(next)
297 result = search_for_shellitem(This, next, psi);
299 return result;
302 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
304 HTREEITEM root;
305 TRACE("%p, %p\n", This, psi);
307 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
308 TVGN_ROOT, 0);
309 if(!root)
310 return NULL;
312 return search_for_shellitem(This, root, psi);
315 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
317 SHFILEINFOW sfi;
318 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
319 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
320 return sfi.iIcon;
323 /* Insert a shellitem into the given place in the tree and return the
324 resulting treeitem. */
325 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
326 HTREEITEM hParent, HTREEITEM hInsertAfter)
328 TVINSERTSTRUCTW tvins;
329 TVITEMEXW *tvi = &tvins.u.itemex;
330 HTREEITEM hinserted;
331 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
333 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
334 tvi->cChildren = I_CHILDRENCALLBACK;
335 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
336 tvi->pszText = LPSTR_TEXTCALLBACKW;
338 /* Every treeitem contains a pointer to the corresponding ShellItem. */
339 tvi->lParam = (LPARAM)psi;
340 tvins.hParent = hParent;
341 tvins.hInsertAfter = hInsertAfter;
343 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
344 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
345 if(hinserted)
346 IShellItem_AddRef(psi);
348 return hinserted;
351 /* Enumerates the children of the folder represented by hitem
352 * according to the settings for the root, and adds them to the
353 * treeview. Returns the number of children added. */
354 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
356 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
357 nstc_root *root = root_for_treeitem(This, hitem);
358 LPITEMIDLIST pidl_parent;
359 IShellFolder *psf;
360 IEnumIDList *peidl;
361 UINT added = 0;
362 HRESULT hr;
364 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
365 if(SUCCEEDED(hr))
367 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
368 if(SUCCEEDED(hr))
370 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
371 if(SUCCEEDED(hr))
373 LPITEMIDLIST pidl;
374 IShellItem *psi;
375 ULONG fetched;
377 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
379 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
380 ILFree(pidl);
381 if(SUCCEEDED(hr))
383 if(insert_shellitem(This, psi, hitem, NULL))
385 events_OnItemAdded(This, psi, FALSE);
386 added++;
389 IShellItem_Release(psi);
391 else
392 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
394 IEnumIDList_Release(peidl);
396 else
397 ERR("EnumObjects failed with 0x%08x\n", hr);
399 IShellFolder_Release(psf);
401 else
402 ERR("BindToHandler failed with 0x%08x\n", hr);
404 ILFree(pidl_parent);
406 else
407 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
409 return added;
412 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
414 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
417 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
419 return shellitem_from_treeitem(This, get_selected_treeitem(This));
422 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
424 HTREEITEM next;
426 /* Collapse this node first, and then first child/next sibling. */
427 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
429 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
430 if(next) collapse_all(This, next);
432 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
433 if(next) collapse_all(This, next);
436 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
438 TVHITTESTINFO tviht;
439 tviht.pt.x = pt->x;
440 tviht.pt.y = pt->y;
441 tviht.hItem = NULL;
443 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
444 if(hitflag) *hitflag = tviht.flags;
445 return tviht.hItem;
448 /*************************************************************************
449 * NamespaceTree window functions
451 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
453 NSTC2Impl *This = crs->lpCreateParams;
454 HIMAGELIST ShellSmallIconList;
455 DWORD treeview_style, treeview_ex_style;
457 TRACE("%p (%p)\n", This, crs);
458 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
459 This->hwnd_main = hWnd;
461 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
463 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
464 0, 0, crs->cx, crs->cy,
465 hWnd, NULL, explorerframe_hinstance, NULL);
467 if(!This->hwnd_tv)
469 ERR("Failed to create treeview!\n");
470 return HRESULT_FROM_WIN32(GetLastError());
473 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
474 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
476 if(This->style & NSTCS_AUTOHSCROLL)
477 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
478 if(This->style & NSTCS_FADEINOUTEXPANDOS)
479 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
480 if(This->style & NSTCS_PARTIALCHECKBOXES)
481 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
482 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
483 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
484 if(This->style & NSTCS_DIMMEDCHECKBOXES)
485 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
487 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
489 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
491 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
492 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
494 else
496 ERR("Failed to get the System Image List.\n");
499 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
501 /* Subclass the treeview to get the keybord events. */
502 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
503 (ULONG_PTR)tv_wndproc);
504 if(This->tv_oldwndproc)
505 SetPropA(This->hwnd_tv, "PROP_THIS", This);
507 return TRUE;
510 static LRESULT resize_namespacetree(NSTC2Impl *This)
512 RECT rc;
513 TRACE("%p\n", This);
515 GetClientRect(This->hwnd_main, &rc);
516 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
518 return TRUE;
521 static LRESULT destroy_namespacetree(NSTC2Impl *This)
523 TRACE("%p\n", This);
525 /* Undo the subclassing */
526 if(This->tv_oldwndproc)
528 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
529 RemovePropA(This->hwnd_tv, "PROP_THIS");
532 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
534 /* This reference was added in create_namespacetree */
535 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
536 return TRUE;
539 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
541 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
542 TRACE("%p\n", This);
544 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
545 return TRUE;
548 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
550 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
551 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
552 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
553 HRESULT hr;
555 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
557 if(item->mask & TVIF_CHILDREN)
559 SFGAOF sfgao;
561 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
562 if(SUCCEEDED(hr))
563 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
564 else
565 item->cChildren = 1;
567 item->mask |= TVIF_DI_SETITEM;
570 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
572 LPITEMIDLIST pidl;
574 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
575 if(FAILED(hr))
577 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
578 if(SUCCEEDED(hr))
580 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
581 item->mask |= TVIF_DI_SETITEM;
582 ILFree(pidl);
584 else
585 ERR("Failed to get IDList (%08x).\n", hr);
589 if(item->mask & TVIF_TEXT)
591 LPWSTR display_name;
593 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
594 if(SUCCEEDED(hr))
596 lstrcpynW(item->pszText, display_name, MAX_PATH);
597 item->mask |= TVIF_DI_SETITEM;
598 CoTaskMemFree(display_name);
600 else
601 ERR("Failed to get display name (%08x).\n", hr);
604 return TRUE;
607 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
609 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
612 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
614 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
615 IShellItem *psi;
616 TRACE("%p\n", This);
618 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
619 events_OnBeforeExpand(This, psi);
621 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
623 /* The node has no children, try to find some */
624 if(!fill_sublevel(This, nmtv->itemNew.hItem))
626 TVITEMEXW tvi;
627 /* Failed to enumerate any children, remove the expando
628 * (if any). */
629 tvi.hItem = nmtv->itemNew.hItem;
630 tvi.mask = TVIF_CHILDREN;
631 tvi.cChildren = 0;
632 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
634 return TRUE;
637 return FALSE;
640 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
642 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
643 IShellItem *psi;
644 TRACE("%p\n", This);
646 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
647 events_OnAfterExpand(This, psi);
648 return TRUE;
651 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
653 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
654 IShellItemArray *psia;
655 IShellItem *psi;
656 HRESULT hr;
657 TRACE("%p\n", This);
659 /* Note: Only supports one selected item. */
660 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
661 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
662 if(SUCCEEDED(hr))
664 events_OnSelectionChanged(This, psia);
665 IShellItemArray_Release(psia);
668 return TRUE;
671 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
673 TVHITTESTINFO tvhit;
674 IShellItem *psi;
675 HRESULT hr;
676 TRACE("%p (%p)\n", This, nmhdr);
678 GetCursorPos(&tvhit.pt);
679 ScreenToClient(This->hwnd_tv, &tvhit.pt);
680 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
682 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
683 return TRUE;
685 /* TVHT_ maps onto the corresponding NSTCEHT_ */
686 psi = shellitem_from_treeitem(This, tvhit.hItem);
687 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
689 /* The expando should not be expanded unless
690 * double-clicked. */
691 if(tvhit.flags == TVHT_ONITEMBUTTON)
692 return TRUE;
694 if(SUCCEEDED(hr))
695 return FALSE;
696 else
697 return TRUE;
700 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
702 TVHITTESTINFO tvhit;
703 IShellItem *psi;
704 HRESULT hr;
705 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
707 tvhit.pt.x = (int)(short)LOWORD(lParam);
708 tvhit.pt.y = (int)(short)HIWORD(lParam);
710 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
712 /* Seems to generate only ONITEM and ONITEMICON */
713 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
714 return FALSE;
716 psi = shellitem_from_treeitem(This, tvhit.hItem);
717 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
719 if(SUCCEEDED(hr))
720 return FALSE;
721 else
722 return TRUE;
725 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
727 IShellItem *psi;
728 HTREEITEM hitem;
729 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
731 /* Handled by the client? */
732 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
733 return TRUE;
735 if(uMsg == WM_KEYDOWN)
737 switch(wParam)
739 case VK_DELETE:
740 psi = get_selected_shellitem(This);
741 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
742 return TRUE;
744 case VK_F2:
745 hitem = get_selected_treeitem(This);
746 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
747 return TRUE;
751 /* Let the TreeView handle the key */
752 return FALSE;
755 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
757 NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS");
759 switch(uMessage) {
760 case WM_KEYDOWN:
761 case WM_KEYUP:
762 case WM_CHAR:
763 case WM_SYSKEYDOWN:
764 case WM_SYSKEYUP:
765 case WM_SYSCHAR:
766 if(on_kbd_event(This, uMessage, wParam, lParam))
767 return TRUE;
768 break;
770 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
773 /* Pass the message on to the treeview */
774 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
777 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
778 WPARAM wParam, LPARAM lParam)
780 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
781 NMHDR *nmhdr;
783 switch(uMessage)
785 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
786 case WM_SIZE: return resize_namespacetree(This);
787 case WM_DESTROY: return destroy_namespacetree(This);
788 case WM_NOTIFY:
789 nmhdr = (NMHDR*)lParam;
790 switch(nmhdr->code)
792 case NM_CLICK: return on_nm_click(This, nmhdr);
793 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
794 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
795 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
796 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
797 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
798 default: break;
800 break;
801 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
803 return 0;
806 /**************************************************************************
807 * INameSpaceTreeControl2 Implementation
809 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
810 REFIID riid,
811 void **ppvObject)
813 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
814 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
816 *ppvObject = NULL;
817 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
818 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
819 IsEqualIID(riid, &IID_IUnknown))
821 *ppvObject = &This->INameSpaceTreeControl2_iface;
823 else if(IsEqualIID(riid, &IID_IOleWindow))
825 *ppvObject = &This->IOleWindow_iface;
828 if(*ppvObject)
830 IUnknown_AddRef((IUnknown*)*ppvObject);
831 return S_OK;
834 return E_NOINTERFACE;
837 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
839 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
840 LONG ref = InterlockedIncrement(&This->ref);
842 TRACE("%p - ref %d\n", This, ref);
844 return ref;
847 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
849 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
850 LONG ref = InterlockedDecrement(&This->ref);
852 TRACE("%p - ref: %d\n", This, ref);
854 if(!ref)
856 TRACE("Freeing.\n");
857 HeapFree(GetProcessHeap(), 0, This);
858 EFRAME_UnlockModule();
859 return 0;
862 return ref;
865 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
866 HWND hwndParent,
867 RECT *prc,
868 NSTCSTYLE nstcsFlags)
870 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
871 WNDCLASSW wc;
872 DWORD window_style, window_ex_style;
873 INITCOMMONCONTROLSEX icex;
874 RECT rc;
875 static const WCHAR NSTC2_CLASS_NAME[] =
876 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
877 'C','o','n','t','r','o','l',0};
879 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
881 if(nstcsFlags & unsupported_styles)
882 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
883 nstcsFlags, nstcsFlags & unsupported_styles);
885 This->style = nstcsFlags;
887 icex.dwSize = sizeof( icex );
888 icex.dwICC = ICC_TREEVIEW_CLASSES;
889 InitCommonControlsEx( &icex );
891 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
893 wc.style = CS_HREDRAW | CS_VREDRAW;
894 wc.lpfnWndProc = NSTC2_WndProc;
895 wc.cbClsExtra = 0;
896 wc.cbWndExtra = 0;
897 wc.hInstance = explorerframe_hinstance;
898 wc.hIcon = 0;
899 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
900 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
901 wc.lpszMenuName = NULL;
902 wc.lpszClassName = NSTC2_CLASS_NAME;
904 if (!RegisterClassW(&wc)) return E_FAIL;
907 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
908 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
909 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
910 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
912 if(prc)
913 CopyRect(&rc, prc);
914 else
915 rc.left = rc.right = rc.top = rc.bottom = 0;
917 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
918 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
919 hwndParent, 0, explorerframe_hinstance, This);
921 if(!This->hwnd_main)
923 ERR("Failed to create the window.\n");
924 return HRESULT_FROM_WIN32(GetLastError());
927 return S_OK;
930 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, IUnknown *handler, DWORD *cookie)
932 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
934 TRACE("%p (%p, %p)\n", This, handler, cookie);
936 *cookie = 0;
938 /* Only one client supported */
939 if (This->events || This->customdraw || This->dragdrop)
940 return E_FAIL;
942 /* FIXME: request INameSpaceTreeAccessible too */
943 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlEvents, (void**)&This->events);
944 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlCustomDraw, (void**)&This->customdraw);
945 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlDropHandler, (void**)&This->dragdrop);
947 if (This->events || This->customdraw || This->dragdrop)
948 *cookie = 1;
950 return *cookie ? S_OK : E_FAIL;
953 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, DWORD cookie)
955 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
957 TRACE("%p (%x)\n", This, cookie);
959 /* The cookie is ignored. */
961 if (This->events)
963 INameSpaceTreeControlEvents_Release(This->events);
964 This->events = NULL;
967 if (This->customdraw)
969 INameSpaceTreeControlCustomDraw_Release(This->customdraw);
970 This->customdraw = NULL;
973 if (This->dragdrop)
975 INameSpaceTreeControlDropHandler_Release(This->dragdrop);
976 This->dragdrop = NULL;
979 return S_OK;
982 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
983 int iIndex,
984 IShellItem *psiRoot,
985 SHCONTF grfEnumFlags,
986 NSTCROOTSTYLE grfRootStyle,
987 IShellItemFilter *pif)
989 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
990 nstc_root *new_root;
991 struct list *add_after_entry;
992 HTREEITEM add_after_hitem;
993 int i;
995 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
997 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
998 if(!new_root)
999 return E_OUTOFMEMORY;
1001 new_root->psi = psiRoot;
1002 new_root->enum_flags = grfEnumFlags;
1003 new_root->root_style = grfRootStyle;
1004 new_root->pif = pif;
1006 /* We want to keep the roots in the internal list and in the
1007 * treeview in the same order. */
1008 add_after_entry = &This->roots;
1009 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
1010 add_after_entry = list_next(&This->roots, add_after_entry);
1012 if(add_after_entry == &This->roots)
1013 add_after_hitem = TVI_FIRST;
1014 else
1015 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1017 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1018 if(!new_root->htreeitem)
1020 WARN("Failed to add the root.\n");
1021 HeapFree(GetProcessHeap(), 0, new_root);
1022 return E_FAIL;
1025 list_add_after(add_after_entry, &new_root->entry);
1026 events_OnItemAdded(This, psiRoot, TRUE);
1028 if(grfRootStyle & NSTCRS_HIDDEN)
1030 TVITEMEXW tvi;
1031 tvi.mask = TVIF_STATEEX;
1032 tvi.uStateEx = TVIS_EX_FLAT;
1033 tvi.hItem = new_root->htreeitem;
1035 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1038 if(grfRootStyle & NSTCRS_EXPANDED)
1039 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1040 (LPARAM)new_root->htreeitem);
1042 return S_OK;
1045 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1046 IShellItem *psiRoot,
1047 SHCONTF grfEnumFlags,
1048 NSTCROOTSTYLE grfRootStyle,
1049 IShellItemFilter *pif)
1051 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1052 UINT root_count;
1053 TRACE("%p, %p, %x, %x, %p\n",
1054 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1056 root_count = list_count(&This->roots);
1058 return INameSpaceTreeControl2_InsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1061 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1062 IShellItem *psiRoot)
1064 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1065 nstc_root *cursor, *root = NULL;
1066 TRACE("%p (%p)\n", This, psiRoot);
1068 if(!psiRoot)
1069 return E_NOINTERFACE;
1071 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1073 HRESULT hr;
1074 int order;
1075 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1076 if(hr == S_OK)
1078 root = cursor;
1079 break;
1083 TRACE("root %p\n", root);
1084 if(root)
1086 events_OnItemDeleted(This, root->psi, TRUE);
1087 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1088 list_remove(&root->entry);
1089 HeapFree(GetProcessHeap(), 0, root);
1090 return S_OK;
1092 else
1094 WARN("No matching root found.\n");
1095 return E_FAIL;
1099 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1101 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1102 nstc_root *cur1, *cur2;
1104 TRACE("%p\n", This);
1106 if (list_empty(&This->roots))
1107 return E_INVALIDARG;
1109 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1110 INameSpaceTreeControl2_RemoveRoot(iface, cur1->psi);
1112 return S_OK;
1115 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1116 IShellItemArray **ppsiaRootItems)
1118 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1119 IShellFolder *psf;
1120 LPITEMIDLIST *array;
1121 nstc_root *root;
1122 UINT count, i;
1123 HRESULT hr;
1124 TRACE("%p (%p)\n", This, ppsiaRootItems);
1126 count = list_count(&This->roots);
1128 if(!count)
1129 return E_INVALIDARG;
1131 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST)*count);
1133 i = 0;
1134 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1135 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1137 SHGetDesktopFolder(&psf);
1138 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1139 ppsiaRootItems);
1140 IShellFolder_Release(psf);
1142 for(i = 0; i < count; i++)
1143 ILFree(array[i]);
1145 HeapFree(GetProcessHeap(), 0, array);
1147 return hr;
1150 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1151 IShellItem *psi,
1152 NSTCITEMSTATE nstcisMask,
1153 NSTCITEMSTATE nstcisFlags)
1155 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1156 TVITEMEXW tvi;
1157 HTREEITEM hitem;
1159 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1161 hitem = treeitem_from_shellitem(This, psi);
1162 if(!hitem) return E_INVALIDARG;
1164 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1165 in two TVM_SETITEMW's */
1166 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1168 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1169 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1171 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1173 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1176 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1177 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1179 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1180 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1183 if(nstcisMask & NSTCIS_DISABLED)
1184 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1185 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1186 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1187 (nstcisFlags & NSTCIS_DISABLED) )
1188 tvi.mask = TVIF_STATE;
1189 else
1190 tvi.mask = 0;
1192 if(tvi.mask)
1194 tvi.stateMask = tvi.state = 0;
1195 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1196 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1197 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1199 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1201 tvi.stateMask = 0;
1204 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1205 tvi.hItem = hitem;
1207 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1210 return S_OK;
1213 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1214 IShellItem *psi,
1215 NSTCITEMSTATE nstcisMask,
1216 NSTCITEMSTATE *pnstcisFlags)
1218 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1219 HTREEITEM hitem;
1220 TVITEMEXW tvi;
1221 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1223 hitem = treeitem_from_shellitem(This, psi);
1224 if(!hitem)
1225 return E_INVALIDARG;
1227 *pnstcisFlags = 0;
1229 tvi.hItem = hitem;
1230 tvi.mask = TVIF_STATE;
1231 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1233 if(nstcisMask & NSTCIS_DISABLED)
1234 tvi.mask |= TVIF_STATEEX;
1236 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1237 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1238 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1239 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1240 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1242 *pnstcisFlags &= nstcisMask;
1244 return S_OK;
1247 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1248 IShellItemArray **psiaItems)
1250 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1251 IShellItem *psiselected;
1253 TRACE("%p (%p)\n", This, psiaItems);
1255 psiselected = get_selected_shellitem(This);
1256 if(!psiselected)
1258 *psiaItems = NULL;
1259 return E_FAIL;
1262 return SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1263 (void**)psiaItems);
1266 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1267 IShellItem *psi,
1268 int *piStateNumber)
1270 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1271 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1272 return E_NOTIMPL;
1275 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1276 IShellItem *psi,
1277 int iStateNumber)
1279 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1280 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1281 return E_NOTIMPL;
1284 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1285 IShellItem *psi)
1287 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1288 HTREEITEM hitem;
1290 TRACE("%p (%p)\n", This, psi);
1292 hitem = treeitem_from_shellitem(This, psi);
1293 if(hitem)
1295 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1296 return S_OK;
1299 return E_INVALIDARG;
1302 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1303 LPCWSTR pszTheme)
1305 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1306 FIXME("stub, %p (%p)\n", This, pszTheme);
1307 return E_NOTIMPL;
1310 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1311 IShellItem *psi,
1312 NSTCGNI nstcgi,
1313 IShellItem **ppsiNext)
1315 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1316 HTREEITEM hitem, hnext;
1317 UINT tvgn;
1318 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1320 if(!ppsiNext) return E_POINTER;
1321 if(!psi) return E_FAIL;
1323 *ppsiNext = NULL;
1325 hitem = treeitem_from_shellitem(This, psi);
1326 if(!hitem)
1327 return E_INVALIDARG;
1329 switch(nstcgi)
1331 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1332 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1333 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1334 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1335 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1336 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1337 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1338 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1339 default:
1340 FIXME("Unknown nstcgi value %d\n", nstcgi);
1341 return E_FAIL;
1344 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1345 if(hnext)
1347 *ppsiNext = shellitem_from_treeitem(This, hnext);
1348 IShellItem_AddRef(*ppsiNext);
1349 return S_OK;
1352 return E_FAIL;
1355 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1356 POINT *ppt,
1357 IShellItem **ppsiOut)
1359 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1360 HTREEITEM hitem;
1361 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1363 if(!ppt || !ppsiOut)
1364 return E_POINTER;
1366 *ppsiOut = NULL;
1368 hitem = treeitem_from_point(This, ppt, NULL);
1369 if(hitem)
1370 *ppsiOut = shellitem_from_treeitem(This, hitem);
1372 if(*ppsiOut)
1374 IShellItem_AddRef(*ppsiOut);
1375 return S_OK;
1378 return S_FALSE;
1381 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1382 IShellItem *psi,
1383 RECT *prect)
1385 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1386 HTREEITEM hitem;
1387 TRACE("%p (%p, %p)\n", This, psi, prect);
1389 if(!psi || !prect)
1390 return E_POINTER;
1392 hitem = treeitem_from_shellitem(This, psi);
1393 if(hitem)
1395 *(HTREEITEM*)prect = hitem;
1396 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1398 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1399 return S_OK;
1403 return E_INVALIDARG;
1406 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1408 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1409 nstc_root *root;
1410 TRACE("%p\n", This);
1412 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1413 collapse_all(This, root->htreeitem);
1415 return S_OK;
1418 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1419 NSTCSTYLE nstcsMask,
1420 NSTCSTYLE nstcsStyle)
1422 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1423 static const DWORD tv_style_flags =
1424 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1425 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1426 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1427 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1428 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1429 static const DWORD nstc_flags =
1430 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1431 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1432 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1433 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1435 /* Fail if there is an attempt to set an unknown style. */
1436 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1437 return E_FAIL;
1439 if(nstcsMask & tv_style_flags)
1441 DWORD new_style;
1442 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1443 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1446 /* Flags affecting the host window */
1447 if(nstcsMask & NSTCS_BORDER)
1449 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1450 new_style &= ~WS_BORDER;
1451 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1452 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1454 if(nstcsMask & NSTCS_TABSTOP)
1456 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1457 new_style &= ~WS_EX_CONTROLPARENT;
1458 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1459 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1462 if((nstcsStyle & nstcsMask) & unsupported_styles)
1463 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1464 (nstcsStyle & nstcsMask),
1465 (nstcsStyle & nstcsMask) & unsupported_styles);
1467 This->style &= ~nstcsMask;
1468 This->style |= (nstcsStyle & nstcsMask);
1470 return S_OK;
1473 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1474 NSTCSTYLE nstcsMask,
1475 NSTCSTYLE *pnstcsStyle)
1477 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1478 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1480 *pnstcsStyle = (This->style & nstcsMask);
1482 return S_OK;
1485 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1486 NSTCSTYLE2 nstcsMask,
1487 NSTCSTYLE2 nstcsStyle)
1489 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1490 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1492 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1493 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1494 (nstcsStyle & nstcsMask),
1495 (nstcsStyle & nstcsMask) & unsupported_styles2);
1497 This->style2 &= ~nstcsMask;
1498 This->style2 |= (nstcsStyle & nstcsMask);
1500 return S_OK;
1503 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1504 NSTCSTYLE2 nstcsMask,
1505 NSTCSTYLE2 *pnstcsStyle)
1507 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1508 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1510 *pnstcsStyle = (This->style2 & nstcsMask);
1512 return S_OK;
1515 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1516 NSTC2_fnQueryInterface,
1517 NSTC2_fnAddRef,
1518 NSTC2_fnRelease,
1519 NSTC2_fnInitialize,
1520 NSTC2_fnTreeAdvise,
1521 NSTC2_fnTreeUnadvise,
1522 NSTC2_fnAppendRoot,
1523 NSTC2_fnInsertRoot,
1524 NSTC2_fnRemoveRoot,
1525 NSTC2_fnRemoveAllRoots,
1526 NSTC2_fnGetRootItems,
1527 NSTC2_fnSetItemState,
1528 NSTC2_fnGetItemState,
1529 NSTC2_fnGetSelectedItems,
1530 NSTC2_fnGetItemCustomState,
1531 NSTC2_fnSetItemCustomState,
1532 NSTC2_fnEnsureItemVisible,
1533 NSTC2_fnSetTheme,
1534 NSTC2_fnGetNextItem,
1535 NSTC2_fnHitTest,
1536 NSTC2_fnGetItemRect,
1537 NSTC2_fnCollapseAll,
1538 NSTC2_fnSetControlStyle,
1539 NSTC2_fnGetControlStyle,
1540 NSTC2_fnSetControlStyle2,
1541 NSTC2_fnGetControlStyle2
1544 /**************************************************************************
1545 * IOleWindow Implementation
1548 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1550 NSTC2Impl *This = impl_from_IOleWindow(iface);
1551 return INameSpaceTreeControl2_QueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1554 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1556 NSTC2Impl *This = impl_from_IOleWindow(iface);
1557 return INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
1560 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1562 NSTC2Impl *This = impl_from_IOleWindow(iface);
1563 return INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
1566 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1568 NSTC2Impl *This = impl_from_IOleWindow(iface);
1569 TRACE("%p (%p)\n", This, phwnd);
1571 *phwnd = This->hwnd_main;
1572 return S_OK;
1575 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1577 NSTC2Impl *This = impl_from_IOleWindow(iface);
1578 TRACE("%p (%d)\n", This, fEnterMode);
1580 /* Not implemented */
1581 return E_NOTIMPL;
1584 static const IOleWindowVtbl vt_IOleWindow = {
1585 IOW_fnQueryInterface,
1586 IOW_fnAddRef,
1587 IOW_fnRelease,
1588 IOW_fnGetWindow,
1589 IOW_fnContextSensitiveHelp
1592 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1594 NSTC2Impl *nstc;
1595 HRESULT ret;
1597 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1599 if(!ppv)
1600 return E_POINTER;
1601 if(pUnkOuter)
1602 return CLASS_E_NOAGGREGATION;
1604 EFRAME_LockModule();
1606 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1607 if (!nstc)
1608 return E_OUTOFMEMORY;
1610 nstc->ref = 1;
1611 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1612 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1614 list_init(&nstc->roots);
1616 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1617 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1619 TRACE("--(%p)\n", ppv);
1620 return ret;