msvcp90: Added _Stofx implementation.
[wine/multimedia.git] / dlls / explorerframe / nstc.c
blob00ad1f6e32bc1e4ae725638bf3ceb62f56daadf3
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
25 #define NONAMELESSSTRUCT
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "shellapi.h"
33 #include "wine/list.h"
34 #include "wine/debug.h"
36 #include "explorerframe_main.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
40 typedef struct nstc_root {
41 IShellItem *psi;
42 HTREEITEM htreeitem;
43 SHCONTF enum_flags;
44 NSTCROOTSTYLE root_style;
45 IShellItemFilter *pif;
46 struct list entry;
47 } nstc_root;
49 typedef struct {
50 INameSpaceTreeControl2 INameSpaceTreeControl2_iface;
51 IOleWindow IOleWindow_iface;
52 LONG ref;
54 HWND hwnd_main;
55 HWND hwnd_tv;
57 WNDPROC tv_oldwndproc;
59 NSTCSTYLE style;
60 NSTCSTYLE2 style2;
61 struct list roots;
63 INameSpaceTreeControlEvents *pnstce;
64 } NSTC2Impl;
66 static const DWORD unsupported_styles =
67 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
68 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
69 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
70 static const DWORD unsupported_styles2 =
71 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
72 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
74 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
76 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
79 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
81 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
84 /* Forward declarations */
85 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
87 /*************************************************************************
88 * NamespaceTree event wrappers
90 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
91 int *piDefaultIcon, int *piOpenIcon)
93 HRESULT ret;
94 LONG refcount;
95 if(!This->pnstce) return E_NOTIMPL;
97 refcount = IShellItem_AddRef(psi);
98 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->pnstce, psi, piDefaultIcon, piOpenIcon);
99 if(IShellItem_Release(psi) < refcount - 1)
100 ERR("ShellItem was released by client - please file a bug.\n");
101 return ret;
104 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
106 HRESULT ret;
107 LONG refcount;
108 if(!This->pnstce) return S_OK;
110 refcount = IShellItem_AddRef(psi);
111 ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
112 if(IShellItem_Release(psi) < refcount - 1)
113 ERR("ShellItem was released by client - please file a bug.\n");
114 return ret;
117 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
119 HRESULT ret;
120 LONG refcount;
121 if(!This->pnstce) return S_OK;
123 refcount = IShellItem_AddRef(psi);
124 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->pnstce, psi, fIsRoot);
125 if(IShellItem_Release(psi) < refcount - 1)
126 ERR("ShellItem was released by client - please file a bug.\n");
127 return ret;
130 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
132 HRESULT ret;
133 LONG refcount;
134 if(!This->pnstce) return S_OK;
136 refcount = IShellItem_AddRef(psi);
137 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->pnstce, psi);
138 if(IShellItem_Release(psi) < refcount - 1)
139 ERR("ShellItem was released by client - please file a bug.\n");
140 return ret;
143 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
145 HRESULT ret;
146 LONG refcount;
147 if(!This->pnstce) return S_OK;
149 refcount = IShellItem_AddRef(psi);
150 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->pnstce, psi);
151 if(IShellItem_Release(psi) < refcount - 1)
152 ERR("ShellItem was released by client - please file a bug.\n");
153 return ret;
156 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
157 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
159 HRESULT ret;
160 LONG refcount;
161 if(!This->pnstce) return S_OK;
163 refcount = IShellItem_AddRef(psi);
164 ret = INameSpaceTreeControlEvents_OnItemClick(This->pnstce, psi, nstceHitTest, nstceClickType);
165 if(IShellItem_Release(psi) < refcount - 1)
166 ERR("ShellItem was released by client - please file a bug.\n");
167 return ret;
170 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
172 if(!This->pnstce) return S_OK;
174 return INameSpaceTreeControlEvents_OnSelectionChanged(This->pnstce, psia);
177 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
179 if(!This->pnstce) return S_OK;
181 return INameSpaceTreeControlEvents_OnKeyboardInput(This->pnstce, uMsg, wParam, lParam);
184 /*************************************************************************
185 * NamespaceTree helper functions
187 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
188 NSTCSTYLE nstcs_mask, DWORD *new_style)
190 DWORD old_style, tv_mask = 0;
191 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
193 if(This->hwnd_tv)
194 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
195 else
196 old_style = /* The default */
197 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
198 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
199 TVS_EDITLABELS | TVS_TRACKSELECT;
201 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
202 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
203 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
204 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
205 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
206 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
207 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
208 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
209 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
210 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
211 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
213 *new_style = 0;
215 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
216 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
217 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
218 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
219 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
220 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
221 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
222 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
223 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
224 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
225 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
227 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
229 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
231 return old_style^*new_style;
234 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
236 TVITEMEXW tvi;
238 tvi.mask = TVIF_PARAM;
239 tvi.lParam = 0;
240 tvi.hItem = hitem;
242 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
244 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
245 return (IShellItem*)tvi.lParam;
248 /* Returns the root that the given treeitem belongs to. */
249 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
251 HTREEITEM tmp, hroot = hitem;
252 nstc_root *root;
254 /* Work our way up the hierarchy */
255 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
256 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
258 /* Search through the list of roots for a match */
259 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
260 if(root->htreeitem == hroot)
261 break;
263 TRACE("root is %p\n", root);
264 return root;
267 /* Find a shellitem in the tree, starting from the given node. */
268 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
269 IShellItem *psi)
271 IShellItem *psi_node;
272 HTREEITEM next, result = NULL;
273 HRESULT hr;
274 int cmpo;
275 TRACE("%p, %p, %p\n", This, node, psi);
277 /* Check this node */
278 psi_node = shellitem_from_treeitem(This, node);
279 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
280 if(hr == S_OK)
281 return node;
283 /* Any children? */
284 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
285 TVGN_CHILD, (LPARAM)node);
286 if(next)
288 result = search_for_shellitem(This, next, psi);
289 if(result) return result;
292 /* Try our next sibling. */
293 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
294 TVGN_NEXT, (LPARAM)node);
295 if(next)
296 result = search_for_shellitem(This, next, psi);
298 return result;
301 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
303 HTREEITEM root;
304 TRACE("%p, %p\n", This, psi);
306 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
307 TVGN_ROOT, 0);
308 if(!root)
309 return NULL;
311 return search_for_shellitem(This, root, psi);
314 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
316 SHFILEINFOW sfi;
317 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
318 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
319 return sfi.iIcon;
322 /* Insert a shellitem into the given place in the tree and return the
323 resulting treeitem. */
324 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
325 HTREEITEM hParent, HTREEITEM hInsertAfter)
327 TVINSERTSTRUCTW tvins;
328 TVITEMEXW *tvi = &tvins.u.itemex;
329 HTREEITEM hinserted;
330 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
332 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
333 tvi->cChildren = I_CHILDRENCALLBACK;
334 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
335 tvi->pszText = LPSTR_TEXTCALLBACKW;
337 /* Every treeitem contains a pointer to the corresponding ShellItem. */
338 tvi->lParam = (LPARAM)psi;
339 tvins.hParent = hParent;
340 tvins.hInsertAfter = hInsertAfter;
342 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
343 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
344 if(hinserted)
345 IShellItem_AddRef(psi);
347 return hinserted;
350 /* Enumerates the children of the folder represented by hitem
351 * according to the settings for the root, and adds them to the
352 * treeview. Returns the number of children added. */
353 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
355 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
356 nstc_root *root = root_for_treeitem(This, hitem);
357 LPITEMIDLIST pidl_parent;
358 IShellFolder *psf;
359 IEnumIDList *peidl;
360 UINT added = 0;
361 HRESULT hr;
363 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
364 if(SUCCEEDED(hr))
366 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
367 if(SUCCEEDED(hr))
369 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
370 if(SUCCEEDED(hr))
372 LPITEMIDLIST pidl;
373 IShellItem *psi;
374 ULONG fetched;
376 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
378 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
379 ILFree(pidl);
380 if(SUCCEEDED(hr))
382 if(insert_shellitem(This, psi, hitem, NULL))
384 events_OnItemAdded(This, psi, FALSE);
385 added++;
388 IShellItem_Release(psi);
390 else
391 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
393 IEnumIDList_Release(peidl);
395 else
396 ERR("EnumObjects failed with 0x%08x\n", hr);
398 IShellFolder_Release(psf);
400 else
401 ERR("BindToHandler failed with 0x%08x\n", hr);
403 ILFree(pidl_parent);
405 else
406 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
408 return added;
411 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
413 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
416 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
418 return shellitem_from_treeitem(This, get_selected_treeitem(This));
421 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
423 HTREEITEM next;
425 /* Collapse this node first, and then first child/next sibling. */
426 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
428 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
429 if(next) collapse_all(This, next);
431 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
432 if(next) collapse_all(This, next);
435 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
437 TVHITTESTINFO tviht;
438 tviht.pt.x = pt->x;
439 tviht.pt.y = pt->y;
440 tviht.hItem = NULL;
442 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
443 if(hitflag) *hitflag = tviht.flags;
444 return tviht.hItem;
447 /*************************************************************************
448 * NamespaceTree window functions
450 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
452 NSTC2Impl *This = crs->lpCreateParams;
453 HIMAGELIST ShellSmallIconList;
454 DWORD treeview_style, treeview_ex_style;
456 TRACE("%p (%p)\n", This, crs);
457 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
458 This->hwnd_main = hWnd;
460 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
462 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
463 0, 0, crs->cx, crs->cy,
464 hWnd, NULL, explorerframe_hinstance, NULL);
466 if(!This->hwnd_tv)
468 ERR("Failed to create treeview!\n");
469 return HRESULT_FROM_WIN32(GetLastError());
472 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
473 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
475 if(This->style & NSTCS_AUTOHSCROLL)
476 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
477 if(This->style & NSTCS_FADEINOUTEXPANDOS)
478 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
479 if(This->style & NSTCS_PARTIALCHECKBOXES)
480 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
481 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
482 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
483 if(This->style & NSTCS_DIMMEDCHECKBOXES)
484 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
486 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
488 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
490 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
491 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
493 else
495 ERR("Failed to get the System Image List.\n");
498 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
500 /* Subclass the treeview to get the keybord events. */
501 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
502 (ULONG_PTR)tv_wndproc);
503 if(This->tv_oldwndproc)
504 SetPropA(This->hwnd_tv, "PROP_THIS", This);
506 return TRUE;
509 static LRESULT resize_namespacetree(NSTC2Impl *This)
511 RECT rc;
512 TRACE("%p\n", This);
514 GetClientRect(This->hwnd_main, &rc);
515 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
517 return TRUE;
520 static LRESULT destroy_namespacetree(NSTC2Impl *This)
522 TRACE("%p\n", This);
524 /* Undo the subclassing */
525 if(This->tv_oldwndproc)
527 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
528 RemovePropA(This->hwnd_tv, "PROP_THIS");
531 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
533 /* This reference was added in create_namespacetree */
534 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
535 return TRUE;
538 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
540 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
541 TRACE("%p\n", This);
543 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
544 return TRUE;
547 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
549 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
550 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
551 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
552 HRESULT hr;
554 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
556 if(item->mask & TVIF_CHILDREN)
558 SFGAOF sfgao;
560 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
561 if(SUCCEEDED(hr))
562 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
563 else
564 item->cChildren = 1;
566 item->mask |= TVIF_DI_SETITEM;
569 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
571 LPITEMIDLIST pidl;
573 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
574 if(FAILED(hr))
576 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
577 if(SUCCEEDED(hr))
579 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
580 item->mask |= TVIF_DI_SETITEM;
581 ILFree(pidl);
583 else
584 ERR("Failed to get IDList (%08x).\n", hr);
588 if(item->mask & TVIF_TEXT)
590 LPWSTR display_name;
592 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
593 if(SUCCEEDED(hr))
595 lstrcpynW(item->pszText, display_name, MAX_PATH);
596 item->mask |= TVIF_DI_SETITEM;
597 CoTaskMemFree(display_name);
599 else
600 ERR("Failed to get display name (%08x).\n", hr);
603 return TRUE;
606 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
608 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
611 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
613 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
614 IShellItem *psi;
615 TRACE("%p\n", This);
617 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
618 events_OnBeforeExpand(This, psi);
620 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
622 /* The node has no children, try to find some */
623 if(!fill_sublevel(This, nmtv->itemNew.hItem))
625 TVITEMEXW tvi;
626 /* Failed to enumerate any children, remove the expando
627 * (if any). */
628 tvi.hItem = nmtv->itemNew.hItem;
629 tvi.mask = TVIF_CHILDREN;
630 tvi.cChildren = 0;
631 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
633 return TRUE;
636 return FALSE;
639 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
641 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
642 IShellItem *psi;
643 TRACE("%p\n", This);
645 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
646 events_OnAfterExpand(This, psi);
647 return TRUE;
650 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
652 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
653 IShellItemArray *psia;
654 IShellItem *psi;
655 HRESULT hr;
656 TRACE("%p\n", This);
658 /* Note: Only supports one selected item. */
659 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
660 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
661 if(SUCCEEDED(hr))
663 events_OnSelectionChanged(This, psia);
664 IShellItemArray_Release(psia);
667 return TRUE;
670 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
672 TVHITTESTINFO tvhit;
673 IShellItem *psi;
674 HRESULT hr;
675 TRACE("%p (%p)\n", This, nmhdr);
677 GetCursorPos(&tvhit.pt);
678 ScreenToClient(This->hwnd_tv, &tvhit.pt);
679 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
681 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
682 return TRUE;
684 /* TVHT_ maps onto the corresponding NSTCEHT_ */
685 psi = shellitem_from_treeitem(This, tvhit.hItem);
686 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
688 /* The expando should not be expanded unless
689 * double-clicked. */
690 if(tvhit.flags == TVHT_ONITEMBUTTON)
691 return TRUE;
693 if(SUCCEEDED(hr))
694 return FALSE;
695 else
696 return TRUE;
699 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
701 TVHITTESTINFO tvhit;
702 IShellItem *psi;
703 HRESULT hr;
704 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
706 tvhit.pt.x = (int)(short)LOWORD(lParam);
707 tvhit.pt.y = (int)(short)HIWORD(lParam);
709 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
711 /* Seems to generate only ONITEM and ONITEMICON */
712 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
713 return FALSE;
715 psi = shellitem_from_treeitem(This, tvhit.hItem);
716 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
718 if(SUCCEEDED(hr))
719 return FALSE;
720 else
721 return TRUE;
724 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
726 IShellItem *psi;
727 HTREEITEM hitem;
728 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
730 /* Handled by the client? */
731 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
732 return TRUE;
734 if(uMsg == WM_KEYDOWN)
736 switch(wParam)
738 case VK_DELETE:
739 psi = get_selected_shellitem(This);
740 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
741 return TRUE;
743 case VK_F2:
744 hitem = get_selected_treeitem(This);
745 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
746 return TRUE;
750 /* Let the TreeView handle the key */
751 return FALSE;
754 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
756 NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS");
758 switch(uMessage) {
759 case WM_KEYDOWN:
760 case WM_KEYUP:
761 case WM_CHAR:
762 case WM_SYSKEYDOWN:
763 case WM_SYSKEYUP:
764 case WM_SYSCHAR:
765 if(on_kbd_event(This, uMessage, wParam, lParam))
766 return TRUE;
767 break;
769 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
772 /* Pass the message on to the treeview */
773 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
776 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
777 WPARAM wParam, LPARAM lParam)
779 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
780 NMHDR *nmhdr;
782 switch(uMessage)
784 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
785 case WM_SIZE: return resize_namespacetree(This);
786 case WM_DESTROY: return destroy_namespacetree(This);
787 case WM_NOTIFY:
788 nmhdr = (NMHDR*)lParam;
789 switch(nmhdr->code)
791 case NM_CLICK: return on_nm_click(This, nmhdr);
792 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
793 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
794 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
795 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
796 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
797 default: break;
799 break;
800 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
802 return 0;
805 /**************************************************************************
806 * INameSpaceTreeControl2 Implementation
808 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
809 REFIID riid,
810 void **ppvObject)
812 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
813 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
815 *ppvObject = NULL;
816 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
817 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
818 IsEqualIID(riid, &IID_IUnknown))
820 *ppvObject = This;
822 else if(IsEqualIID(riid, &IID_IOleWindow))
824 *ppvObject = &This->IOleWindow_iface;
827 if(*ppvObject)
829 IUnknown_AddRef((IUnknown*)*ppvObject);
830 return S_OK;
833 return E_NOINTERFACE;
836 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
838 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
839 LONG ref = InterlockedIncrement(&This->ref);
841 TRACE("%p - ref %d\n", This, ref);
843 return ref;
846 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
848 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
849 LONG ref = InterlockedDecrement(&This->ref);
851 TRACE("%p - ref: %d\n", This, ref);
853 if(!ref)
855 TRACE("Freeing.\n");
856 HeapFree(GetProcessHeap(), 0, This);
857 EFRAME_UnlockModule();
858 return 0;
861 return ref;
864 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
865 HWND hwndParent,
866 RECT *prc,
867 NSTCSTYLE nstcsFlags)
869 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
870 WNDCLASSW wc;
871 DWORD window_style, window_ex_style;
872 RECT rc;
873 static const WCHAR NSTC2_CLASS_NAME[] =
874 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
875 'C','o','n','t','r','o','l',0};
877 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
879 if(nstcsFlags & unsupported_styles)
880 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
881 nstcsFlags, nstcsFlags & unsupported_styles);
883 This->style = nstcsFlags;
885 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
887 wc.style = CS_HREDRAW | CS_VREDRAW;
888 wc.lpfnWndProc = NSTC2_WndProc;
889 wc.cbClsExtra = 0;
890 wc.cbWndExtra = 0;
891 wc.hInstance = explorerframe_hinstance;
892 wc.hIcon = 0;
893 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
894 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
895 wc.lpszMenuName = NULL;
896 wc.lpszClassName = NSTC2_CLASS_NAME;
898 if (!RegisterClassW(&wc)) return E_FAIL;
901 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
902 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
903 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
904 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
906 if(prc)
907 CopyRect(&rc, prc);
908 else
909 rc.left = rc.right = rc.top = rc.bottom = 0;
911 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
912 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
913 hwndParent, 0, explorerframe_hinstance, This);
915 if(!This->hwnd_main)
917 ERR("Failed to create the window.\n");
918 return HRESULT_FROM_WIN32(GetLastError());
921 return S_OK;
924 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface,
925 IUnknown *punk,
926 DWORD *pdwCookie)
928 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
929 HRESULT hr;
930 TRACE("%p (%p, %p)\n", This, punk, pdwCookie);
932 *pdwCookie = 0;
934 /* Only one client supported */
935 if(This->pnstce)
936 return E_FAIL;
938 hr = IUnknown_QueryInterface(punk, &IID_INameSpaceTreeControlEvents,(void**)&This->pnstce);
939 if(SUCCEEDED(hr))
941 *pdwCookie = 1;
942 return hr;
945 return E_FAIL;
948 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface,
949 DWORD dwCookie)
951 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
952 TRACE("%p (%x)\n", This, dwCookie);
954 /* The cookie is ignored. */
956 if(This->pnstce)
958 INameSpaceTreeControlEvents_Release(This->pnstce);
959 This->pnstce = NULL;
962 return S_OK;
965 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
966 int iIndex,
967 IShellItem *psiRoot,
968 SHCONTF grfEnumFlags,
969 NSTCROOTSTYLE grfRootStyle,
970 IShellItemFilter *pif)
972 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
973 nstc_root *new_root;
974 struct list *add_after_entry;
975 HTREEITEM add_after_hitem;
976 UINT i;
978 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
980 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
981 if(!new_root)
982 return E_OUTOFMEMORY;
984 new_root->psi = psiRoot;
985 new_root->enum_flags = grfEnumFlags;
986 new_root->root_style = grfRootStyle;
987 new_root->pif = pif;
989 /* We want to keep the roots in the internal list and in the
990 * treeview in the same order. */
991 add_after_entry = &This->roots;
992 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
993 add_after_entry = list_next(&This->roots, add_after_entry);
995 if(add_after_entry == &This->roots)
996 add_after_hitem = TVI_FIRST;
997 else
998 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1000 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1001 if(!new_root->htreeitem)
1003 WARN("Failed to add the root.\n");
1004 HeapFree(GetProcessHeap(), 0, new_root);
1005 return E_FAIL;
1008 list_add_after(add_after_entry, &new_root->entry);
1009 events_OnItemAdded(This, psiRoot, TRUE);
1011 if(grfRootStyle & NSTCRS_HIDDEN)
1013 TVITEMEXW tvi;
1014 tvi.mask = TVIF_STATEEX;
1015 tvi.uStateEx = TVIS_EX_FLAT;
1016 tvi.hItem = new_root->htreeitem;
1018 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1021 if(grfRootStyle & NSTCRS_EXPANDED)
1022 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1023 (LPARAM)new_root->htreeitem);
1025 return S_OK;
1028 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1029 IShellItem *psiRoot,
1030 SHCONTF grfEnumFlags,
1031 NSTCROOTSTYLE grfRootStyle,
1032 IShellItemFilter *pif)
1034 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1035 UINT root_count;
1036 TRACE("%p, %p, %x, %x, %p\n",
1037 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1039 root_count = list_count(&This->roots);
1041 return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1044 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1045 IShellItem *psiRoot)
1047 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1048 nstc_root *cursor, *root = NULL;
1049 TRACE("%p (%p)\n", This, psiRoot);
1051 if(!psiRoot)
1052 return E_NOINTERFACE;
1054 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1056 HRESULT hr;
1057 int order;
1058 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1059 if(hr == S_OK)
1061 root = cursor;
1062 break;
1066 TRACE("root %p\n", root);
1067 if(root)
1069 events_OnItemDeleted(This, root->psi, TRUE);
1070 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1071 list_remove(&root->entry);
1072 HeapFree(GetProcessHeap(), 0, root);
1073 return S_OK;
1075 else
1077 WARN("No matching root found.\n");
1078 return E_FAIL;
1082 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1084 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1085 nstc_root *cur1, *cur2;
1086 UINT removed = 0;
1087 TRACE("%p\n", This);
1089 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1091 NSTC2_fnRemoveRoot(iface, cur1->psi);
1092 removed++;
1095 if(removed)
1096 return S_OK;
1097 else
1098 return E_INVALIDARG;
1101 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1102 IShellItemArray **ppsiaRootItems)
1104 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1105 IShellFolder *psf;
1106 LPITEMIDLIST *array;
1107 nstc_root *root;
1108 UINT count, i;
1109 HRESULT hr;
1110 TRACE("%p (%p)\n", This, ppsiaRootItems);
1112 count = list_count(&This->roots);
1114 if(!count)
1115 return E_INVALIDARG;
1117 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST)*count);
1119 i = 0;
1120 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1121 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1123 SHGetDesktopFolder(&psf);
1124 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1125 ppsiaRootItems);
1126 IShellFolder_Release(psf);
1128 for(i = 0; i < count; i++)
1129 ILFree(array[i]);
1131 HeapFree(GetProcessHeap(), 0, array);
1133 return hr;
1136 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1137 IShellItem *psi,
1138 NSTCITEMSTATE nstcisMask,
1139 NSTCITEMSTATE nstcisFlags)
1141 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1142 TVITEMEXW tvi;
1143 HTREEITEM hitem;
1145 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1147 hitem = treeitem_from_shellitem(This, psi);
1148 if(!hitem) return E_INVALIDARG;
1150 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1151 in two TVM_SETITEMW's */
1152 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1154 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1155 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1157 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1159 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1162 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1163 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1165 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1166 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1169 if(nstcisMask & NSTCIS_DISABLED)
1170 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1171 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1172 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1173 (nstcisFlags & NSTCIS_DISABLED) )
1174 tvi.mask = TVIF_STATE;
1175 else
1176 tvi.mask = 0;
1178 if(tvi.mask)
1180 tvi.stateMask = tvi.state = 0;
1181 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1182 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1183 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1185 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1187 tvi.stateMask = 0;
1190 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1191 tvi.hItem = hitem;
1193 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1196 return S_OK;
1199 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1200 IShellItem *psi,
1201 NSTCITEMSTATE nstcisMask,
1202 NSTCITEMSTATE *pnstcisFlags)
1204 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1205 HTREEITEM hitem;
1206 TVITEMEXW tvi;
1207 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1209 hitem = treeitem_from_shellitem(This, psi);
1210 if(!hitem)
1211 return E_INVALIDARG;
1213 *pnstcisFlags = 0;
1215 tvi.hItem = hitem;
1216 tvi.mask = TVIF_STATE;
1217 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1219 if(nstcisMask & NSTCIS_DISABLED)
1220 tvi.mask |= TVIF_STATEEX;
1222 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1223 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1224 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1225 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1226 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1228 *pnstcisFlags &= nstcisMask;
1230 return S_OK;
1233 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1234 IShellItemArray **psiaItems)
1236 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1237 IShellItem *psiselected;
1238 HRESULT hr;
1239 TRACE("%p (%p)\n", This, psiaItems);
1241 psiselected = get_selected_shellitem(This);
1242 if(!psiselected)
1243 return E_FAIL;
1245 hr = SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1246 (void**)psiaItems);
1247 return hr;
1250 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1251 IShellItem *psi,
1252 int *piStateNumber)
1254 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1255 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1256 return E_NOTIMPL;
1259 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1260 IShellItem *psi,
1261 int iStateNumber)
1263 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1264 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1265 return E_NOTIMPL;
1268 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1269 IShellItem *psi)
1271 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1272 HTREEITEM hitem;
1274 TRACE("%p (%p)\n", This, psi);
1276 hitem = treeitem_from_shellitem(This, psi);
1277 if(hitem)
1279 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1280 return S_OK;
1283 return E_INVALIDARG;
1286 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1287 LPCWSTR pszTheme)
1289 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1290 FIXME("stub, %p (%p)\n", This, pszTheme);
1291 return E_NOTIMPL;
1294 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1295 IShellItem *psi,
1296 NSTCGNI nstcgi,
1297 IShellItem **ppsiNext)
1299 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1300 HTREEITEM hitem, hnext;
1301 UINT tvgn;
1302 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1304 if(!ppsiNext) return E_POINTER;
1305 if(!psi) return E_FAIL;
1307 *ppsiNext = NULL;
1309 hitem = treeitem_from_shellitem(This, psi);
1310 if(!hitem)
1311 return E_INVALIDARG;
1313 switch(nstcgi)
1315 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1316 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1317 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1318 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1319 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1320 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1321 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1322 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1323 default:
1324 FIXME("Unknown nstcgi value %d\n", nstcgi);
1325 return E_FAIL;
1328 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1329 if(hnext)
1331 *ppsiNext = shellitem_from_treeitem(This, hnext);
1332 IShellItem_AddRef(*ppsiNext);
1333 return S_OK;
1336 return E_FAIL;
1339 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1340 POINT *ppt,
1341 IShellItem **ppsiOut)
1343 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1344 HTREEITEM hitem;
1345 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1347 if(!ppt || !ppsiOut)
1348 return E_POINTER;
1350 *ppsiOut = NULL;
1352 hitem = treeitem_from_point(This, ppt, NULL);
1353 if(hitem)
1354 *ppsiOut = shellitem_from_treeitem(This, hitem);
1356 if(*ppsiOut)
1358 IShellItem_AddRef(*ppsiOut);
1359 return S_OK;
1362 return S_FALSE;
1365 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1366 IShellItem *psi,
1367 RECT *prect)
1369 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1370 HTREEITEM hitem;
1371 TRACE("%p (%p, %p)\n", This, psi, prect);
1373 if(!psi || !prect)
1374 return E_POINTER;
1376 hitem = treeitem_from_shellitem(This, psi);
1377 if(hitem)
1379 *(HTREEITEM*)prect = hitem;
1380 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1382 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1383 return S_OK;
1387 return E_INVALIDARG;
1390 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1392 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1393 nstc_root *root;
1394 TRACE("%p\n", This);
1396 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1397 collapse_all(This, root->htreeitem);
1399 return S_OK;
1402 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1403 NSTCSTYLE nstcsMask,
1404 NSTCSTYLE nstcsStyle)
1406 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1407 static const DWORD tv_style_flags =
1408 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1409 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1410 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1411 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1412 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1413 static const DWORD nstc_flags =
1414 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1415 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1416 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1417 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1419 /* Fail if there is an attempt to set an unknown style. */
1420 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1421 return E_FAIL;
1423 if(nstcsMask & tv_style_flags)
1425 DWORD new_style;
1426 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1427 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1430 /* Flags affecting the host window */
1431 if(nstcsMask & NSTCS_BORDER)
1433 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1434 new_style &= ~WS_BORDER;
1435 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1436 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1438 if(nstcsMask & NSTCS_TABSTOP)
1440 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1441 new_style &= ~WS_EX_CONTROLPARENT;
1442 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1443 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1446 if((nstcsStyle & nstcsMask) & unsupported_styles)
1447 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1448 (nstcsStyle & nstcsMask),
1449 (nstcsStyle & nstcsMask) & unsupported_styles);
1451 This->style &= ~nstcsMask;
1452 This->style |= (nstcsStyle & nstcsMask);
1454 return S_OK;
1457 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1458 NSTCSTYLE nstcsMask,
1459 NSTCSTYLE *pnstcsStyle)
1461 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1462 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1464 *pnstcsStyle = (This->style & nstcsMask);
1466 return S_OK;
1469 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1470 NSTCSTYLE2 nstcsMask,
1471 NSTCSTYLE2 nstcsStyle)
1473 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1474 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1476 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1477 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1478 (nstcsStyle & nstcsMask),
1479 (nstcsStyle & nstcsMask) & unsupported_styles2);
1481 This->style2 &= ~nstcsMask;
1482 This->style2 |= (nstcsStyle & nstcsMask);
1484 return S_OK;
1487 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1488 NSTCSTYLE2 nstcsMask,
1489 NSTCSTYLE2 *pnstcsStyle)
1491 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1492 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1494 *pnstcsStyle = (This->style2 & nstcsMask);
1496 return S_OK;
1499 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1500 NSTC2_fnQueryInterface,
1501 NSTC2_fnAddRef,
1502 NSTC2_fnRelease,
1503 NSTC2_fnInitialize,
1504 NSTC2_fnTreeAdvise,
1505 NSTC2_fnTreeUnadvise,
1506 NSTC2_fnAppendRoot,
1507 NSTC2_fnInsertRoot,
1508 NSTC2_fnRemoveRoot,
1509 NSTC2_fnRemoveAllRoots,
1510 NSTC2_fnGetRootItems,
1511 NSTC2_fnSetItemState,
1512 NSTC2_fnGetItemState,
1513 NSTC2_fnGetSelectedItems,
1514 NSTC2_fnGetItemCustomState,
1515 NSTC2_fnSetItemCustomState,
1516 NSTC2_fnEnsureItemVisible,
1517 NSTC2_fnSetTheme,
1518 NSTC2_fnGetNextItem,
1519 NSTC2_fnHitTest,
1520 NSTC2_fnGetItemRect,
1521 NSTC2_fnCollapseAll,
1522 NSTC2_fnSetControlStyle,
1523 NSTC2_fnGetControlStyle,
1524 NSTC2_fnSetControlStyle2,
1525 NSTC2_fnGetControlStyle2
1528 /**************************************************************************
1529 * IOleWindow Implementation
1532 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1534 NSTC2Impl *This = impl_from_IOleWindow(iface);
1535 TRACE("%p\n", This);
1536 return NSTC2_fnQueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1539 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1541 NSTC2Impl *This = impl_from_IOleWindow(iface);
1542 TRACE("%p\n", This);
1543 return NSTC2_fnAddRef(&This->INameSpaceTreeControl2_iface);
1546 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1548 NSTC2Impl *This = impl_from_IOleWindow(iface);
1549 TRACE("%p\n", This);
1550 return NSTC2_fnRelease(&This->INameSpaceTreeControl2_iface);
1553 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1555 NSTC2Impl *This = impl_from_IOleWindow(iface);
1556 TRACE("%p (%p)\n", This, phwnd);
1558 *phwnd = This->hwnd_main;
1559 return S_OK;
1562 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1564 NSTC2Impl *This = impl_from_IOleWindow(iface);
1565 TRACE("%p (%d)\n", This, fEnterMode);
1567 /* Not implemented */
1568 return E_NOTIMPL;
1571 static const IOleWindowVtbl vt_IOleWindow = {
1572 IOW_fnQueryInterface,
1573 IOW_fnAddRef,
1574 IOW_fnRelease,
1575 IOW_fnGetWindow,
1576 IOW_fnContextSensitiveHelp
1579 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1581 NSTC2Impl *nstc;
1582 HRESULT ret;
1584 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1586 if(!ppv)
1587 return E_POINTER;
1588 if(pUnkOuter)
1589 return CLASS_E_NOAGGREGATION;
1591 EFRAME_LockModule();
1593 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1594 nstc->ref = 1;
1595 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1596 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1598 list_init(&nstc->roots);
1600 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1601 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1603 TRACE("--(%p)\n", ppv);
1604 return ret;