crypt32: Avoid relying on PATH_MAX in import_certs_from_dir helper.
[wine/multimedia.git] / dlls / explorerframe / nstc.c
blob6ae1458672ed4f6d28fd14ceeea94ff059ef2826
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 const INameSpaceTreeControl2Vtbl *lpVtbl;
51 const IOleWindowVtbl *lpowVtbl;
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 /* Forward declarations */
75 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
77 /*************************************************************************
78 * NamespaceTree event wrappers
80 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
81 int *piDefaultIcon, int *piOpenIcon)
83 HRESULT ret;
84 LONG refcount;
85 if(!This->pnstce) return E_NOTIMPL;
87 refcount = IShellItem_AddRef(psi);
88 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->pnstce, psi, piDefaultIcon, piOpenIcon);
89 if(IShellItem_Release(psi) < refcount - 1)
90 ERR("ShellItem was released by client - please file a bug.\n");
91 return ret;
94 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
96 HRESULT ret;
97 LONG refcount;
98 if(!This->pnstce) return S_OK;
100 refcount = IShellItem_AddRef(psi);
101 ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
102 if(IShellItem_Release(psi) < refcount - 1)
103 ERR("ShellItem was released by client - please file a bug.\n");
104 return ret;
107 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
109 HRESULT ret;
110 LONG refcount;
111 if(!This->pnstce) return S_OK;
113 refcount = IShellItem_AddRef(psi);
114 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->pnstce, psi, fIsRoot);
115 if(IShellItem_Release(psi) < refcount - 1)
116 ERR("ShellItem was released by client - please file a bug.\n");
117 return ret;
120 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
122 HRESULT ret;
123 LONG refcount;
124 if(!This->pnstce) return S_OK;
126 refcount = IShellItem_AddRef(psi);
127 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->pnstce, psi);
128 if(IShellItem_Release(psi) < refcount - 1)
129 ERR("ShellItem was released by client - please file a bug.\n");
130 return ret;
133 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
135 HRESULT ret;
136 LONG refcount;
137 if(!This->pnstce) return S_OK;
139 refcount = IShellItem_AddRef(psi);
140 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->pnstce, psi);
141 if(IShellItem_Release(psi) < refcount - 1)
142 ERR("ShellItem was released by client - please file a bug.\n");
143 return ret;
146 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
147 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
149 HRESULT ret;
150 LONG refcount;
151 if(!This->pnstce) return S_OK;
153 refcount = IShellItem_AddRef(psi);
154 ret = INameSpaceTreeControlEvents_OnItemClick(This->pnstce, psi, nstceHitTest, nstceClickType);
155 if(IShellItem_Release(psi) < refcount - 1)
156 ERR("ShellItem was released by client - please file a bug.\n");
157 return ret;
160 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
162 if(!This->pnstce) return S_OK;
164 return INameSpaceTreeControlEvents_OnSelectionChanged(This->pnstce, psia);
167 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
169 if(!This->pnstce) return S_OK;
171 return INameSpaceTreeControlEvents_OnKeyboardInput(This->pnstce, uMsg, wParam, lParam);
174 /*************************************************************************
175 * NamespaceTree helper functions
177 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
178 NSTCSTYLE nstcs_mask, DWORD *new_style)
180 DWORD old_style, tv_mask = 0;
181 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
183 if(This->hwnd_tv)
184 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
185 else
186 old_style = /* The default */
187 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
188 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
189 TVS_EDITLABELS | TVS_TRACKSELECT;
191 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
192 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
193 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
194 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
195 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
196 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
197 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
198 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
199 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
200 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
201 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
203 *new_style = 0;
205 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
206 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
207 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
208 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
209 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
210 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
211 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
212 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
213 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
214 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
215 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
217 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
219 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
221 return old_style^*new_style;
224 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
226 TVITEMEXW tvi;
228 tvi.mask = TVIF_PARAM;
229 tvi.lParam = 0;
230 tvi.hItem = hitem;
232 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
234 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
235 return (IShellItem*)tvi.lParam;
238 /* Returns the root that the given treeitem belongs to. */
239 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
241 HTREEITEM tmp, hroot = hitem;
242 nstc_root *root;
244 /* Work our way up the hierarchy */
245 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
246 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
248 /* Search through the list of roots for a match */
249 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
250 if(root->htreeitem == hroot)
251 break;
253 TRACE("root is %p\n", root);
254 return root;
257 /* Find a shellitem in the tree, starting from the given node. */
258 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
259 IShellItem *psi)
261 IShellItem *psi_node;
262 HTREEITEM next, result = NULL;
263 HRESULT hr;
264 int cmpo;
265 TRACE("%p, %p, %p\n", This, node, psi);
267 /* Check this node */
268 psi_node = shellitem_from_treeitem(This, node);
269 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
270 if(hr == S_OK)
271 return node;
273 /* Any children? */
274 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
275 TVGN_CHILD, (LPARAM)node);
276 if(next)
278 result = search_for_shellitem(This, next, psi);
279 if(result) return result;
282 /* Try our next sibling. */
283 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
284 TVGN_NEXT, (LPARAM)node);
285 if(next)
286 result = search_for_shellitem(This, next, psi);
288 return result;
291 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
293 HTREEITEM root;
294 TRACE("%p, %p\n", This, psi);
296 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
297 TVGN_ROOT, 0);
298 if(!root)
299 return NULL;
301 return search_for_shellitem(This, root, psi);
304 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
306 SHFILEINFOW sfi;
307 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
308 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
309 return sfi.iIcon;
312 /* Insert a shellitem into the given place in the tree and return the
313 resulting treeitem. */
314 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
315 HTREEITEM hParent, HTREEITEM hInsertAfter)
317 TVINSERTSTRUCTW tvins;
318 TVITEMEXW *tvi = &tvins.u.itemex;
319 HTREEITEM hinserted;
320 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
322 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
323 tvi->cChildren = I_CHILDRENCALLBACK;
324 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
325 tvi->pszText = LPSTR_TEXTCALLBACKW;
327 /* Every treeitem contains a pointer to the corresponding ShellItem. */
328 tvi->lParam = (LPARAM)psi;
329 tvins.hParent = hParent;
330 tvins.hInsertAfter = hInsertAfter;
332 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
333 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
334 if(hinserted)
335 IShellItem_AddRef(psi);
337 return hinserted;
340 /* Enumerates the children of the folder represented by hitem
341 * according to the settings for the root, and adds them to the
342 * treeview. Returns the number of children added. */
343 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
345 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
346 nstc_root *root = root_for_treeitem(This, hitem);
347 LPITEMIDLIST pidl_parent;
348 IShellFolder *psf;
349 IEnumIDList *peidl;
350 UINT added = 0;
351 HRESULT hr;
353 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
354 if(SUCCEEDED(hr))
356 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
357 if(SUCCEEDED(hr))
359 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
360 if(SUCCEEDED(hr))
362 LPITEMIDLIST pidl;
363 IShellItem *psi;
364 ULONG fetched;
366 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
368 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
369 ILFree(pidl);
370 if(SUCCEEDED(hr))
372 if(insert_shellitem(This, psi, hitem, NULL))
374 events_OnItemAdded(This, psi, FALSE);
375 added++;
378 IShellItem_Release(psi);
380 else
381 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
383 IEnumIDList_Release(peidl);
385 else
386 ERR("EnumObjects failed with 0x%08x\n", hr);
388 IShellFolder_Release(psf);
390 else
391 ERR("BindToHandler failed with 0x%08x\n", hr);
393 ILFree(pidl_parent);
395 else
396 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
398 return added;
401 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
403 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
406 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
408 return shellitem_from_treeitem(This, get_selected_treeitem(This));
411 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
413 HTREEITEM next;
415 /* Collapse this node first, and then first child/next sibling. */
416 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
418 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
419 if(next) collapse_all(This, next);
421 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
422 if(next) collapse_all(This, next);
425 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
427 TVHITTESTINFO tviht;
428 tviht.pt.x = pt->x;
429 tviht.pt.y = pt->y;
430 tviht.hItem = NULL;
432 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
433 if(hitflag) *hitflag = tviht.flags;
434 return tviht.hItem;
437 /*************************************************************************
438 * NamespaceTree window functions
440 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
442 NSTC2Impl *This = crs->lpCreateParams;
443 HIMAGELIST ShellSmallIconList;
444 DWORD treeview_style, treeview_ex_style;
446 TRACE("%p (%p)\n", This, crs);
447 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
448 This->hwnd_main = hWnd;
450 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
452 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
453 0, 0, crs->cx, crs->cy,
454 hWnd, NULL, explorerframe_hinstance, NULL);
456 if(!This->hwnd_tv)
458 ERR("Failed to create treeview!\n");
459 return HRESULT_FROM_WIN32(GetLastError());
462 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
463 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
465 if(This->style & NSTCS_AUTOHSCROLL)
466 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
467 if(This->style & NSTCS_FADEINOUTEXPANDOS)
468 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
469 if(This->style & NSTCS_PARTIALCHECKBOXES)
470 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
471 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
472 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
473 if(This->style & NSTCS_DIMMEDCHECKBOXES)
474 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
476 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
478 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
480 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
481 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
483 else
485 ERR("Failed to get the System Image List.\n");
488 INameSpaceTreeControl_AddRef((INameSpaceTreeControl*)This);
490 /* Subclass the treeview to get the keybord events. */
491 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
492 (ULONG_PTR)tv_wndproc);
493 if(This->tv_oldwndproc)
494 SetPropA(This->hwnd_tv, "PROP_THIS", This);
496 return TRUE;
499 static LRESULT resize_namespacetree(NSTC2Impl *This)
501 RECT rc;
502 TRACE("%p\n", This);
504 GetClientRect(This->hwnd_main, &rc);
505 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
507 return TRUE;
510 static LRESULT destroy_namespacetree(NSTC2Impl *This)
512 TRACE("%p\n", This);
514 /* Undo the subclassing */
515 if(This->tv_oldwndproc)
517 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
518 RemovePropA(This->hwnd_tv, "PROP_THIS");
521 INameSpaceTreeControl_RemoveAllRoots((INameSpaceTreeControl*)This);
523 /* This reference was added in create_namespacetree */
524 INameSpaceTreeControl_Release((INameSpaceTreeControl*)This);
525 return TRUE;
528 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
530 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
531 TRACE("%p\n", This);
533 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
534 return TRUE;
537 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
539 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
540 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
541 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
542 HRESULT hr;
544 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
546 if(item->mask & TVIF_CHILDREN)
548 SFGAOF sfgao;
550 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
551 if(SUCCEEDED(hr))
552 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
553 else
554 item->cChildren = 1;
556 item->mask |= TVIF_DI_SETITEM;
559 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
561 LPITEMIDLIST pidl;
563 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
564 if(FAILED(hr))
566 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
567 if(SUCCEEDED(hr))
569 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
570 item->mask |= TVIF_DI_SETITEM;
571 ILFree(pidl);
573 else
574 ERR("Failed to get IDList (%08x).\n", hr);
578 if(item->mask & TVIF_TEXT)
580 LPWSTR display_name;
582 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
583 if(SUCCEEDED(hr))
585 lstrcpynW(item->pszText, display_name, MAX_PATH);
586 item->mask |= TVIF_DI_SETITEM;
587 CoTaskMemFree(display_name);
589 else
590 ERR("Failed to get display name (%08x).\n", hr);
593 return TRUE;
596 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
598 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
601 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
603 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
604 IShellItem *psi;
605 TRACE("%p\n", This);
607 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
608 events_OnBeforeExpand(This, psi);
610 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
612 /* The node has no children, try to find some */
613 if(!fill_sublevel(This, nmtv->itemNew.hItem))
615 TVITEMEXW tvi;
616 /* Failed to enumerate any children, remove the expando
617 * (if any). */
618 tvi.hItem = nmtv->itemNew.hItem;
619 tvi.mask = TVIF_CHILDREN;
620 tvi.cChildren = 0;
621 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
623 return TRUE;
626 return FALSE;
629 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
631 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
632 IShellItem *psi;
633 TRACE("%p\n", This);
635 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
636 events_OnAfterExpand(This, psi);
637 return TRUE;
640 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
642 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
643 IShellItemArray *psia;
644 IShellItem *psi;
645 HRESULT hr;
646 TRACE("%p\n", This);
648 /* Note: Only supports one selected item. */
649 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
650 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
651 if(SUCCEEDED(hr))
653 events_OnSelectionChanged(This, psia);
654 IShellItemArray_Release(psia);
657 return TRUE;
660 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
662 TVHITTESTINFO tvhit;
663 IShellItem *psi;
664 HRESULT hr;
665 TRACE("%p (%p)\n", This, nmhdr);
667 GetCursorPos(&tvhit.pt);
668 ScreenToClient(This->hwnd_tv, &tvhit.pt);
669 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
671 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
672 return TRUE;
674 /* TVHT_ maps onto the corresponding NSTCEHT_ */
675 psi = shellitem_from_treeitem(This, tvhit.hItem);
676 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
678 /* The expando should not be expanded unless
679 * double-clicked. */
680 if(tvhit.flags == TVHT_ONITEMBUTTON)
681 return TRUE;
683 if(SUCCEEDED(hr))
684 return FALSE;
685 else
686 return TRUE;
689 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
691 TVHITTESTINFO tvhit;
692 IShellItem *psi;
693 HRESULT hr;
694 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
696 tvhit.pt.x = (int)(short)LOWORD(lParam);
697 tvhit.pt.y = (int)(short)HIWORD(lParam);
699 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
701 /* Seems to generate only ONITEM and ONITEMICON */
702 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
703 return FALSE;
705 psi = shellitem_from_treeitem(This, tvhit.hItem);
706 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
708 if(SUCCEEDED(hr))
709 return FALSE;
710 else
711 return TRUE;
714 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 IShellItem *psi;
717 HTREEITEM hitem;
718 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
720 /* Handled by the client? */
721 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
722 return TRUE;
724 if(uMsg == WM_KEYDOWN)
726 switch(wParam)
728 case VK_DELETE:
729 psi = get_selected_shellitem(This);
730 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
731 return TRUE;
733 case VK_F2:
734 hitem = get_selected_treeitem(This);
735 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
736 return TRUE;
740 /* Let the TreeView handle the key */
741 return FALSE;
744 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
746 NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS");
748 switch(uMessage) {
749 case WM_KEYDOWN:
750 case WM_KEYUP:
751 case WM_CHAR:
752 case WM_SYSKEYDOWN:
753 case WM_SYSKEYUP:
754 case WM_SYSCHAR:
755 if(on_kbd_event(This, uMessage, wParam, lParam))
756 return TRUE;
757 break;
759 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
762 /* Pass the message on to the treeview */
763 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
766 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
767 WPARAM wParam, LPARAM lParam)
769 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
770 NMHDR *nmhdr;
772 switch(uMessage)
774 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
775 case WM_SIZE: return resize_namespacetree(This);
776 case WM_DESTROY: return destroy_namespacetree(This);
777 case WM_NOTIFY:
778 nmhdr = (NMHDR*)lParam;
779 switch(nmhdr->code)
781 case NM_CLICK: return on_nm_click(This, nmhdr);
782 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
783 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
784 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
785 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
786 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
787 default: break;
789 break;
790 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
792 return 0;
795 /**************************************************************************
796 * INameSpaceTreeControl2 Implementation
798 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
799 REFIID riid,
800 void **ppvObject)
802 NSTC2Impl *This = (NSTC2Impl*)iface;
803 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
805 *ppvObject = NULL;
806 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
807 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
808 IsEqualIID(riid, &IID_IUnknown))
810 *ppvObject = This;
812 else if(IsEqualIID(riid, &IID_IOleWindow))
814 *ppvObject = &This->lpowVtbl;
817 if(*ppvObject)
819 IUnknown_AddRef((IUnknown*)*ppvObject);
820 return S_OK;
823 return E_NOINTERFACE;
826 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
828 NSTC2Impl *This = (NSTC2Impl*)iface;
829 LONG ref = InterlockedIncrement(&This->ref);
831 TRACE("%p - ref %d\n", This, ref);
833 return ref;
836 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
838 NSTC2Impl *This = (NSTC2Impl*)iface;
839 LONG ref = InterlockedDecrement(&This->ref);
841 TRACE("%p - ref: %d\n", This, ref);
843 if(!ref)
845 TRACE("Freeing.\n");
846 HeapFree(GetProcessHeap(), 0, This);
847 EFRAME_UnlockModule();
848 return 0;
851 return ref;
854 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
855 HWND hwndParent,
856 RECT *prc,
857 NSTCSTYLE nstcsFlags)
859 NSTC2Impl *This = (NSTC2Impl*)iface;
860 WNDCLASSW wc;
861 DWORD window_style, window_ex_style;
862 RECT rc;
863 static const WCHAR NSTC2_CLASS_NAME[] =
864 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
865 'C','o','n','t','r','o','l',0};
867 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
869 if(nstcsFlags & unsupported_styles)
870 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
871 nstcsFlags, nstcsFlags & unsupported_styles);
873 This->style = nstcsFlags;
875 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
877 wc.style = CS_HREDRAW | CS_VREDRAW;
878 wc.lpfnWndProc = NSTC2_WndProc;
879 wc.cbClsExtra = 0;
880 wc.cbWndExtra = 0;
881 wc.hInstance = explorerframe_hinstance;
882 wc.hIcon = 0;
883 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
884 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
885 wc.lpszMenuName = NULL;
886 wc.lpszClassName = NSTC2_CLASS_NAME;
888 if (!RegisterClassW(&wc)) return E_FAIL;
891 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
892 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
893 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
894 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
896 if(prc)
897 CopyRect(&rc, prc);
898 else
899 rc.left = rc.right = rc.top = rc.bottom = 0;
901 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
902 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
903 hwndParent, 0, explorerframe_hinstance, This);
905 if(!This->hwnd_main)
907 ERR("Failed to create the window.\n");
908 return HRESULT_FROM_WIN32(GetLastError());
911 return S_OK;
914 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface,
915 IUnknown *punk,
916 DWORD *pdwCookie)
918 NSTC2Impl *This = (NSTC2Impl*)iface;
919 HRESULT hr;
920 TRACE("%p (%p, %p)\n", This, punk, pdwCookie);
922 *pdwCookie = 0;
924 /* Only one client supported */
925 if(This->pnstce)
926 return E_FAIL;
928 hr = IUnknown_QueryInterface(punk, &IID_INameSpaceTreeControlEvents,(void**)&This->pnstce);
929 if(SUCCEEDED(hr))
931 *pdwCookie = 1;
932 return hr;
935 return E_FAIL;
938 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface,
939 DWORD dwCookie)
941 NSTC2Impl *This = (NSTC2Impl*)iface;
942 TRACE("%p (%x)\n", This, dwCookie);
944 /* The cookie is ignored. */
946 if(This->pnstce)
948 INameSpaceTreeControlEvents_Release(This->pnstce);
949 This->pnstce = NULL;
952 return S_OK;
955 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
956 int iIndex,
957 IShellItem *psiRoot,
958 SHCONTF grfEnumFlags,
959 NSTCROOTSTYLE grfRootStyle,
960 IShellItemFilter *pif)
962 NSTC2Impl *This = (NSTC2Impl*)iface;
963 nstc_root *new_root;
964 struct list *add_after_entry;
965 HTREEITEM add_after_hitem;
966 UINT i;
968 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
970 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
971 if(!new_root)
972 return E_OUTOFMEMORY;
974 new_root->psi = psiRoot;
975 new_root->enum_flags = grfEnumFlags;
976 new_root->root_style = grfRootStyle;
977 new_root->pif = pif;
979 /* We want to keep the roots in the internal list and in the
980 * treeview in the same order. */
981 add_after_entry = &This->roots;
982 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
983 add_after_entry = list_next(&This->roots, add_after_entry);
985 if(add_after_entry == &This->roots)
986 add_after_hitem = TVI_FIRST;
987 else
988 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
990 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
991 if(!new_root->htreeitem)
993 WARN("Failed to add the root.\n");
994 HeapFree(GetProcessHeap(), 0, new_root);
995 return E_FAIL;
998 list_add_after(add_after_entry, &new_root->entry);
999 events_OnItemAdded(This, psiRoot, TRUE);
1001 if(grfRootStyle & NSTCRS_HIDDEN)
1003 TVITEMEXW tvi;
1004 tvi.mask = TVIF_STATEEX;
1005 tvi.uStateEx = TVIS_EX_FLAT;
1006 tvi.hItem = new_root->htreeitem;
1008 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1011 if(grfRootStyle & NSTCRS_EXPANDED)
1012 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1013 (LPARAM)new_root->htreeitem);
1015 return S_OK;
1018 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1019 IShellItem *psiRoot,
1020 SHCONTF grfEnumFlags,
1021 NSTCROOTSTYLE grfRootStyle,
1022 IShellItemFilter *pif)
1024 NSTC2Impl *This = (NSTC2Impl*)iface;
1025 UINT root_count;
1026 TRACE("%p, %p, %x, %x, %p\n",
1027 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1029 root_count = list_count(&This->roots);
1031 return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1034 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1035 IShellItem *psiRoot)
1037 NSTC2Impl *This = (NSTC2Impl*)iface;
1038 nstc_root *cursor, *root = NULL;
1039 TRACE("%p (%p)\n", This, psiRoot);
1041 if(!psiRoot)
1042 return E_NOINTERFACE;
1044 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1046 HRESULT hr;
1047 int order;
1048 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1049 if(hr == S_OK)
1051 root = cursor;
1052 break;
1056 TRACE("root %p\n", root);
1057 if(root)
1059 events_OnItemDeleted(This, root->psi, TRUE);
1060 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1061 list_remove(&root->entry);
1062 HeapFree(GetProcessHeap(), 0, root);
1063 return S_OK;
1065 else
1067 WARN("No matching root found.\n");
1068 return E_FAIL;
1072 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1074 NSTC2Impl *This = (NSTC2Impl*)iface;
1075 nstc_root *cur1, *cur2;
1076 UINT removed = 0;
1077 TRACE("%p\n", This);
1079 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1081 NSTC2_fnRemoveRoot(iface, cur1->psi);
1082 removed++;
1085 if(removed)
1086 return S_OK;
1087 else
1088 return E_INVALIDARG;
1091 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1092 IShellItemArray **ppsiaRootItems)
1094 NSTC2Impl *This = (NSTC2Impl*)iface;
1095 IShellFolder *psf;
1096 LPITEMIDLIST *array;
1097 nstc_root *root;
1098 UINT count, i;
1099 HRESULT hr;
1100 TRACE("%p (%p)\n", This, ppsiaRootItems);
1102 count = list_count(&This->roots);
1104 if(!count)
1105 return E_INVALIDARG;
1107 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST*)*count);
1109 i = 0;
1110 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1111 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1113 SHGetDesktopFolder(&psf);
1114 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1115 ppsiaRootItems);
1116 IShellFolder_Release(psf);
1118 for(i = 0; i < count; i++)
1119 ILFree(array[i]);
1121 HeapFree(GetProcessHeap(), 0, array);
1123 return hr;
1126 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1127 IShellItem *psi,
1128 NSTCITEMSTATE nstcisMask,
1129 NSTCITEMSTATE nstcisFlags)
1131 NSTC2Impl *This = (NSTC2Impl*)iface;
1132 TVITEMEXW tvi;
1133 HTREEITEM hitem;
1135 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1137 hitem = treeitem_from_shellitem(This, psi);
1138 if(!hitem) return E_INVALIDARG;
1140 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1141 in two TVM_SETITEMW's */
1142 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1144 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1145 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1147 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1149 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1152 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1153 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1155 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1156 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1159 if(nstcisMask & NSTCIS_DISABLED)
1160 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1161 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1162 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1163 (nstcisFlags & NSTCIS_DISABLED) )
1164 tvi.mask = TVIF_STATE;
1165 else
1166 tvi.mask = 0;
1168 if(tvi.mask)
1170 tvi.stateMask = tvi.state = 0;
1171 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1172 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1173 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1175 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1177 tvi.stateMask = 0;
1180 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1181 tvi.hItem = hitem;
1183 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1186 return S_OK;
1189 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1190 IShellItem *psi,
1191 NSTCITEMSTATE nstcisMask,
1192 NSTCITEMSTATE *pnstcisFlags)
1194 NSTC2Impl *This = (NSTC2Impl*)iface;
1195 HTREEITEM hitem;
1196 TVITEMEXW tvi;
1197 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1199 hitem = treeitem_from_shellitem(This, psi);
1200 if(!hitem)
1201 return E_INVALIDARG;
1203 *pnstcisFlags = 0;
1205 tvi.hItem = hitem;
1206 tvi.mask = TVIF_STATE;
1207 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1209 if(nstcisMask & NSTCIS_DISABLED)
1210 tvi.mask |= TVIF_STATEEX;
1212 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1213 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1214 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1215 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1216 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1218 *pnstcisFlags &= nstcisMask;
1220 return S_OK;
1223 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1224 IShellItemArray **psiaItems)
1226 NSTC2Impl *This = (NSTC2Impl*)iface;
1227 IShellItem *psiselected;
1228 HRESULT hr;
1229 TRACE("%p (%p)\n", This, psiaItems);
1231 psiselected = get_selected_shellitem(This);
1232 if(!psiselected)
1233 return E_FAIL;
1235 hr = SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1236 (void**)psiaItems);
1237 return hr;
1240 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1241 IShellItem *psi,
1242 int *piStateNumber)
1244 NSTC2Impl *This = (NSTC2Impl*)iface;
1245 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1246 return E_NOTIMPL;
1249 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1250 IShellItem *psi,
1251 int iStateNumber)
1253 NSTC2Impl *This = (NSTC2Impl*)iface;
1254 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1255 return E_NOTIMPL;
1258 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1259 IShellItem *psi)
1261 NSTC2Impl *This = (NSTC2Impl*)iface;
1262 HTREEITEM hitem;
1264 TRACE("%p (%p)\n", This, psi);
1266 hitem = treeitem_from_shellitem(This, psi);
1267 if(hitem)
1269 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1270 return S_OK;
1273 return E_INVALIDARG;
1276 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1277 LPCWSTR pszTheme)
1279 NSTC2Impl *This = (NSTC2Impl*)iface;
1280 FIXME("stub, %p (%p)\n", This, pszTheme);
1281 return E_NOTIMPL;
1284 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1285 IShellItem *psi,
1286 NSTCGNI nstcgi,
1287 IShellItem **ppsiNext)
1289 NSTC2Impl *This = (NSTC2Impl*)iface;
1290 HTREEITEM hitem, hnext;
1291 UINT tvgn;
1292 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1294 if(!ppsiNext) return E_POINTER;
1295 if(!psi) return E_FAIL;
1297 *ppsiNext = NULL;
1299 hitem = treeitem_from_shellitem(This, psi);
1300 if(!hitem)
1301 return E_INVALIDARG;
1303 switch(nstcgi)
1305 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1306 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1307 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1308 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1309 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1310 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1311 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1312 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1313 default:
1314 FIXME("Unknown nstcgi value %d\n", nstcgi);
1315 return E_FAIL;
1318 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1319 if(hnext)
1321 *ppsiNext = shellitem_from_treeitem(This, hnext);
1322 IShellItem_AddRef(*ppsiNext);
1323 return S_OK;
1326 return E_FAIL;
1329 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1330 POINT *ppt,
1331 IShellItem **ppsiOut)
1333 NSTC2Impl *This = (NSTC2Impl*)iface;
1334 HTREEITEM hitem;
1335 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1337 if(!ppt || !ppsiOut)
1338 return E_POINTER;
1340 *ppsiOut = NULL;
1342 hitem = treeitem_from_point(This, ppt, NULL);
1343 if(hitem)
1344 *ppsiOut = shellitem_from_treeitem(This, hitem);
1346 if(*ppsiOut)
1348 IShellItem_AddRef(*ppsiOut);
1349 return S_OK;
1352 return S_FALSE;
1355 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1356 IShellItem *psi,
1357 RECT *prect)
1359 NSTC2Impl *This = (NSTC2Impl*)iface;
1360 HTREEITEM hitem;
1361 TRACE("%p (%p, %p)\n", This, psi, prect);
1363 if(!psi || !prect)
1364 return E_POINTER;
1366 hitem = treeitem_from_shellitem(This, psi);
1367 if(hitem)
1369 *(HTREEITEM*)prect = hitem;
1370 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1372 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1373 return S_OK;
1377 return E_INVALIDARG;
1380 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1382 NSTC2Impl *This = (NSTC2Impl*)iface;
1383 nstc_root *root;
1384 TRACE("%p\n", This);
1386 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1387 collapse_all(This, root->htreeitem);
1389 return S_OK;
1392 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1393 NSTCSTYLE nstcsMask,
1394 NSTCSTYLE nstcsStyle)
1396 NSTC2Impl *This = (NSTC2Impl*)iface;
1397 static const DWORD tv_style_flags =
1398 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1399 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1400 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1401 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1402 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1403 static const DWORD nstc_flags =
1404 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1405 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1406 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1407 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1409 /* Fail if there is an attempt to set an unknown style. */
1410 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1411 return E_FAIL;
1413 if(nstcsMask & tv_style_flags)
1415 DWORD new_style;
1416 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1417 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1420 /* Flags affecting the host window */
1421 if(nstcsMask & NSTCS_BORDER)
1423 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1424 new_style &= ~WS_BORDER;
1425 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1426 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1428 if(nstcsMask & NSTCS_TABSTOP)
1430 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1431 new_style &= ~WS_EX_CONTROLPARENT;
1432 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1433 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1436 if((nstcsStyle & nstcsMask) & unsupported_styles)
1437 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1438 (nstcsStyle & nstcsMask),
1439 (nstcsStyle & nstcsMask) & unsupported_styles);
1441 This->style &= ~nstcsMask;
1442 This->style |= (nstcsStyle & nstcsMask);
1444 return S_OK;
1447 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1448 NSTCSTYLE nstcsMask,
1449 NSTCSTYLE *pnstcsStyle)
1451 NSTC2Impl *This = (NSTC2Impl*)iface;
1452 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1454 *pnstcsStyle = (This->style & nstcsMask);
1456 return S_OK;
1459 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1460 NSTCSTYLE2 nstcsMask,
1461 NSTCSTYLE2 nstcsStyle)
1463 NSTC2Impl *This = (NSTC2Impl*)iface;
1464 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1466 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1467 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1468 (nstcsStyle & nstcsMask),
1469 (nstcsStyle & nstcsMask) & unsupported_styles2);
1471 This->style2 &= ~nstcsMask;
1472 This->style2 |= (nstcsStyle & nstcsMask);
1474 return S_OK;
1477 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1478 NSTCSTYLE2 nstcsMask,
1479 NSTCSTYLE2 *pnstcsStyle)
1481 NSTC2Impl *This = (NSTC2Impl*)iface;
1482 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1484 *pnstcsStyle = (This->style2 & nstcsMask);
1486 return S_OK;
1489 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1490 NSTC2_fnQueryInterface,
1491 NSTC2_fnAddRef,
1492 NSTC2_fnRelease,
1493 NSTC2_fnInitialize,
1494 NSTC2_fnTreeAdvise,
1495 NSTC2_fnTreeUnadvise,
1496 NSTC2_fnAppendRoot,
1497 NSTC2_fnInsertRoot,
1498 NSTC2_fnRemoveRoot,
1499 NSTC2_fnRemoveAllRoots,
1500 NSTC2_fnGetRootItems,
1501 NSTC2_fnSetItemState,
1502 NSTC2_fnGetItemState,
1503 NSTC2_fnGetSelectedItems,
1504 NSTC2_fnGetItemCustomState,
1505 NSTC2_fnSetItemCustomState,
1506 NSTC2_fnEnsureItemVisible,
1507 NSTC2_fnSetTheme,
1508 NSTC2_fnGetNextItem,
1509 NSTC2_fnHitTest,
1510 NSTC2_fnGetItemRect,
1511 NSTC2_fnCollapseAll,
1512 NSTC2_fnSetControlStyle,
1513 NSTC2_fnGetControlStyle,
1514 NSTC2_fnSetControlStyle2,
1515 NSTC2_fnGetControlStyle2
1518 /**************************************************************************
1519 * IOleWindow Implementation
1522 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
1524 return (NSTC2Impl *)((char*)iface - FIELD_OFFSET(NSTC2Impl, lpowVtbl));
1527 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1529 NSTC2Impl *This = impl_from_IOleWindow(iface);
1530 TRACE("%p\n", This);
1531 return NSTC2_fnQueryInterface((INameSpaceTreeControl2*)This, riid, ppvObject);
1534 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1536 NSTC2Impl *This = impl_from_IOleWindow(iface);
1537 TRACE("%p\n", This);
1538 return NSTC2_fnAddRef((INameSpaceTreeControl2*)This);
1541 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1543 NSTC2Impl *This = impl_from_IOleWindow(iface);
1544 TRACE("%p\n", This);
1545 return NSTC2_fnRelease((INameSpaceTreeControl2*)This);
1548 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1550 NSTC2Impl *This = impl_from_IOleWindow(iface);
1551 TRACE("%p (%p)\n", This, phwnd);
1553 *phwnd = This->hwnd_main;
1554 return S_OK;
1557 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1559 NSTC2Impl *This = impl_from_IOleWindow(iface);
1560 TRACE("%p (%d)\n", This, fEnterMode);
1562 /* Not implemented */
1563 return E_NOTIMPL;
1566 static const IOleWindowVtbl vt_IOleWindow = {
1567 IOW_fnQueryInterface,
1568 IOW_fnAddRef,
1569 IOW_fnRelease,
1570 IOW_fnGetWindow,
1571 IOW_fnContextSensitiveHelp
1574 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1576 NSTC2Impl *nstc;
1577 HRESULT ret;
1579 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1581 if(!ppv)
1582 return E_POINTER;
1583 if(pUnkOuter)
1584 return CLASS_E_NOAGGREGATION;
1586 EFRAME_LockModule();
1588 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1589 nstc->ref = 1;
1590 nstc->lpVtbl = &vt_INameSpaceTreeControl2;
1591 nstc->lpowVtbl = &vt_IOleWindow;
1593 list_init(&nstc->roots);
1595 ret = INameSpaceTreeControl_QueryInterface((INameSpaceTreeControl*)nstc, riid, ppv);
1596 INameSpaceTreeControl_Release((INameSpaceTreeControl*)nstc);
1598 TRACE("--(%p)\n", ppv);
1599 return ret;