kernelbase: Add QuirkIsEnabled3 stub.
[wine.git] / dlls / explorerframe / nstc.c
bloba2ab974058991db8fcff24c1a39a2fe33b3d81fb
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 const WCHAR thispropW[] = {'P','R','O','P','_','T','H','I','S',0};
77 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
79 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
82 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
84 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
87 /* Forward declarations */
88 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
90 /*************************************************************************
91 * NamespaceTree event wrappers
93 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
94 int *piDefaultIcon, int *piOpenIcon)
96 HRESULT ret;
97 LONG refcount;
98 if(!This->events) return E_NOTIMPL;
100 refcount = IShellItem_AddRef(psi);
101 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->events, psi, piDefaultIcon, piOpenIcon);
102 if(IShellItem_Release(psi) < refcount - 1)
103 ERR("ShellItem was released by client - please file a bug.\n");
104 return ret;
107 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
109 HRESULT ret;
110 LONG refcount;
111 if(!This->events) return S_OK;
113 refcount = IShellItem_AddRef(psi);
114 ret = INameSpaceTreeControlEvents_OnItemAdded(This->events, psi, fIsRoot);
115 if(IShellItem_Release(psi) < refcount - 1)
116 ERR("ShellItem was released by client - please file a bug.\n");
117 return ret;
120 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
122 HRESULT ret;
123 LONG refcount;
124 if(!This->events) return S_OK;
126 refcount = IShellItem_AddRef(psi);
127 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->events, psi, fIsRoot);
128 if(IShellItem_Release(psi) < refcount - 1)
129 ERR("ShellItem was released by client - please file a bug.\n");
130 return ret;
133 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
135 HRESULT ret;
136 LONG refcount;
137 if(!This->events) return S_OK;
139 refcount = IShellItem_AddRef(psi);
140 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->events, psi);
141 if(IShellItem_Release(psi) < refcount - 1)
142 ERR("ShellItem was released by client - please file a bug.\n");
143 return ret;
146 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
148 HRESULT ret;
149 LONG refcount;
150 if(!This->events) return S_OK;
152 refcount = IShellItem_AddRef(psi);
153 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->events, psi);
154 if(IShellItem_Release(psi) < refcount - 1)
155 ERR("ShellItem was released by client - please file a bug.\n");
156 return ret;
159 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
160 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
162 HRESULT ret;
163 LONG refcount;
164 if(!This->events) return S_OK;
166 refcount = IShellItem_AddRef(psi);
167 ret = INameSpaceTreeControlEvents_OnItemClick(This->events, psi, nstceHitTest, nstceClickType);
168 if(IShellItem_Release(psi) < refcount - 1)
169 ERR("ShellItem was released by client - please file a bug.\n");
170 return ret;
173 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
175 if(!This->events) return S_OK;
177 return INameSpaceTreeControlEvents_OnSelectionChanged(This->events, psia);
180 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
182 if(!This->events) return S_OK;
184 return INameSpaceTreeControlEvents_OnKeyboardInput(This->events, uMsg, wParam, lParam);
187 /*************************************************************************
188 * NamespaceTree helper functions
190 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
191 NSTCSTYLE nstcs_mask, DWORD *new_style)
193 DWORD old_style, tv_mask = 0;
194 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
196 if(This->hwnd_tv)
197 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
198 else
199 old_style = /* The default */
200 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
201 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
202 TVS_EDITLABELS | TVS_TRACKSELECT;
204 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
205 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
206 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
207 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
208 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
209 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
210 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
211 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
212 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
213 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
214 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
216 *new_style = 0;
218 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
219 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
220 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
221 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
222 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
223 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
224 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
225 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
226 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
227 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
228 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
230 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
232 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
234 return old_style^*new_style;
237 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
239 TVITEMEXW tvi;
241 tvi.mask = TVIF_PARAM;
242 tvi.lParam = 0;
243 tvi.hItem = hitem;
245 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
247 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
248 return (IShellItem*)tvi.lParam;
251 /* Returns the root that the given treeitem belongs to. */
252 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
254 HTREEITEM tmp, hroot = hitem;
255 nstc_root *root;
257 /* Work our way up the hierarchy */
258 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
259 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
261 /* Search through the list of roots for a match */
262 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
263 if(root->htreeitem == hroot)
264 break;
266 TRACE("root is %p\n", root);
267 return root;
270 /* Find a shellitem in the tree, starting from the given node. */
271 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
272 IShellItem *psi)
274 IShellItem *psi_node;
275 HTREEITEM next, result = NULL;
276 HRESULT hr;
277 int cmpo;
278 TRACE("%p, %p, %p\n", This, node, psi);
280 /* Check this node */
281 psi_node = shellitem_from_treeitem(This, node);
282 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
283 if(hr == S_OK)
284 return node;
286 /* Any children? */
287 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
288 TVGN_CHILD, (LPARAM)node);
289 if(next)
291 result = search_for_shellitem(This, next, psi);
292 if(result) return result;
295 /* Try our next sibling. */
296 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
297 TVGN_NEXT, (LPARAM)node);
298 if(next)
299 result = search_for_shellitem(This, next, psi);
301 return result;
304 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
306 HTREEITEM root;
307 TRACE("%p, %p\n", This, psi);
309 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
310 TVGN_ROOT, 0);
311 if(!root)
312 return NULL;
314 return search_for_shellitem(This, root, psi);
317 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
319 SHFILEINFOW sfi;
320 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
321 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
322 return sfi.iIcon;
325 /* Insert a shellitem into the given place in the tree and return the
326 resulting treeitem. */
327 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
328 HTREEITEM hParent, HTREEITEM hInsertAfter)
330 TVINSERTSTRUCTW tvins;
331 TVITEMEXW *tvi = &tvins.u.itemex;
332 HTREEITEM hinserted;
333 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
335 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
336 tvi->cChildren = I_CHILDRENCALLBACK;
337 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
338 tvi->pszText = LPSTR_TEXTCALLBACKW;
340 /* Every treeitem contains a pointer to the corresponding ShellItem. */
341 tvi->lParam = (LPARAM)psi;
342 tvins.hParent = hParent;
343 tvins.hInsertAfter = hInsertAfter;
345 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
346 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
347 if(hinserted)
348 IShellItem_AddRef(psi);
350 return hinserted;
353 /* Enumerates the children of the folder represented by hitem
354 * according to the settings for the root, and adds them to the
355 * treeview. Returns the number of children added. */
356 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
358 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
359 nstc_root *root = root_for_treeitem(This, hitem);
360 LPITEMIDLIST pidl_parent;
361 IShellFolder *psf;
362 IEnumIDList *peidl;
363 UINT added = 0;
364 HRESULT hr;
366 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
367 if(SUCCEEDED(hr))
369 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
370 if(SUCCEEDED(hr))
372 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
373 if(SUCCEEDED(hr))
375 LPITEMIDLIST pidl;
376 IShellItem *psi;
377 ULONG fetched;
379 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
381 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
382 ILFree(pidl);
383 if(SUCCEEDED(hr))
385 if(insert_shellitem(This, psi, hitem, NULL))
387 events_OnItemAdded(This, psi, FALSE);
388 added++;
391 IShellItem_Release(psi);
393 else
394 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
396 IEnumIDList_Release(peidl);
398 else
399 ERR("EnumObjects failed with 0x%08x\n", hr);
401 IShellFolder_Release(psf);
403 else
404 ERR("BindToHandler failed with 0x%08x\n", hr);
406 ILFree(pidl_parent);
408 else
409 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
411 return added;
414 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
416 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
419 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
421 return shellitem_from_treeitem(This, get_selected_treeitem(This));
424 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
426 HTREEITEM next;
428 /* Collapse this node first, and then first child/next sibling. */
429 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
431 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
432 if(next) collapse_all(This, next);
434 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
435 if(next) collapse_all(This, next);
438 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
440 TVHITTESTINFO tviht;
441 tviht.pt.x = pt->x;
442 tviht.pt.y = pt->y;
443 tviht.hItem = NULL;
445 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
446 if(hitflag) *hitflag = tviht.flags;
447 return tviht.hItem;
450 /*************************************************************************
451 * NamespaceTree window functions
453 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
455 NSTC2Impl *This = crs->lpCreateParams;
456 HIMAGELIST ShellSmallIconList;
457 DWORD treeview_style, treeview_ex_style;
459 TRACE("%p (%p)\n", This, crs);
460 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
461 This->hwnd_main = hWnd;
463 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
465 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
466 0, 0, crs->cx, crs->cy,
467 hWnd, NULL, explorerframe_hinstance, NULL);
469 if(!This->hwnd_tv)
471 ERR("Failed to create treeview!\n");
472 return HRESULT_FROM_WIN32(GetLastError());
475 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
476 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
478 if(This->style & NSTCS_AUTOHSCROLL)
479 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
480 if(This->style & NSTCS_FADEINOUTEXPANDOS)
481 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
482 if(This->style & NSTCS_PARTIALCHECKBOXES)
483 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
484 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
485 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
486 if(This->style & NSTCS_DIMMEDCHECKBOXES)
487 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
489 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
491 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
493 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
494 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
496 else
498 ERR("Failed to get the System Image List.\n");
501 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
503 /* Subclass the treeview to get the keyboard events. */
504 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
505 (ULONG_PTR)tv_wndproc);
506 if(This->tv_oldwndproc)
507 SetPropW(This->hwnd_tv, thispropW, This);
509 return TRUE;
512 static LRESULT resize_namespacetree(NSTC2Impl *This)
514 RECT rc;
515 TRACE("%p\n", This);
517 GetClientRect(This->hwnd_main, &rc);
518 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
520 return TRUE;
523 static LRESULT destroy_namespacetree(NSTC2Impl *This)
525 TRACE("%p\n", This);
527 /* Undo the subclassing */
528 if(This->tv_oldwndproc)
530 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
531 RemovePropW(This->hwnd_tv, thispropW);
534 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
536 /* This reference was added in create_namespacetree */
537 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
538 return TRUE;
541 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
543 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
544 TRACE("%p\n", This);
546 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
547 return TRUE;
550 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
552 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
553 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
554 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
555 HRESULT hr;
557 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
559 if(item->mask & TVIF_CHILDREN)
561 SFGAOF sfgao;
563 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
564 if(SUCCEEDED(hr))
565 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
566 else
567 item->cChildren = 1;
569 item->mask |= TVIF_DI_SETITEM;
572 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
574 LPITEMIDLIST pidl;
576 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
577 if(FAILED(hr))
579 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
580 if(SUCCEEDED(hr))
582 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
583 item->mask |= TVIF_DI_SETITEM;
584 ILFree(pidl);
586 else
587 ERR("Failed to get IDList (%08x).\n", hr);
591 if(item->mask & TVIF_TEXT)
593 LPWSTR display_name;
595 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
596 if(SUCCEEDED(hr))
598 lstrcpynW(item->pszText, display_name, MAX_PATH);
599 item->mask |= TVIF_DI_SETITEM;
600 CoTaskMemFree(display_name);
602 else
603 ERR("Failed to get display name (%08x).\n", hr);
606 return TRUE;
609 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
611 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
614 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
616 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
617 IShellItem *psi;
618 TRACE("%p\n", This);
620 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
621 events_OnBeforeExpand(This, psi);
623 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
625 /* The node has no children, try to find some */
626 if(!fill_sublevel(This, nmtv->itemNew.hItem))
628 TVITEMEXW tvi;
629 /* Failed to enumerate any children, remove the expando
630 * (if any). */
631 tvi.hItem = nmtv->itemNew.hItem;
632 tvi.mask = TVIF_CHILDREN;
633 tvi.cChildren = 0;
634 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
636 return TRUE;
639 return FALSE;
642 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
644 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
645 IShellItem *psi;
646 TRACE("%p\n", This);
648 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
649 events_OnAfterExpand(This, psi);
650 return TRUE;
653 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
655 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
656 IShellItemArray *psia;
657 IShellItem *psi;
658 HRESULT hr;
659 TRACE("%p\n", This);
661 /* Note: Only supports one selected item. */
662 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
663 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
664 if(SUCCEEDED(hr))
666 events_OnSelectionChanged(This, psia);
667 IShellItemArray_Release(psia);
670 return TRUE;
673 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
675 TVHITTESTINFO tvhit;
676 IShellItem *psi;
677 HRESULT hr;
678 TRACE("%p (%p)\n", This, nmhdr);
680 GetCursorPos(&tvhit.pt);
681 ScreenToClient(This->hwnd_tv, &tvhit.pt);
682 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
684 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
685 return TRUE;
687 /* TVHT_ maps onto the corresponding NSTCEHT_ */
688 psi = shellitem_from_treeitem(This, tvhit.hItem);
689 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
691 /* The expando should not be expanded unless
692 * double-clicked. */
693 if(tvhit.flags == TVHT_ONITEMBUTTON)
694 return TRUE;
696 if(SUCCEEDED(hr))
697 return FALSE;
698 else
699 return TRUE;
702 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
704 TVHITTESTINFO tvhit;
705 IShellItem *psi;
706 HRESULT hr;
707 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
709 tvhit.pt.x = (int)(short)LOWORD(lParam);
710 tvhit.pt.y = (int)(short)HIWORD(lParam);
712 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
714 /* Seems to generate only ONITEM and ONITEMICON */
715 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
716 return FALSE;
718 psi = shellitem_from_treeitem(This, tvhit.hItem);
719 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
721 if(SUCCEEDED(hr))
722 return FALSE;
723 else
724 return TRUE;
727 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
729 IShellItem *psi;
730 HTREEITEM hitem;
731 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
733 /* Handled by the client? */
734 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
735 return TRUE;
737 if(uMsg == WM_KEYDOWN)
739 switch(wParam)
741 case VK_DELETE:
742 psi = get_selected_shellitem(This);
743 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
744 return TRUE;
746 case VK_F2:
747 hitem = get_selected_treeitem(This);
748 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
749 return TRUE;
753 /* Let the TreeView handle the key */
754 return FALSE;
757 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
759 NSTC2Impl *This = (NSTC2Impl*)GetPropW(hWnd, thispropW);
761 switch(uMessage) {
762 case WM_KEYDOWN:
763 case WM_KEYUP:
764 case WM_CHAR:
765 case WM_SYSKEYDOWN:
766 case WM_SYSKEYUP:
767 case WM_SYSCHAR:
768 if(on_kbd_event(This, uMessage, wParam, lParam))
769 return TRUE;
770 break;
772 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
775 /* Pass the message on to the treeview */
776 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
779 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
780 WPARAM wParam, LPARAM lParam)
782 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
783 NMHDR *nmhdr;
785 switch(uMessage)
787 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
788 case WM_SIZE: return resize_namespacetree(This);
789 case WM_DESTROY: return destroy_namespacetree(This);
790 case WM_NOTIFY:
791 nmhdr = (NMHDR*)lParam;
792 switch(nmhdr->code)
794 case NM_CLICK: return on_nm_click(This, nmhdr);
795 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
796 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
797 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
798 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
799 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
800 default: break;
802 break;
803 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
805 return 0;
808 /**************************************************************************
809 * INameSpaceTreeControl2 Implementation
811 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
812 REFIID riid,
813 void **ppvObject)
815 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
816 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
818 *ppvObject = NULL;
819 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
820 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
821 IsEqualIID(riid, &IID_IUnknown))
823 *ppvObject = &This->INameSpaceTreeControl2_iface;
825 else if(IsEqualIID(riid, &IID_IOleWindow))
827 *ppvObject = &This->IOleWindow_iface;
830 if(*ppvObject)
832 IUnknown_AddRef((IUnknown*)*ppvObject);
833 return S_OK;
836 return E_NOINTERFACE;
839 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
841 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
842 LONG ref = InterlockedIncrement(&This->ref);
844 TRACE("%p - ref %d\n", This, ref);
846 return ref;
849 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
851 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
852 LONG ref = InterlockedDecrement(&This->ref);
854 TRACE("%p - ref: %d\n", This, ref);
856 if(!ref)
858 TRACE("Freeing.\n");
859 HeapFree(GetProcessHeap(), 0, This);
860 EFRAME_UnlockModule();
861 return 0;
864 return ref;
867 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
868 HWND hwndParent,
869 RECT *prc,
870 NSTCSTYLE nstcsFlags)
872 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
873 WNDCLASSW wc;
874 DWORD window_style, window_ex_style;
875 INITCOMMONCONTROLSEX icex;
876 RECT rc;
877 static const WCHAR NSTC2_CLASS_NAME[] =
878 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
879 'C','o','n','t','r','o','l',0};
881 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
883 if(nstcsFlags & unsupported_styles)
884 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
885 nstcsFlags, nstcsFlags & unsupported_styles);
887 This->style = nstcsFlags;
889 icex.dwSize = sizeof( icex );
890 icex.dwICC = ICC_TREEVIEW_CLASSES;
891 InitCommonControlsEx( &icex );
893 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
895 wc.style = CS_HREDRAW | CS_VREDRAW;
896 wc.lpfnWndProc = NSTC2_WndProc;
897 wc.cbClsExtra = 0;
898 wc.cbWndExtra = 0;
899 wc.hInstance = explorerframe_hinstance;
900 wc.hIcon = 0;
901 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
902 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
903 wc.lpszMenuName = NULL;
904 wc.lpszClassName = NSTC2_CLASS_NAME;
906 if (!RegisterClassW(&wc)) return E_FAIL;
909 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
910 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
911 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
912 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
914 if(prc)
915 rc = *prc;
916 else
917 SetRectEmpty(&rc);
919 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
920 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
921 hwndParent, 0, explorerframe_hinstance, This);
923 if(!This->hwnd_main)
925 ERR("Failed to create the window.\n");
926 return HRESULT_FROM_WIN32(GetLastError());
929 return S_OK;
932 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, IUnknown *handler, DWORD *cookie)
934 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
936 TRACE("%p (%p, %p)\n", This, handler, cookie);
938 *cookie = 0;
940 /* Only one client supported */
941 if (This->events || This->customdraw || This->dragdrop)
942 return E_FAIL;
944 /* FIXME: request INameSpaceTreeAccessible too */
945 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlEvents, (void**)&This->events);
946 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlCustomDraw, (void**)&This->customdraw);
947 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlDropHandler, (void**)&This->dragdrop);
949 if (This->events || This->customdraw || This->dragdrop)
950 *cookie = 1;
952 return *cookie ? S_OK : E_FAIL;
955 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, DWORD cookie)
957 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
959 TRACE("%p (%x)\n", This, cookie);
961 /* The cookie is ignored. */
963 if (This->events)
965 INameSpaceTreeControlEvents_Release(This->events);
966 This->events = NULL;
969 if (This->customdraw)
971 INameSpaceTreeControlCustomDraw_Release(This->customdraw);
972 This->customdraw = NULL;
975 if (This->dragdrop)
977 INameSpaceTreeControlDropHandler_Release(This->dragdrop);
978 This->dragdrop = NULL;
981 return S_OK;
984 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
985 int iIndex,
986 IShellItem *psiRoot,
987 SHCONTF grfEnumFlags,
988 NSTCROOTSTYLE grfRootStyle,
989 IShellItemFilter *pif)
991 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
992 nstc_root *new_root;
993 struct list *add_after_entry;
994 HTREEITEM add_after_hitem;
995 int i;
997 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
999 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
1000 if(!new_root)
1001 return E_OUTOFMEMORY;
1003 new_root->psi = psiRoot;
1004 new_root->enum_flags = grfEnumFlags;
1005 new_root->root_style = grfRootStyle;
1006 new_root->pif = pif;
1008 /* We want to keep the roots in the internal list and in the
1009 * treeview in the same order. */
1010 add_after_entry = &This->roots;
1011 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
1012 add_after_entry = list_next(&This->roots, add_after_entry);
1014 if(add_after_entry == &This->roots)
1015 add_after_hitem = TVI_FIRST;
1016 else
1017 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1019 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1020 if(!new_root->htreeitem)
1022 WARN("Failed to add the root.\n");
1023 HeapFree(GetProcessHeap(), 0, new_root);
1024 return E_FAIL;
1027 list_add_after(add_after_entry, &new_root->entry);
1028 events_OnItemAdded(This, psiRoot, TRUE);
1030 if(grfRootStyle & NSTCRS_HIDDEN)
1032 TVITEMEXW tvi;
1033 tvi.mask = TVIF_STATEEX;
1034 tvi.uStateEx = TVIS_EX_FLAT;
1035 tvi.hItem = new_root->htreeitem;
1037 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1040 if(grfRootStyle & NSTCRS_EXPANDED)
1041 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1042 (LPARAM)new_root->htreeitem);
1044 return S_OK;
1047 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1048 IShellItem *psiRoot,
1049 SHCONTF grfEnumFlags,
1050 NSTCROOTSTYLE grfRootStyle,
1051 IShellItemFilter *pif)
1053 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1054 UINT root_count;
1055 TRACE("%p, %p, %x, %x, %p\n",
1056 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1058 root_count = list_count(&This->roots);
1060 return INameSpaceTreeControl2_InsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1063 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1064 IShellItem *psiRoot)
1066 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1067 nstc_root *cursor, *root = NULL;
1068 TRACE("%p (%p)\n", This, psiRoot);
1070 if(!psiRoot)
1071 return E_NOINTERFACE;
1073 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1075 HRESULT hr;
1076 int order;
1077 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1078 if(hr == S_OK)
1080 root = cursor;
1081 break;
1085 TRACE("root %p\n", root);
1086 if(root)
1088 events_OnItemDeleted(This, root->psi, TRUE);
1089 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1090 list_remove(&root->entry);
1091 HeapFree(GetProcessHeap(), 0, root);
1092 return S_OK;
1094 else
1096 WARN("No matching root found.\n");
1097 return E_FAIL;
1101 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1103 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1104 nstc_root *cur1, *cur2;
1106 TRACE("%p\n", This);
1108 if (list_empty(&This->roots))
1109 return E_INVALIDARG;
1111 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1112 INameSpaceTreeControl2_RemoveRoot(iface, cur1->psi);
1114 return S_OK;
1117 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1118 IShellItemArray **ppsiaRootItems)
1120 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1121 IShellFolder *psf;
1122 LPITEMIDLIST *array;
1123 nstc_root *root;
1124 UINT count, i;
1125 HRESULT hr;
1126 TRACE("%p (%p)\n", This, ppsiaRootItems);
1128 count = list_count(&This->roots);
1130 if(!count)
1131 return E_INVALIDARG;
1133 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST)*count);
1135 i = 0;
1136 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1137 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1139 SHGetDesktopFolder(&psf);
1140 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1141 ppsiaRootItems);
1142 IShellFolder_Release(psf);
1144 for(i = 0; i < count; i++)
1145 ILFree(array[i]);
1147 HeapFree(GetProcessHeap(), 0, array);
1149 return hr;
1152 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1153 IShellItem *psi,
1154 NSTCITEMSTATE nstcisMask,
1155 NSTCITEMSTATE nstcisFlags)
1157 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1158 TVITEMEXW tvi;
1159 HTREEITEM hitem;
1161 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1163 hitem = treeitem_from_shellitem(This, psi);
1164 if(!hitem) return E_INVALIDARG;
1166 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1167 in two TVM_SETITEMW's */
1168 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1170 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1171 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1173 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1175 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1178 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1179 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1181 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1182 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1185 if(nstcisMask & NSTCIS_DISABLED)
1186 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1187 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1188 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1189 (nstcisFlags & NSTCIS_DISABLED) )
1190 tvi.mask = TVIF_STATE;
1191 else
1192 tvi.mask = 0;
1194 if(tvi.mask)
1196 tvi.stateMask = tvi.state = 0;
1197 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1198 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1199 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1201 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1203 tvi.stateMask = 0;
1206 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1207 tvi.hItem = hitem;
1209 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1212 return S_OK;
1215 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1216 IShellItem *psi,
1217 NSTCITEMSTATE nstcisMask,
1218 NSTCITEMSTATE *pnstcisFlags)
1220 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1221 HTREEITEM hitem;
1222 TVITEMEXW tvi;
1223 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1225 hitem = treeitem_from_shellitem(This, psi);
1226 if(!hitem)
1227 return E_INVALIDARG;
1229 *pnstcisFlags = 0;
1231 tvi.hItem = hitem;
1232 tvi.mask = TVIF_STATE;
1233 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1235 if(nstcisMask & NSTCIS_DISABLED)
1236 tvi.mask |= TVIF_STATEEX;
1238 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1239 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1240 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1241 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1242 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1244 *pnstcisFlags &= nstcisMask;
1246 return S_OK;
1249 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1250 IShellItemArray **psiaItems)
1252 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1253 IShellItem *psiselected;
1255 TRACE("%p (%p)\n", This, psiaItems);
1257 psiselected = get_selected_shellitem(This);
1258 if(!psiselected)
1260 *psiaItems = NULL;
1261 return E_FAIL;
1264 return SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1265 (void**)psiaItems);
1268 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1269 IShellItem *psi,
1270 int *piStateNumber)
1272 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1273 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1274 return E_NOTIMPL;
1277 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1278 IShellItem *psi,
1279 int iStateNumber)
1281 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1282 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1283 return E_NOTIMPL;
1286 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1287 IShellItem *psi)
1289 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1290 HTREEITEM hitem;
1292 TRACE("%p (%p)\n", This, psi);
1294 hitem = treeitem_from_shellitem(This, psi);
1295 if(hitem)
1297 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1298 return S_OK;
1301 return E_INVALIDARG;
1304 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1305 LPCWSTR pszTheme)
1307 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1308 FIXME("stub, %p (%p)\n", This, pszTheme);
1309 return E_NOTIMPL;
1312 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1313 IShellItem *psi,
1314 NSTCGNI nstcgi,
1315 IShellItem **ppsiNext)
1317 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1318 HTREEITEM hitem, hnext;
1319 UINT tvgn;
1320 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1322 if(!ppsiNext) return E_POINTER;
1323 if(!psi) return E_FAIL;
1325 *ppsiNext = NULL;
1327 hitem = treeitem_from_shellitem(This, psi);
1328 if(!hitem)
1329 return E_INVALIDARG;
1331 switch(nstcgi)
1333 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1334 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1335 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1336 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1337 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1338 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1339 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1340 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1341 default:
1342 FIXME("Unknown nstcgi value %d\n", nstcgi);
1343 return E_FAIL;
1346 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1347 if(hnext)
1349 *ppsiNext = shellitem_from_treeitem(This, hnext);
1350 IShellItem_AddRef(*ppsiNext);
1351 return S_OK;
1354 return E_FAIL;
1357 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1358 POINT *ppt,
1359 IShellItem **ppsiOut)
1361 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1362 HTREEITEM hitem;
1363 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1365 if(!ppt || !ppsiOut)
1366 return E_POINTER;
1368 *ppsiOut = NULL;
1370 hitem = treeitem_from_point(This, ppt, NULL);
1371 if(hitem)
1372 *ppsiOut = shellitem_from_treeitem(This, hitem);
1374 if(*ppsiOut)
1376 IShellItem_AddRef(*ppsiOut);
1377 return S_OK;
1380 return S_FALSE;
1383 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1384 IShellItem *psi,
1385 RECT *prect)
1387 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1388 HTREEITEM hitem;
1389 TRACE("%p (%p, %p)\n", This, psi, prect);
1391 if(!psi || !prect)
1392 return E_POINTER;
1394 hitem = treeitem_from_shellitem(This, psi);
1395 if(hitem)
1397 *(HTREEITEM*)prect = hitem;
1398 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1400 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1401 return S_OK;
1405 return E_INVALIDARG;
1408 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1410 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1411 nstc_root *root;
1412 TRACE("%p\n", This);
1414 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1415 collapse_all(This, root->htreeitem);
1417 return S_OK;
1420 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1421 NSTCSTYLE nstcsMask,
1422 NSTCSTYLE nstcsStyle)
1424 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1425 static const DWORD tv_style_flags =
1426 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1427 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1428 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1429 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1430 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1431 static const DWORD nstc_flags =
1432 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1433 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1434 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1435 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1437 /* Fail if there is an attempt to set an unknown style. */
1438 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1439 return E_FAIL;
1441 if(nstcsMask & tv_style_flags)
1443 DWORD new_style;
1444 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1445 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1448 /* Flags affecting the host window */
1449 if(nstcsMask & NSTCS_BORDER)
1451 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1452 new_style &= ~WS_BORDER;
1453 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1454 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1456 if(nstcsMask & NSTCS_TABSTOP)
1458 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1459 new_style &= ~WS_EX_CONTROLPARENT;
1460 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1461 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1464 if((nstcsStyle & nstcsMask) & unsupported_styles)
1465 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1466 (nstcsStyle & nstcsMask),
1467 (nstcsStyle & nstcsMask) & unsupported_styles);
1469 This->style &= ~nstcsMask;
1470 This->style |= (nstcsStyle & nstcsMask);
1472 return S_OK;
1475 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1476 NSTCSTYLE nstcsMask,
1477 NSTCSTYLE *pnstcsStyle)
1479 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1480 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1482 *pnstcsStyle = (This->style & nstcsMask);
1484 return S_OK;
1487 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1488 NSTCSTYLE2 nstcsMask,
1489 NSTCSTYLE2 nstcsStyle)
1491 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1492 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1494 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1495 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1496 (nstcsStyle & nstcsMask),
1497 (nstcsStyle & nstcsMask) & unsupported_styles2);
1499 This->style2 &= ~nstcsMask;
1500 This->style2 |= (nstcsStyle & nstcsMask);
1502 return S_OK;
1505 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1506 NSTCSTYLE2 nstcsMask,
1507 NSTCSTYLE2 *pnstcsStyle)
1509 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1510 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1512 *pnstcsStyle = (This->style2 & nstcsMask);
1514 return S_OK;
1517 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1518 NSTC2_fnQueryInterface,
1519 NSTC2_fnAddRef,
1520 NSTC2_fnRelease,
1521 NSTC2_fnInitialize,
1522 NSTC2_fnTreeAdvise,
1523 NSTC2_fnTreeUnadvise,
1524 NSTC2_fnAppendRoot,
1525 NSTC2_fnInsertRoot,
1526 NSTC2_fnRemoveRoot,
1527 NSTC2_fnRemoveAllRoots,
1528 NSTC2_fnGetRootItems,
1529 NSTC2_fnSetItemState,
1530 NSTC2_fnGetItemState,
1531 NSTC2_fnGetSelectedItems,
1532 NSTC2_fnGetItemCustomState,
1533 NSTC2_fnSetItemCustomState,
1534 NSTC2_fnEnsureItemVisible,
1535 NSTC2_fnSetTheme,
1536 NSTC2_fnGetNextItem,
1537 NSTC2_fnHitTest,
1538 NSTC2_fnGetItemRect,
1539 NSTC2_fnCollapseAll,
1540 NSTC2_fnSetControlStyle,
1541 NSTC2_fnGetControlStyle,
1542 NSTC2_fnSetControlStyle2,
1543 NSTC2_fnGetControlStyle2
1546 /**************************************************************************
1547 * IOleWindow Implementation
1550 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1552 NSTC2Impl *This = impl_from_IOleWindow(iface);
1553 return INameSpaceTreeControl2_QueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1556 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1558 NSTC2Impl *This = impl_from_IOleWindow(iface);
1559 return INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
1562 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1564 NSTC2Impl *This = impl_from_IOleWindow(iface);
1565 return INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
1568 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1570 NSTC2Impl *This = impl_from_IOleWindow(iface);
1571 TRACE("%p (%p)\n", This, phwnd);
1573 *phwnd = This->hwnd_main;
1574 return S_OK;
1577 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1579 NSTC2Impl *This = impl_from_IOleWindow(iface);
1580 TRACE("%p (%d)\n", This, fEnterMode);
1582 /* Not implemented */
1583 return E_NOTIMPL;
1586 static const IOleWindowVtbl vt_IOleWindow = {
1587 IOW_fnQueryInterface,
1588 IOW_fnAddRef,
1589 IOW_fnRelease,
1590 IOW_fnGetWindow,
1591 IOW_fnContextSensitiveHelp
1594 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1596 NSTC2Impl *nstc;
1597 HRESULT ret;
1599 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1601 if(!ppv)
1602 return E_POINTER;
1603 if(pUnkOuter)
1604 return CLASS_E_NOAGGREGATION;
1606 EFRAME_LockModule();
1608 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1609 if (!nstc)
1610 return E_OUTOFMEMORY;
1612 nstc->ref = 1;
1613 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1614 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1616 list_init(&nstc->roots);
1618 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1619 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1621 TRACE("--(%p)\n", ppv);
1622 return ret;