ntdll: Read correct sysfs entry for core information.
[wine.git] / dlls / explorerframe / nstc.c
blob37e1a553a4422bc5e4c71aec7f60f940c1f03237
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"
31 #include "commctrl.h"
32 #include "commoncontrols.h"
34 #include "wine/list.h"
35 #include "wine/debug.h"
36 #include "wine/heap.h"
38 #include "explorerframe_main.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
42 typedef struct nstc_root {
43 IShellItem *psi;
44 HTREEITEM htreeitem;
45 SHCONTF enum_flags;
46 NSTCROOTSTYLE root_style;
47 IShellItemFilter *pif;
48 struct list entry;
49 } nstc_root;
51 typedef struct {
52 INameSpaceTreeControl2 INameSpaceTreeControl2_iface;
53 IOleWindow IOleWindow_iface;
54 LONG ref;
56 HWND hwnd_main;
57 HWND hwnd_tv;
59 WNDPROC tv_oldwndproc;
61 NSTCSTYLE style;
62 NSTCSTYLE2 style2;
63 struct list roots;
65 INameSpaceTreeControlCustomDraw *customdraw;
66 INameSpaceTreeControlDropHandler *dragdrop;
67 INameSpaceTreeControlEvents *events;
68 } NSTC2Impl;
70 static const DWORD unsupported_styles =
71 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
72 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
73 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
74 static const DWORD unsupported_styles2 =
75 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
76 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
78 static const WCHAR thispropW[] = {'P','R','O','P','_','T','H','I','S',0};
80 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
82 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
85 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
87 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
90 /* Forward declarations */
91 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
93 /*************************************************************************
94 * NamespaceTree event wrappers
96 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
97 int *piDefaultIcon, int *piOpenIcon)
99 HRESULT ret;
100 LONG refcount;
101 if(!This->events) return E_NOTIMPL;
103 refcount = IShellItem_AddRef(psi);
104 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->events, psi, piDefaultIcon, piOpenIcon);
105 if(IShellItem_Release(psi) < refcount - 1)
106 ERR("ShellItem was released by client - please file a bug.\n");
107 return ret;
110 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
112 HRESULT ret;
113 LONG refcount;
114 if(!This->events) return S_OK;
116 refcount = IShellItem_AddRef(psi);
117 ret = INameSpaceTreeControlEvents_OnItemAdded(This->events, psi, fIsRoot);
118 if(IShellItem_Release(psi) < refcount - 1)
119 ERR("ShellItem was released by client - please file a bug.\n");
120 return ret;
123 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
125 HRESULT ret;
126 LONG refcount;
127 if(!This->events) return S_OK;
129 refcount = IShellItem_AddRef(psi);
130 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->events, psi, fIsRoot);
131 if(IShellItem_Release(psi) < refcount - 1)
132 ERR("ShellItem was released by client - please file a bug.\n");
133 return ret;
136 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
138 HRESULT ret;
139 LONG refcount;
140 if(!This->events) return S_OK;
142 refcount = IShellItem_AddRef(psi);
143 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->events, psi);
144 if(IShellItem_Release(psi) < refcount - 1)
145 ERR("ShellItem was released by client - please file a bug.\n");
146 return ret;
149 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
151 HRESULT ret;
152 LONG refcount;
153 if(!This->events) return S_OK;
155 refcount = IShellItem_AddRef(psi);
156 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->events, psi);
157 if(IShellItem_Release(psi) < refcount - 1)
158 ERR("ShellItem was released by client - please file a bug.\n");
159 return ret;
162 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
163 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
165 HRESULT ret;
166 LONG refcount;
167 if(!This->events) return S_OK;
169 refcount = IShellItem_AddRef(psi);
170 ret = INameSpaceTreeControlEvents_OnItemClick(This->events, psi, nstceHitTest, nstceClickType);
171 if(IShellItem_Release(psi) < refcount - 1)
172 ERR("ShellItem was released by client - please file a bug.\n");
173 return ret;
176 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
178 if(!This->events) return S_OK;
180 return INameSpaceTreeControlEvents_OnSelectionChanged(This->events, psia);
183 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
185 if(!This->events) return S_OK;
187 return INameSpaceTreeControlEvents_OnKeyboardInput(This->events, uMsg, wParam, lParam);
190 /*************************************************************************
191 * NamespaceTree helper functions
193 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
194 NSTCSTYLE nstcs_mask, DWORD *new_style)
196 DWORD old_style, tv_mask = 0;
197 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
199 if(This->hwnd_tv)
200 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
201 else
202 old_style = /* The default */
203 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
204 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
205 TVS_EDITLABELS | TVS_TRACKSELECT;
207 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
208 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
209 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
210 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
211 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
212 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
213 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
214 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
215 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
216 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
217 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
219 *new_style = 0;
221 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
222 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
223 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
224 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
225 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
226 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
227 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
228 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
229 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
230 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
231 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
233 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
235 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
237 return old_style^*new_style;
240 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
242 TVITEMEXW tvi;
244 tvi.mask = TVIF_PARAM;
245 tvi.lParam = 0;
246 tvi.hItem = hitem;
248 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
250 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
251 return (IShellItem*)tvi.lParam;
254 /* Returns the root that the given treeitem belongs to. */
255 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
257 HTREEITEM tmp, hroot = hitem;
258 nstc_root *root;
260 /* Work our way up the hierarchy */
261 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
262 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
264 /* Search through the list of roots for a match */
265 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
266 if(root->htreeitem == hroot)
267 break;
269 TRACE("root is %p\n", root);
270 return root;
273 /* Find a shellitem in the tree, starting from the given node. */
274 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
275 IShellItem *psi)
277 IShellItem *psi_node;
278 HTREEITEM next, result = NULL;
279 HRESULT hr;
280 int cmpo;
281 TRACE("%p, %p, %p\n", This, node, psi);
283 /* Check this node */
284 psi_node = shellitem_from_treeitem(This, node);
285 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
286 if(hr == S_OK)
287 return node;
289 /* Any children? */
290 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
291 TVGN_CHILD, (LPARAM)node);
292 if(next)
294 result = search_for_shellitem(This, next, psi);
295 if(result) return result;
298 /* Try our next sibling. */
299 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
300 TVGN_NEXT, (LPARAM)node);
301 if(next)
302 result = search_for_shellitem(This, next, psi);
304 return result;
307 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
309 HTREEITEM root;
310 TRACE("%p, %p\n", This, psi);
312 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
313 TVGN_ROOT, 0);
314 if(!root)
315 return NULL;
317 return search_for_shellitem(This, root, psi);
320 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
322 SHFILEINFOW sfi;
323 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
324 IImageList *list;
326 list = (IImageList *)SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
327 if (list) IImageList_Release(list);
328 return sfi.iIcon;
331 /* Insert a shellitem into the given place in the tree and return the
332 resulting treeitem. */
333 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
334 HTREEITEM hParent, HTREEITEM hInsertAfter)
336 TVINSERTSTRUCTW tvins;
337 TVITEMEXW *tvi = &tvins.u.itemex;
338 HTREEITEM hinserted;
339 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
341 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
342 tvi->cChildren = I_CHILDRENCALLBACK;
343 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
344 tvi->pszText = LPSTR_TEXTCALLBACKW;
346 /* Every treeitem contains a pointer to the corresponding ShellItem. */
347 tvi->lParam = (LPARAM)psi;
348 tvins.hParent = hParent;
349 tvins.hInsertAfter = hInsertAfter;
351 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
352 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
353 if(hinserted)
354 IShellItem_AddRef(psi);
356 return hinserted;
359 /* Enumerates the children of the folder represented by hitem
360 * according to the settings for the root, and adds them to the
361 * treeview. Returns the number of children added. */
362 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
364 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
365 nstc_root *root = root_for_treeitem(This, hitem);
366 LPITEMIDLIST pidl_parent;
367 IShellFolder *psf;
368 IEnumIDList *peidl;
369 UINT added = 0;
370 HRESULT hr;
372 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
373 if(SUCCEEDED(hr))
375 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
376 if(SUCCEEDED(hr))
378 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
379 if(SUCCEEDED(hr))
381 LPITEMIDLIST pidl;
382 IShellItem *psi;
383 ULONG fetched;
385 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
387 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
388 ILFree(pidl);
389 if(SUCCEEDED(hr))
391 if(insert_shellitem(This, psi, hitem, NULL))
393 events_OnItemAdded(This, psi, FALSE);
394 added++;
397 IShellItem_Release(psi);
399 else
400 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
402 IEnumIDList_Release(peidl);
404 else
405 ERR("EnumObjects failed with 0x%08x\n", hr);
407 IShellFolder_Release(psf);
409 else
410 ERR("BindToHandler failed with 0x%08x\n", hr);
412 ILFree(pidl_parent);
414 else
415 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
417 return added;
420 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
422 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
425 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
427 return shellitem_from_treeitem(This, get_selected_treeitem(This));
430 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
432 HTREEITEM next;
434 /* Collapse this node first, and then first child/next sibling. */
435 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
437 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
438 if(next) collapse_all(This, next);
440 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
441 if(next) collapse_all(This, next);
444 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
446 TVHITTESTINFO tviht;
447 tviht.pt.x = pt->x;
448 tviht.pt.y = pt->y;
449 tviht.hItem = NULL;
451 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
452 if(hitflag) *hitflag = tviht.flags;
453 return tviht.hItem;
456 /*************************************************************************
457 * NamespaceTree window functions
459 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
461 NSTC2Impl *This = crs->lpCreateParams;
462 HIMAGELIST ShellSmallIconList;
463 DWORD treeview_style, treeview_ex_style;
465 TRACE("%p (%p)\n", This, crs);
466 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
467 This->hwnd_main = hWnd;
469 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
471 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
472 0, 0, crs->cx, crs->cy,
473 hWnd, NULL, explorerframe_hinstance, NULL);
475 if(!This->hwnd_tv)
477 ERR("Failed to create treeview!\n");
478 return HRESULT_FROM_WIN32(GetLastError());
481 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
482 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
484 if(This->style & NSTCS_AUTOHSCROLL)
485 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
486 if(This->style & NSTCS_FADEINOUTEXPANDOS)
487 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
488 if(This->style & NSTCS_PARTIALCHECKBOXES)
489 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
490 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
491 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
492 if(This->style & NSTCS_DIMMEDCHECKBOXES)
493 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
495 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
497 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
499 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
500 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
502 else
504 ERR("Failed to get the System Image List.\n");
507 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
509 /* Subclass the treeview to get the keyboard events. */
510 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
511 (ULONG_PTR)tv_wndproc);
512 if(This->tv_oldwndproc)
513 SetPropW(This->hwnd_tv, thispropW, This);
515 return TRUE;
518 static LRESULT resize_namespacetree(NSTC2Impl *This)
520 RECT rc;
521 TRACE("%p\n", This);
523 GetClientRect(This->hwnd_main, &rc);
524 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
526 return TRUE;
529 static LRESULT destroy_namespacetree(NSTC2Impl *This)
531 TRACE("%p\n", This);
533 /* Undo the subclassing */
534 if(This->tv_oldwndproc)
536 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
537 RemovePropW(This->hwnd_tv, thispropW);
540 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
542 /* This reference was added in create_namespacetree */
543 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
544 return TRUE;
547 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
549 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
550 TRACE("%p\n", This);
552 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
553 return TRUE;
556 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
558 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
559 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
560 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
561 HRESULT hr;
563 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
565 if(item->mask & TVIF_CHILDREN)
567 SFGAOF sfgao;
569 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
570 if(SUCCEEDED(hr))
571 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
572 else
573 item->cChildren = 1;
575 item->mask |= TVIF_DI_SETITEM;
578 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
580 LPITEMIDLIST pidl;
582 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
583 if(FAILED(hr))
585 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
586 if(SUCCEEDED(hr))
588 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
589 item->mask |= TVIF_DI_SETITEM;
590 ILFree(pidl);
592 else
593 ERR("Failed to get IDList (%08x).\n", hr);
597 if(item->mask & TVIF_TEXT)
599 LPWSTR display_name;
601 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
602 if(SUCCEEDED(hr))
604 lstrcpynW(item->pszText, display_name, MAX_PATH);
605 item->mask |= TVIF_DI_SETITEM;
606 CoTaskMemFree(display_name);
608 else
609 ERR("Failed to get display name (%08x).\n", hr);
612 return TRUE;
615 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
617 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
620 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
622 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
623 IShellItem *psi;
624 TRACE("%p\n", This);
626 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
627 events_OnBeforeExpand(This, psi);
629 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
631 /* The node has no children, try to find some */
632 if(!fill_sublevel(This, nmtv->itemNew.hItem))
634 TVITEMEXW tvi;
635 /* Failed to enumerate any children, remove the expando
636 * (if any). */
637 tvi.hItem = nmtv->itemNew.hItem;
638 tvi.mask = TVIF_CHILDREN;
639 tvi.cChildren = 0;
640 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
642 return TRUE;
645 return FALSE;
648 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
650 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
651 IShellItem *psi;
652 TRACE("%p\n", This);
654 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
655 events_OnAfterExpand(This, psi);
656 return TRUE;
659 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
661 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
662 IShellItemArray *psia;
663 IShellItem *psi;
664 HRESULT hr;
665 TRACE("%p\n", This);
667 /* Note: Only supports one selected item. */
668 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
669 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
670 if(SUCCEEDED(hr))
672 events_OnSelectionChanged(This, psia);
673 IShellItemArray_Release(psia);
676 return TRUE;
679 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
681 TVHITTESTINFO tvhit;
682 IShellItem *psi;
683 HRESULT hr;
684 TRACE("%p (%p)\n", This, nmhdr);
686 GetCursorPos(&tvhit.pt);
687 ScreenToClient(This->hwnd_tv, &tvhit.pt);
688 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
690 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
691 return TRUE;
693 /* TVHT_ maps onto the corresponding NSTCEHT_ */
694 psi = shellitem_from_treeitem(This, tvhit.hItem);
695 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
697 /* The expando should not be expanded unless
698 * double-clicked. */
699 if(tvhit.flags == TVHT_ONITEMBUTTON)
700 return TRUE;
702 if(SUCCEEDED(hr))
703 return FALSE;
704 else
705 return TRUE;
708 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
710 TVHITTESTINFO tvhit;
711 IShellItem *psi;
712 HRESULT hr;
713 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
715 tvhit.pt.x = (int)(short)LOWORD(lParam);
716 tvhit.pt.y = (int)(short)HIWORD(lParam);
718 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
720 /* Seems to generate only ONITEM and ONITEMICON */
721 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
722 return FALSE;
724 psi = shellitem_from_treeitem(This, tvhit.hItem);
725 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
727 if(SUCCEEDED(hr))
728 return FALSE;
729 else
730 return TRUE;
733 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
735 IShellItem *psi;
736 HTREEITEM hitem;
737 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
739 /* Handled by the client? */
740 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
741 return TRUE;
743 if(uMsg == WM_KEYDOWN)
745 switch(wParam)
747 case VK_DELETE:
748 psi = get_selected_shellitem(This);
749 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
750 return TRUE;
752 case VK_F2:
753 hitem = get_selected_treeitem(This);
754 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
755 return TRUE;
759 /* Let the TreeView handle the key */
760 return FALSE;
763 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
765 NSTC2Impl *This = (NSTC2Impl*)GetPropW(hWnd, thispropW);
767 switch(uMessage) {
768 case WM_KEYDOWN:
769 case WM_KEYUP:
770 case WM_CHAR:
771 case WM_SYSKEYDOWN:
772 case WM_SYSKEYUP:
773 case WM_SYSCHAR:
774 if(on_kbd_event(This, uMessage, wParam, lParam))
775 return TRUE;
776 break;
778 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
781 /* Pass the message on to the treeview */
782 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
785 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
786 WPARAM wParam, LPARAM lParam)
788 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
789 NMHDR *nmhdr;
791 switch(uMessage)
793 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
794 case WM_SIZE: return resize_namespacetree(This);
795 case WM_DESTROY: return destroy_namespacetree(This);
796 case WM_NOTIFY:
797 nmhdr = (NMHDR*)lParam;
798 switch(nmhdr->code)
800 case NM_CLICK: return on_nm_click(This, nmhdr);
801 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
802 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
803 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
804 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
805 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
806 default: break;
808 break;
809 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
811 return 0;
814 /**************************************************************************
815 * INameSpaceTreeControl2 Implementation
817 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
818 REFIID riid,
819 void **ppvObject)
821 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
822 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
824 *ppvObject = NULL;
825 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
826 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
827 IsEqualIID(riid, &IID_IUnknown))
829 *ppvObject = &This->INameSpaceTreeControl2_iface;
831 else if(IsEqualIID(riid, &IID_IOleWindow))
833 *ppvObject = &This->IOleWindow_iface;
836 if(*ppvObject)
838 IUnknown_AddRef((IUnknown*)*ppvObject);
839 return S_OK;
842 return E_NOINTERFACE;
845 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
847 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
848 LONG ref = InterlockedIncrement(&This->ref);
850 TRACE("%p - ref %d\n", This, ref);
852 return ref;
855 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
857 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
858 LONG ref = InterlockedDecrement(&This->ref);
860 TRACE("%p - ref: %d\n", This, ref);
862 if(!ref)
864 TRACE("Freeing.\n");
865 heap_free(This);
866 EFRAME_UnlockModule();
869 return ref;
872 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
873 HWND hwndParent,
874 RECT *prc,
875 NSTCSTYLE nstcsFlags)
877 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
878 WNDCLASSW wc;
879 DWORD window_style, window_ex_style;
880 INITCOMMONCONTROLSEX icex;
881 RECT rc;
882 static const WCHAR NSTC2_CLASS_NAME[] =
883 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
884 'C','o','n','t','r','o','l',0};
886 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
888 if(nstcsFlags & unsupported_styles)
889 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
890 nstcsFlags, nstcsFlags & unsupported_styles);
892 This->style = nstcsFlags;
894 icex.dwSize = sizeof( icex );
895 icex.dwICC = ICC_TREEVIEW_CLASSES;
896 InitCommonControlsEx( &icex );
898 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
900 wc.style = CS_HREDRAW | CS_VREDRAW;
901 wc.lpfnWndProc = NSTC2_WndProc;
902 wc.cbClsExtra = 0;
903 wc.cbWndExtra = 0;
904 wc.hInstance = explorerframe_hinstance;
905 wc.hIcon = 0;
906 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
907 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
908 wc.lpszMenuName = NULL;
909 wc.lpszClassName = NSTC2_CLASS_NAME;
911 if (!RegisterClassW(&wc)) return E_FAIL;
914 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
915 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
916 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
917 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
919 if(prc)
920 rc = *prc;
921 else
922 SetRectEmpty(&rc);
924 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
925 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
926 hwndParent, 0, explorerframe_hinstance, This);
928 if(!This->hwnd_main)
930 ERR("Failed to create the window.\n");
931 return HRESULT_FROM_WIN32(GetLastError());
934 return S_OK;
937 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, IUnknown *handler, DWORD *cookie)
939 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
941 TRACE("%p (%p, %p)\n", This, handler, cookie);
943 *cookie = 0;
945 /* Only one client supported */
946 if (This->events || This->customdraw || This->dragdrop)
947 return E_FAIL;
949 /* FIXME: request INameSpaceTreeAccessible too */
950 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlEvents, (void**)&This->events);
951 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlCustomDraw, (void**)&This->customdraw);
952 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlDropHandler, (void**)&This->dragdrop);
954 if (This->events || This->customdraw || This->dragdrop)
955 *cookie = 1;
957 return *cookie ? S_OK : E_FAIL;
960 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, DWORD cookie)
962 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
964 TRACE("%p (%x)\n", This, cookie);
966 /* The cookie is ignored. */
968 if (This->events)
970 INameSpaceTreeControlEvents_Release(This->events);
971 This->events = NULL;
974 if (This->customdraw)
976 INameSpaceTreeControlCustomDraw_Release(This->customdraw);
977 This->customdraw = NULL;
980 if (This->dragdrop)
982 INameSpaceTreeControlDropHandler_Release(This->dragdrop);
983 This->dragdrop = NULL;
986 return S_OK;
989 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
990 int iIndex,
991 IShellItem *psiRoot,
992 SHCONTF grfEnumFlags,
993 NSTCROOTSTYLE grfRootStyle,
994 IShellItemFilter *pif)
996 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
997 nstc_root *new_root;
998 struct list *add_after_entry;
999 HTREEITEM add_after_hitem;
1000 int i;
1002 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
1004 new_root = heap_alloc(sizeof(*new_root));
1005 if(!new_root)
1006 return E_OUTOFMEMORY;
1008 new_root->psi = psiRoot;
1009 new_root->enum_flags = grfEnumFlags;
1010 new_root->root_style = grfRootStyle;
1011 new_root->pif = pif;
1013 /* We want to keep the roots in the internal list and in the
1014 * treeview in the same order. */
1015 add_after_entry = &This->roots;
1016 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
1017 add_after_entry = list_next(&This->roots, add_after_entry);
1019 if(add_after_entry == &This->roots)
1020 add_after_hitem = TVI_FIRST;
1021 else
1022 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1024 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1025 if(!new_root->htreeitem)
1027 WARN("Failed to add the root.\n");
1028 heap_free(new_root);
1029 return E_FAIL;
1032 list_add_after(add_after_entry, &new_root->entry);
1033 events_OnItemAdded(This, psiRoot, TRUE);
1035 if(grfRootStyle & NSTCRS_HIDDEN)
1037 TVITEMEXW tvi;
1038 tvi.mask = TVIF_STATEEX;
1039 tvi.uStateEx = TVIS_EX_FLAT;
1040 tvi.hItem = new_root->htreeitem;
1042 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1045 if(grfRootStyle & NSTCRS_EXPANDED)
1046 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1047 (LPARAM)new_root->htreeitem);
1049 return S_OK;
1052 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1053 IShellItem *psiRoot,
1054 SHCONTF grfEnumFlags,
1055 NSTCROOTSTYLE grfRootStyle,
1056 IShellItemFilter *pif)
1058 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1059 UINT root_count;
1060 TRACE("%p, %p, %x, %x, %p\n",
1061 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1063 root_count = list_count(&This->roots);
1065 return INameSpaceTreeControl2_InsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1068 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1069 IShellItem *psiRoot)
1071 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1072 nstc_root *cursor, *root = NULL;
1073 TRACE("%p (%p)\n", This, psiRoot);
1075 if(!psiRoot)
1076 return E_NOINTERFACE;
1078 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1080 HRESULT hr;
1081 int order;
1082 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1083 if(hr == S_OK)
1085 root = cursor;
1086 break;
1090 TRACE("root %p\n", root);
1091 if(root)
1093 events_OnItemDeleted(This, root->psi, TRUE);
1094 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1095 list_remove(&root->entry);
1096 heap_free(root);
1097 return S_OK;
1099 else
1101 WARN("No matching root found.\n");
1102 return E_FAIL;
1106 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1108 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1109 nstc_root *cur1, *cur2;
1111 TRACE("%p\n", This);
1113 if (list_empty(&This->roots))
1114 return E_INVALIDARG;
1116 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1117 INameSpaceTreeControl2_RemoveRoot(iface, cur1->psi);
1119 return S_OK;
1122 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1123 IShellItemArray **ppsiaRootItems)
1125 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1126 IShellFolder *psf;
1127 LPITEMIDLIST *array;
1128 nstc_root *root;
1129 UINT count, i;
1130 HRESULT hr;
1131 TRACE("%p (%p)\n", This, ppsiaRootItems);
1133 count = list_count(&This->roots);
1135 if(!count)
1136 return E_INVALIDARG;
1138 array = heap_alloc(sizeof(LPITEMIDLIST)*count);
1140 i = 0;
1141 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1142 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1144 SHGetDesktopFolder(&psf);
1145 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1146 ppsiaRootItems);
1147 IShellFolder_Release(psf);
1149 for(i = 0; i < count; i++)
1150 ILFree(array[i]);
1152 heap_free(array);
1154 return hr;
1157 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1158 IShellItem *psi,
1159 NSTCITEMSTATE nstcisMask,
1160 NSTCITEMSTATE nstcisFlags)
1162 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1163 TVITEMEXW tvi;
1164 HTREEITEM hitem;
1166 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1168 hitem = treeitem_from_shellitem(This, psi);
1169 if(!hitem) return E_INVALIDARG;
1171 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1172 in two TVM_SETITEMW's */
1173 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1175 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1176 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1178 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1180 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1183 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1184 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1186 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1187 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1190 if(nstcisMask & NSTCIS_DISABLED)
1191 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1192 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1193 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1194 (nstcisFlags & NSTCIS_DISABLED) )
1195 tvi.mask = TVIF_STATE;
1196 else
1197 tvi.mask = 0;
1199 if(tvi.mask)
1201 tvi.stateMask = tvi.state = 0;
1202 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1203 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1204 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1206 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1208 tvi.stateMask = 0;
1211 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1212 tvi.hItem = hitem;
1214 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1217 return S_OK;
1220 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1221 IShellItem *psi,
1222 NSTCITEMSTATE nstcisMask,
1223 NSTCITEMSTATE *pnstcisFlags)
1225 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1226 HTREEITEM hitem;
1227 TVITEMEXW tvi;
1228 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1230 hitem = treeitem_from_shellitem(This, psi);
1231 if(!hitem)
1232 return E_INVALIDARG;
1234 *pnstcisFlags = 0;
1236 tvi.hItem = hitem;
1237 tvi.mask = TVIF_STATE;
1238 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1240 if(nstcisMask & NSTCIS_DISABLED)
1241 tvi.mask |= TVIF_STATEEX;
1243 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1244 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1245 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1246 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1247 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1249 *pnstcisFlags &= nstcisMask;
1251 return S_OK;
1254 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1255 IShellItemArray **psiaItems)
1257 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1258 IShellItem *psiselected;
1260 TRACE("%p (%p)\n", This, psiaItems);
1262 psiselected = get_selected_shellitem(This);
1263 if(!psiselected)
1265 *psiaItems = NULL;
1266 return E_FAIL;
1269 return SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1270 (void**)psiaItems);
1273 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1274 IShellItem *psi,
1275 int *piStateNumber)
1277 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1278 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1279 return E_NOTIMPL;
1282 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1283 IShellItem *psi,
1284 int iStateNumber)
1286 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1287 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1288 return E_NOTIMPL;
1291 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1292 IShellItem *psi)
1294 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1295 HTREEITEM hitem;
1297 TRACE("%p (%p)\n", This, psi);
1299 hitem = treeitem_from_shellitem(This, psi);
1300 if(hitem)
1302 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1303 return S_OK;
1306 return E_INVALIDARG;
1309 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1310 LPCWSTR pszTheme)
1312 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1313 FIXME("stub, %p (%p)\n", This, pszTheme);
1314 return E_NOTIMPL;
1317 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1318 IShellItem *psi,
1319 NSTCGNI nstcgi,
1320 IShellItem **ppsiNext)
1322 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1323 HTREEITEM hitem, hnext;
1324 UINT tvgn;
1325 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1327 if(!ppsiNext) return E_POINTER;
1328 if(!psi) return E_FAIL;
1330 *ppsiNext = NULL;
1332 hitem = treeitem_from_shellitem(This, psi);
1333 if(!hitem)
1334 return E_INVALIDARG;
1336 switch(nstcgi)
1338 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1339 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1340 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1341 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1342 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1343 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1344 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1345 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1346 default:
1347 FIXME("Unknown nstcgi value %d\n", nstcgi);
1348 return E_FAIL;
1351 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1352 if(hnext)
1354 *ppsiNext = shellitem_from_treeitem(This, hnext);
1355 IShellItem_AddRef(*ppsiNext);
1356 return S_OK;
1359 return E_FAIL;
1362 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1363 POINT *ppt,
1364 IShellItem **ppsiOut)
1366 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1367 HTREEITEM hitem;
1368 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1370 if(!ppt || !ppsiOut)
1371 return E_POINTER;
1373 *ppsiOut = NULL;
1375 hitem = treeitem_from_point(This, ppt, NULL);
1376 if(hitem)
1377 *ppsiOut = shellitem_from_treeitem(This, hitem);
1379 if(*ppsiOut)
1381 IShellItem_AddRef(*ppsiOut);
1382 return S_OK;
1385 return S_FALSE;
1388 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1389 IShellItem *psi,
1390 RECT *prect)
1392 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1393 HTREEITEM hitem;
1394 TRACE("%p (%p, %p)\n", This, psi, prect);
1396 if(!psi || !prect)
1397 return E_POINTER;
1399 hitem = treeitem_from_shellitem(This, psi);
1400 if(hitem)
1402 *(HTREEITEM*)prect = hitem;
1403 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1405 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1406 return S_OK;
1410 return E_INVALIDARG;
1413 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1415 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1416 nstc_root *root;
1417 TRACE("%p\n", This);
1419 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1420 collapse_all(This, root->htreeitem);
1422 return S_OK;
1425 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1426 NSTCSTYLE nstcsMask,
1427 NSTCSTYLE nstcsStyle)
1429 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1430 static const DWORD tv_style_flags =
1431 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1432 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1433 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1434 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1435 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1436 static const DWORD nstc_flags =
1437 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1438 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1439 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1440 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1442 /* Fail if there is an attempt to set an unknown style. */
1443 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1444 return E_FAIL;
1446 if(nstcsMask & tv_style_flags)
1448 DWORD new_style;
1449 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1450 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1453 /* Flags affecting the host window */
1454 if(nstcsMask & NSTCS_BORDER)
1456 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1457 new_style &= ~WS_BORDER;
1458 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1459 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1461 if(nstcsMask & NSTCS_TABSTOP)
1463 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1464 new_style &= ~WS_EX_CONTROLPARENT;
1465 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1466 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1469 if((nstcsStyle & nstcsMask) & unsupported_styles)
1470 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1471 (nstcsStyle & nstcsMask),
1472 (nstcsStyle & nstcsMask) & unsupported_styles);
1474 This->style &= ~nstcsMask;
1475 This->style |= (nstcsStyle & nstcsMask);
1477 return S_OK;
1480 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1481 NSTCSTYLE nstcsMask,
1482 NSTCSTYLE *pnstcsStyle)
1484 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1485 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1487 *pnstcsStyle = (This->style & nstcsMask);
1489 return S_OK;
1492 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1493 NSTCSTYLE2 nstcsMask,
1494 NSTCSTYLE2 nstcsStyle)
1496 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1497 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1499 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1500 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1501 (nstcsStyle & nstcsMask),
1502 (nstcsStyle & nstcsMask) & unsupported_styles2);
1504 This->style2 &= ~nstcsMask;
1505 This->style2 |= (nstcsStyle & nstcsMask);
1507 return S_OK;
1510 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1511 NSTCSTYLE2 nstcsMask,
1512 NSTCSTYLE2 *pnstcsStyle)
1514 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1515 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1517 *pnstcsStyle = (This->style2 & nstcsMask);
1519 return S_OK;
1522 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1523 NSTC2_fnQueryInterface,
1524 NSTC2_fnAddRef,
1525 NSTC2_fnRelease,
1526 NSTC2_fnInitialize,
1527 NSTC2_fnTreeAdvise,
1528 NSTC2_fnTreeUnadvise,
1529 NSTC2_fnAppendRoot,
1530 NSTC2_fnInsertRoot,
1531 NSTC2_fnRemoveRoot,
1532 NSTC2_fnRemoveAllRoots,
1533 NSTC2_fnGetRootItems,
1534 NSTC2_fnSetItemState,
1535 NSTC2_fnGetItemState,
1536 NSTC2_fnGetSelectedItems,
1537 NSTC2_fnGetItemCustomState,
1538 NSTC2_fnSetItemCustomState,
1539 NSTC2_fnEnsureItemVisible,
1540 NSTC2_fnSetTheme,
1541 NSTC2_fnGetNextItem,
1542 NSTC2_fnHitTest,
1543 NSTC2_fnGetItemRect,
1544 NSTC2_fnCollapseAll,
1545 NSTC2_fnSetControlStyle,
1546 NSTC2_fnGetControlStyle,
1547 NSTC2_fnSetControlStyle2,
1548 NSTC2_fnGetControlStyle2
1551 /**************************************************************************
1552 * IOleWindow Implementation
1555 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1557 NSTC2Impl *This = impl_from_IOleWindow(iface);
1558 return INameSpaceTreeControl2_QueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1561 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1563 NSTC2Impl *This = impl_from_IOleWindow(iface);
1564 return INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
1567 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1569 NSTC2Impl *This = impl_from_IOleWindow(iface);
1570 return INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
1573 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1575 NSTC2Impl *This = impl_from_IOleWindow(iface);
1576 TRACE("%p (%p)\n", This, phwnd);
1578 *phwnd = This->hwnd_main;
1579 return S_OK;
1582 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1584 NSTC2Impl *This = impl_from_IOleWindow(iface);
1585 TRACE("%p (%d)\n", This, fEnterMode);
1587 /* Not implemented */
1588 return E_NOTIMPL;
1591 static const IOleWindowVtbl vt_IOleWindow = {
1592 IOW_fnQueryInterface,
1593 IOW_fnAddRef,
1594 IOW_fnRelease,
1595 IOW_fnGetWindow,
1596 IOW_fnContextSensitiveHelp
1599 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1601 NSTC2Impl *nstc;
1602 HRESULT ret;
1604 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1606 if(!ppv)
1607 return E_POINTER;
1608 if(pUnkOuter)
1609 return CLASS_E_NOAGGREGATION;
1611 EFRAME_LockModule();
1613 nstc = heap_alloc_zero(sizeof(*nstc));
1614 if (!nstc)
1615 return E_OUTOFMEMORY;
1617 nstc->ref = 1;
1618 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1619 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1621 list_init(&nstc->roots);
1623 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1624 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1626 TRACE("--(%p)\n", ppv);
1627 return ret;