d3d8: Get rid of the format switching code in d3d8_device_CopyRects().
[wine.git] / dlls / explorerframe / nstc.c
blob9daee8b3b8d18bd20336ddf0e7e700263cab8f25
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 INameSpaceTreeControlCustomDraw *customdraw;
64 INameSpaceTreeControlDropHandler *dragdrop;
65 INameSpaceTreeControlEvents *events;
66 } NSTC2Impl;
68 static const DWORD unsupported_styles =
69 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
70 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
71 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
72 static const DWORD unsupported_styles2 =
73 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
74 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
76 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
78 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
81 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
83 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
86 /* Forward declarations */
87 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
89 /*************************************************************************
90 * NamespaceTree event wrappers
92 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
93 int *piDefaultIcon, int *piOpenIcon)
95 HRESULT ret;
96 LONG refcount;
97 if(!This->events) return E_NOTIMPL;
99 refcount = IShellItem_AddRef(psi);
100 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->events, psi, piDefaultIcon, piOpenIcon);
101 if(IShellItem_Release(psi) < refcount - 1)
102 ERR("ShellItem was released by client - please file a bug.\n");
103 return ret;
106 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
108 HRESULT ret;
109 LONG refcount;
110 if(!This->events) return S_OK;
112 refcount = IShellItem_AddRef(psi);
113 ret = INameSpaceTreeControlEvents_OnItemAdded(This->events, psi, fIsRoot);
114 if(IShellItem_Release(psi) < refcount - 1)
115 ERR("ShellItem was released by client - please file a bug.\n");
116 return ret;
119 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
121 HRESULT ret;
122 LONG refcount;
123 if(!This->events) return S_OK;
125 refcount = IShellItem_AddRef(psi);
126 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->events, psi, fIsRoot);
127 if(IShellItem_Release(psi) < refcount - 1)
128 ERR("ShellItem was released by client - please file a bug.\n");
129 return ret;
132 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
134 HRESULT ret;
135 LONG refcount;
136 if(!This->events) return S_OK;
138 refcount = IShellItem_AddRef(psi);
139 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->events, psi);
140 if(IShellItem_Release(psi) < refcount - 1)
141 ERR("ShellItem was released by client - please file a bug.\n");
142 return ret;
145 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
147 HRESULT ret;
148 LONG refcount;
149 if(!This->events) return S_OK;
151 refcount = IShellItem_AddRef(psi);
152 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->events, psi);
153 if(IShellItem_Release(psi) < refcount - 1)
154 ERR("ShellItem was released by client - please file a bug.\n");
155 return ret;
158 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
159 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
161 HRESULT ret;
162 LONG refcount;
163 if(!This->events) return S_OK;
165 refcount = IShellItem_AddRef(psi);
166 ret = INameSpaceTreeControlEvents_OnItemClick(This->events, psi, nstceHitTest, nstceClickType);
167 if(IShellItem_Release(psi) < refcount - 1)
168 ERR("ShellItem was released by client - please file a bug.\n");
169 return ret;
172 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
174 if(!This->events) return S_OK;
176 return INameSpaceTreeControlEvents_OnSelectionChanged(This->events, psia);
179 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
181 if(!This->events) return S_OK;
183 return INameSpaceTreeControlEvents_OnKeyboardInput(This->events, uMsg, wParam, lParam);
186 /*************************************************************************
187 * NamespaceTree helper functions
189 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
190 NSTCSTYLE nstcs_mask, DWORD *new_style)
192 DWORD old_style, tv_mask = 0;
193 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
195 if(This->hwnd_tv)
196 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
197 else
198 old_style = /* The default */
199 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
200 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
201 TVS_EDITLABELS | TVS_TRACKSELECT;
203 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
204 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
205 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
206 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
207 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
208 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
209 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
210 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
211 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
212 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
213 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
215 *new_style = 0;
217 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
218 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
219 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
220 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
221 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
222 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
223 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
224 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
225 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
226 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
227 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
229 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
231 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
233 return old_style^*new_style;
236 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
238 TVITEMEXW tvi;
240 tvi.mask = TVIF_PARAM;
241 tvi.lParam = 0;
242 tvi.hItem = hitem;
244 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
246 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
247 return (IShellItem*)tvi.lParam;
250 /* Returns the root that the given treeitem belongs to. */
251 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
253 HTREEITEM tmp, hroot = hitem;
254 nstc_root *root;
256 /* Work our way up the hierarchy */
257 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
258 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
260 /* Search through the list of roots for a match */
261 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
262 if(root->htreeitem == hroot)
263 break;
265 TRACE("root is %p\n", root);
266 return root;
269 /* Find a shellitem in the tree, starting from the given node. */
270 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
271 IShellItem *psi)
273 IShellItem *psi_node;
274 HTREEITEM next, result = NULL;
275 HRESULT hr;
276 int cmpo;
277 TRACE("%p, %p, %p\n", This, node, psi);
279 /* Check this node */
280 psi_node = shellitem_from_treeitem(This, node);
281 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
282 if(hr == S_OK)
283 return node;
285 /* Any children? */
286 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
287 TVGN_CHILD, (LPARAM)node);
288 if(next)
290 result = search_for_shellitem(This, next, psi);
291 if(result) return result;
294 /* Try our next sibling. */
295 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
296 TVGN_NEXT, (LPARAM)node);
297 if(next)
298 result = search_for_shellitem(This, next, psi);
300 return result;
303 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
305 HTREEITEM root;
306 TRACE("%p, %p\n", This, psi);
308 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
309 TVGN_ROOT, 0);
310 if(!root)
311 return NULL;
313 return search_for_shellitem(This, root, psi);
316 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
318 SHFILEINFOW sfi;
319 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
320 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
321 return sfi.iIcon;
324 /* Insert a shellitem into the given place in the tree and return the
325 resulting treeitem. */
326 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
327 HTREEITEM hParent, HTREEITEM hInsertAfter)
329 TVINSERTSTRUCTW tvins;
330 TVITEMEXW *tvi = &tvins.u.itemex;
331 HTREEITEM hinserted;
332 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
334 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
335 tvi->cChildren = I_CHILDRENCALLBACK;
336 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
337 tvi->pszText = LPSTR_TEXTCALLBACKW;
339 /* Every treeitem contains a pointer to the corresponding ShellItem. */
340 tvi->lParam = (LPARAM)psi;
341 tvins.hParent = hParent;
342 tvins.hInsertAfter = hInsertAfter;
344 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
345 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
346 if(hinserted)
347 IShellItem_AddRef(psi);
349 return hinserted;
352 /* Enumerates the children of the folder represented by hitem
353 * according to the settings for the root, and adds them to the
354 * treeview. Returns the number of children added. */
355 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
357 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
358 nstc_root *root = root_for_treeitem(This, hitem);
359 LPITEMIDLIST pidl_parent;
360 IShellFolder *psf;
361 IEnumIDList *peidl;
362 UINT added = 0;
363 HRESULT hr;
365 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
366 if(SUCCEEDED(hr))
368 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
369 if(SUCCEEDED(hr))
371 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
372 if(SUCCEEDED(hr))
374 LPITEMIDLIST pidl;
375 IShellItem *psi;
376 ULONG fetched;
378 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
380 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
381 ILFree(pidl);
382 if(SUCCEEDED(hr))
384 if(insert_shellitem(This, psi, hitem, NULL))
386 events_OnItemAdded(This, psi, FALSE);
387 added++;
390 IShellItem_Release(psi);
392 else
393 ERR("SHCreateShellItem failed with 0x%08x\n", hr);
395 IEnumIDList_Release(peidl);
397 else
398 ERR("EnumObjects failed with 0x%08x\n", hr);
400 IShellFolder_Release(psf);
402 else
403 ERR("BindToHandler failed with 0x%08x\n", hr);
405 ILFree(pidl_parent);
407 else
408 ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
410 return added;
413 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
415 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
418 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
420 return shellitem_from_treeitem(This, get_selected_treeitem(This));
423 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
425 HTREEITEM next;
427 /* Collapse this node first, and then first child/next sibling. */
428 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
430 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
431 if(next) collapse_all(This, next);
433 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
434 if(next) collapse_all(This, next);
437 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
439 TVHITTESTINFO tviht;
440 tviht.pt.x = pt->x;
441 tviht.pt.y = pt->y;
442 tviht.hItem = NULL;
444 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
445 if(hitflag) *hitflag = tviht.flags;
446 return tviht.hItem;
449 /*************************************************************************
450 * NamespaceTree window functions
452 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
454 NSTC2Impl *This = crs->lpCreateParams;
455 HIMAGELIST ShellSmallIconList;
456 DWORD treeview_style, treeview_ex_style;
458 TRACE("%p (%p)\n", This, crs);
459 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
460 This->hwnd_main = hWnd;
462 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
464 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
465 0, 0, crs->cx, crs->cy,
466 hWnd, NULL, explorerframe_hinstance, NULL);
468 if(!This->hwnd_tv)
470 ERR("Failed to create treeview!\n");
471 return HRESULT_FROM_WIN32(GetLastError());
474 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
475 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
477 if(This->style & NSTCS_AUTOHSCROLL)
478 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
479 if(This->style & NSTCS_FADEINOUTEXPANDOS)
480 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
481 if(This->style & NSTCS_PARTIALCHECKBOXES)
482 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
483 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
484 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
485 if(This->style & NSTCS_DIMMEDCHECKBOXES)
486 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
488 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
490 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
492 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
493 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
495 else
497 ERR("Failed to get the System Image List.\n");
500 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
502 /* Subclass the treeview to get the keybord events. */
503 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
504 (ULONG_PTR)tv_wndproc);
505 if(This->tv_oldwndproc)
506 SetPropA(This->hwnd_tv, "PROP_THIS", This);
508 return TRUE;
511 static LRESULT resize_namespacetree(NSTC2Impl *This)
513 RECT rc;
514 TRACE("%p\n", This);
516 GetClientRect(This->hwnd_main, &rc);
517 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
519 return TRUE;
522 static LRESULT destroy_namespacetree(NSTC2Impl *This)
524 TRACE("%p\n", This);
526 /* Undo the subclassing */
527 if(This->tv_oldwndproc)
529 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
530 RemovePropA(This->hwnd_tv, "PROP_THIS");
533 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
535 /* This reference was added in create_namespacetree */
536 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
537 return TRUE;
540 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
542 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
543 TRACE("%p\n", This);
545 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
546 return TRUE;
549 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
551 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
552 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
553 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
554 HRESULT hr;
556 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
558 if(item->mask & TVIF_CHILDREN)
560 SFGAOF sfgao;
562 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
563 if(SUCCEEDED(hr))
564 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
565 else
566 item->cChildren = 1;
568 item->mask |= TVIF_DI_SETITEM;
571 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
573 LPITEMIDLIST pidl;
575 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
576 if(FAILED(hr))
578 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
579 if(SUCCEEDED(hr))
581 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
582 item->mask |= TVIF_DI_SETITEM;
583 ILFree(pidl);
585 else
586 ERR("Failed to get IDList (%08x).\n", hr);
590 if(item->mask & TVIF_TEXT)
592 LPWSTR display_name;
594 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
595 if(SUCCEEDED(hr))
597 lstrcpynW(item->pszText, display_name, MAX_PATH);
598 item->mask |= TVIF_DI_SETITEM;
599 CoTaskMemFree(display_name);
601 else
602 ERR("Failed to get display name (%08x).\n", hr);
605 return TRUE;
608 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
610 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
613 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
615 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
616 IShellItem *psi;
617 TRACE("%p\n", This);
619 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
620 events_OnBeforeExpand(This, psi);
622 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
624 /* The node has no children, try to find some */
625 if(!fill_sublevel(This, nmtv->itemNew.hItem))
627 TVITEMEXW tvi;
628 /* Failed to enumerate any children, remove the expando
629 * (if any). */
630 tvi.hItem = nmtv->itemNew.hItem;
631 tvi.mask = TVIF_CHILDREN;
632 tvi.cChildren = 0;
633 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
635 return TRUE;
638 return FALSE;
641 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
643 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
644 IShellItem *psi;
645 TRACE("%p\n", This);
647 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
648 events_OnAfterExpand(This, psi);
649 return TRUE;
652 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
654 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
655 IShellItemArray *psia;
656 IShellItem *psi;
657 HRESULT hr;
658 TRACE("%p\n", This);
660 /* Note: Only supports one selected item. */
661 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
662 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
663 if(SUCCEEDED(hr))
665 events_OnSelectionChanged(This, psia);
666 IShellItemArray_Release(psia);
669 return TRUE;
672 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
674 TVHITTESTINFO tvhit;
675 IShellItem *psi;
676 HRESULT hr;
677 TRACE("%p (%p)\n", This, nmhdr);
679 GetCursorPos(&tvhit.pt);
680 ScreenToClient(This->hwnd_tv, &tvhit.pt);
681 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
683 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
684 return TRUE;
686 /* TVHT_ maps onto the corresponding NSTCEHT_ */
687 psi = shellitem_from_treeitem(This, tvhit.hItem);
688 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
690 /* The expando should not be expanded unless
691 * double-clicked. */
692 if(tvhit.flags == TVHT_ONITEMBUTTON)
693 return TRUE;
695 if(SUCCEEDED(hr))
696 return FALSE;
697 else
698 return TRUE;
701 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
703 TVHITTESTINFO tvhit;
704 IShellItem *psi;
705 HRESULT hr;
706 TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
708 tvhit.pt.x = (int)(short)LOWORD(lParam);
709 tvhit.pt.y = (int)(short)HIWORD(lParam);
711 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
713 /* Seems to generate only ONITEM and ONITEMICON */
714 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
715 return FALSE;
717 psi = shellitem_from_treeitem(This, tvhit.hItem);
718 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
720 if(SUCCEEDED(hr))
721 return FALSE;
722 else
723 return TRUE;
726 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
728 IShellItem *psi;
729 HTREEITEM hitem;
730 TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
732 /* Handled by the client? */
733 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
734 return TRUE;
736 if(uMsg == WM_KEYDOWN)
738 switch(wParam)
740 case VK_DELETE:
741 psi = get_selected_shellitem(This);
742 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
743 return TRUE;
745 case VK_F2:
746 hitem = get_selected_treeitem(This);
747 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
748 return TRUE;
752 /* Let the TreeView handle the key */
753 return FALSE;
756 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
758 NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS");
760 switch(uMessage) {
761 case WM_KEYDOWN:
762 case WM_KEYUP:
763 case WM_CHAR:
764 case WM_SYSKEYDOWN:
765 case WM_SYSKEYUP:
766 case WM_SYSCHAR:
767 if(on_kbd_event(This, uMessage, wParam, lParam))
768 return TRUE;
769 break;
771 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
774 /* Pass the message on to the treeview */
775 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
778 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
779 WPARAM wParam, LPARAM lParam)
781 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
782 NMHDR *nmhdr;
784 switch(uMessage)
786 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
787 case WM_SIZE: return resize_namespacetree(This);
788 case WM_DESTROY: return destroy_namespacetree(This);
789 case WM_NOTIFY:
790 nmhdr = (NMHDR*)lParam;
791 switch(nmhdr->code)
793 case NM_CLICK: return on_nm_click(This, nmhdr);
794 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
795 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
796 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
797 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
798 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
799 default: break;
801 break;
802 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
804 return 0;
807 /**************************************************************************
808 * INameSpaceTreeControl2 Implementation
810 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
811 REFIID riid,
812 void **ppvObject)
814 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
815 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
817 *ppvObject = NULL;
818 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
819 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
820 IsEqualIID(riid, &IID_IUnknown))
822 *ppvObject = This;
824 else if(IsEqualIID(riid, &IID_IOleWindow))
826 *ppvObject = &This->IOleWindow_iface;
829 if(*ppvObject)
831 IUnknown_AddRef((IUnknown*)*ppvObject);
832 return S_OK;
835 return E_NOINTERFACE;
838 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
840 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
841 LONG ref = InterlockedIncrement(&This->ref);
843 TRACE("%p - ref %d\n", This, ref);
845 return ref;
848 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
850 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
851 LONG ref = InterlockedDecrement(&This->ref);
853 TRACE("%p - ref: %d\n", This, ref);
855 if(!ref)
857 TRACE("Freeing.\n");
858 HeapFree(GetProcessHeap(), 0, This);
859 EFRAME_UnlockModule();
860 return 0;
863 return ref;
866 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
867 HWND hwndParent,
868 RECT *prc,
869 NSTCSTYLE nstcsFlags)
871 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
872 WNDCLASSW wc;
873 DWORD window_style, window_ex_style;
874 INITCOMMONCONTROLSEX icex;
875 RECT rc;
876 static const WCHAR NSTC2_CLASS_NAME[] =
877 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
878 'C','o','n','t','r','o','l',0};
880 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
882 if(nstcsFlags & unsupported_styles)
883 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
884 nstcsFlags, nstcsFlags & unsupported_styles);
886 This->style = nstcsFlags;
888 icex.dwSize = sizeof( icex );
889 icex.dwICC = ICC_TREEVIEW_CLASSES;
890 InitCommonControlsEx( &icex );
892 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
894 wc.style = CS_HREDRAW | CS_VREDRAW;
895 wc.lpfnWndProc = NSTC2_WndProc;
896 wc.cbClsExtra = 0;
897 wc.cbWndExtra = 0;
898 wc.hInstance = explorerframe_hinstance;
899 wc.hIcon = 0;
900 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
901 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
902 wc.lpszMenuName = NULL;
903 wc.lpszClassName = NSTC2_CLASS_NAME;
905 if (!RegisterClassW(&wc)) return E_FAIL;
908 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
909 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
910 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
911 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
913 if(prc)
914 CopyRect(&rc, prc);
915 else
916 rc.left = rc.right = rc.top = rc.bottom = 0;
918 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
919 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
920 hwndParent, 0, explorerframe_hinstance, This);
922 if(!This->hwnd_main)
924 ERR("Failed to create the window.\n");
925 return HRESULT_FROM_WIN32(GetLastError());
928 return S_OK;
931 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, IUnknown *handler, DWORD *cookie)
933 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
935 TRACE("%p (%p, %p)\n", This, handler, cookie);
937 *cookie = 0;
939 /* Only one client supported */
940 if (This->events || This->customdraw || This->dragdrop)
941 return E_FAIL;
943 /* FIXME: request INameSpaceTreeAccessible too */
944 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlEvents, (void**)&This->events);
945 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlCustomDraw, (void**)&This->customdraw);
946 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlDropHandler, (void**)&This->dragdrop);
948 if (This->events || This->customdraw || This->dragdrop)
949 *cookie = 1;
951 return *cookie ? S_OK : E_FAIL;
954 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, DWORD cookie)
956 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
958 TRACE("%p (%x)\n", This, cookie);
960 /* The cookie is ignored. */
962 if (This->events)
964 INameSpaceTreeControlEvents_Release(This->events);
965 This->events = NULL;
968 if (This->customdraw)
970 INameSpaceTreeControlCustomDraw_Release(This->customdraw);
971 This->customdraw = NULL;
974 if (This->dragdrop)
976 INameSpaceTreeControlDropHandler_Release(This->dragdrop);
977 This->dragdrop = NULL;
980 return S_OK;
983 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
984 int iIndex,
985 IShellItem *psiRoot,
986 SHCONTF grfEnumFlags,
987 NSTCROOTSTYLE grfRootStyle,
988 IShellItemFilter *pif)
990 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
991 nstc_root *new_root;
992 struct list *add_after_entry;
993 HTREEITEM add_after_hitem;
994 int i;
996 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
998 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
999 if(!new_root)
1000 return E_OUTOFMEMORY;
1002 new_root->psi = psiRoot;
1003 new_root->enum_flags = grfEnumFlags;
1004 new_root->root_style = grfRootStyle;
1005 new_root->pif = pif;
1007 /* We want to keep the roots in the internal list and in the
1008 * treeview in the same order. */
1009 add_after_entry = &This->roots;
1010 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
1011 add_after_entry = list_next(&This->roots, add_after_entry);
1013 if(add_after_entry == &This->roots)
1014 add_after_hitem = TVI_FIRST;
1015 else
1016 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1018 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1019 if(!new_root->htreeitem)
1021 WARN("Failed to add the root.\n");
1022 HeapFree(GetProcessHeap(), 0, new_root);
1023 return E_FAIL;
1026 list_add_after(add_after_entry, &new_root->entry);
1027 events_OnItemAdded(This, psiRoot, TRUE);
1029 if(grfRootStyle & NSTCRS_HIDDEN)
1031 TVITEMEXW tvi;
1032 tvi.mask = TVIF_STATEEX;
1033 tvi.uStateEx = TVIS_EX_FLAT;
1034 tvi.hItem = new_root->htreeitem;
1036 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1039 if(grfRootStyle & NSTCRS_EXPANDED)
1040 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1041 (LPARAM)new_root->htreeitem);
1043 return S_OK;
1046 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1047 IShellItem *psiRoot,
1048 SHCONTF grfEnumFlags,
1049 NSTCROOTSTYLE grfRootStyle,
1050 IShellItemFilter *pif)
1052 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1053 UINT root_count;
1054 TRACE("%p, %p, %x, %x, %p\n",
1055 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1057 root_count = list_count(&This->roots);
1059 return INameSpaceTreeControl2_InsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1062 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1063 IShellItem *psiRoot)
1065 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1066 nstc_root *cursor, *root = NULL;
1067 TRACE("%p (%p)\n", This, psiRoot);
1069 if(!psiRoot)
1070 return E_NOINTERFACE;
1072 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1074 HRESULT hr;
1075 int order;
1076 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1077 if(hr == S_OK)
1079 root = cursor;
1080 break;
1084 TRACE("root %p\n", root);
1085 if(root)
1087 events_OnItemDeleted(This, root->psi, TRUE);
1088 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1089 list_remove(&root->entry);
1090 HeapFree(GetProcessHeap(), 0, root);
1091 return S_OK;
1093 else
1095 WARN("No matching root found.\n");
1096 return E_FAIL;
1100 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1102 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1103 nstc_root *cur1, *cur2;
1105 TRACE("%p\n", This);
1107 if (list_empty(&This->roots))
1108 return E_INVALIDARG;
1110 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1111 INameSpaceTreeControl2_RemoveRoot(iface, cur1->psi);
1113 return S_OK;
1116 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1117 IShellItemArray **ppsiaRootItems)
1119 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1120 IShellFolder *psf;
1121 LPITEMIDLIST *array;
1122 nstc_root *root;
1123 UINT count, i;
1124 HRESULT hr;
1125 TRACE("%p (%p)\n", This, ppsiaRootItems);
1127 count = list_count(&This->roots);
1129 if(!count)
1130 return E_INVALIDARG;
1132 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST)*count);
1134 i = 0;
1135 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1136 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1138 SHGetDesktopFolder(&psf);
1139 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1140 ppsiaRootItems);
1141 IShellFolder_Release(psf);
1143 for(i = 0; i < count; i++)
1144 ILFree(array[i]);
1146 HeapFree(GetProcessHeap(), 0, array);
1148 return hr;
1151 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1152 IShellItem *psi,
1153 NSTCITEMSTATE nstcisMask,
1154 NSTCITEMSTATE nstcisFlags)
1156 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1157 TVITEMEXW tvi;
1158 HTREEITEM hitem;
1160 TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1162 hitem = treeitem_from_shellitem(This, psi);
1163 if(!hitem) return E_INVALIDARG;
1165 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1166 in two TVM_SETITEMW's */
1167 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1169 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1170 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1172 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1174 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1177 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1178 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1180 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1181 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1184 if(nstcisMask & NSTCIS_DISABLED)
1185 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1186 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1187 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1188 (nstcisFlags & NSTCIS_DISABLED) )
1189 tvi.mask = TVIF_STATE;
1190 else
1191 tvi.mask = 0;
1193 if(tvi.mask)
1195 tvi.stateMask = tvi.state = 0;
1196 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1197 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1198 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1200 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1202 tvi.stateMask = 0;
1205 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1206 tvi.hItem = hitem;
1208 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1211 return S_OK;
1214 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1215 IShellItem *psi,
1216 NSTCITEMSTATE nstcisMask,
1217 NSTCITEMSTATE *pnstcisFlags)
1219 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1220 HTREEITEM hitem;
1221 TVITEMEXW tvi;
1222 TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1224 hitem = treeitem_from_shellitem(This, psi);
1225 if(!hitem)
1226 return E_INVALIDARG;
1228 *pnstcisFlags = 0;
1230 tvi.hItem = hitem;
1231 tvi.mask = TVIF_STATE;
1232 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1234 if(nstcisMask & NSTCIS_DISABLED)
1235 tvi.mask |= TVIF_STATEEX;
1237 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1238 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1239 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1240 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1241 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1243 *pnstcisFlags &= nstcisMask;
1245 return S_OK;
1248 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1249 IShellItemArray **psiaItems)
1251 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1252 IShellItem *psiselected;
1254 TRACE("%p (%p)\n", This, psiaItems);
1256 psiselected = get_selected_shellitem(This);
1257 if(!psiselected)
1259 *psiaItems = NULL;
1260 return E_FAIL;
1263 return SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1264 (void**)psiaItems);
1267 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1268 IShellItem *psi,
1269 int *piStateNumber)
1271 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1272 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1273 return E_NOTIMPL;
1276 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1277 IShellItem *psi,
1278 int iStateNumber)
1280 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1281 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1282 return E_NOTIMPL;
1285 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1286 IShellItem *psi)
1288 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1289 HTREEITEM hitem;
1291 TRACE("%p (%p)\n", This, psi);
1293 hitem = treeitem_from_shellitem(This, psi);
1294 if(hitem)
1296 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1297 return S_OK;
1300 return E_INVALIDARG;
1303 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1304 LPCWSTR pszTheme)
1306 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1307 FIXME("stub, %p (%p)\n", This, pszTheme);
1308 return E_NOTIMPL;
1311 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1312 IShellItem *psi,
1313 NSTCGNI nstcgi,
1314 IShellItem **ppsiNext)
1316 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1317 HTREEITEM hitem, hnext;
1318 UINT tvgn;
1319 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1321 if(!ppsiNext) return E_POINTER;
1322 if(!psi) return E_FAIL;
1324 *ppsiNext = NULL;
1326 hitem = treeitem_from_shellitem(This, psi);
1327 if(!hitem)
1328 return E_INVALIDARG;
1330 switch(nstcgi)
1332 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1333 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1334 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1335 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1336 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1337 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1338 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1339 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1340 default:
1341 FIXME("Unknown nstcgi value %d\n", nstcgi);
1342 return E_FAIL;
1345 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1346 if(hnext)
1348 *ppsiNext = shellitem_from_treeitem(This, hnext);
1349 IShellItem_AddRef(*ppsiNext);
1350 return S_OK;
1353 return E_FAIL;
1356 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1357 POINT *ppt,
1358 IShellItem **ppsiOut)
1360 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1361 HTREEITEM hitem;
1362 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1364 if(!ppt || !ppsiOut)
1365 return E_POINTER;
1367 *ppsiOut = NULL;
1369 hitem = treeitem_from_point(This, ppt, NULL);
1370 if(hitem)
1371 *ppsiOut = shellitem_from_treeitem(This, hitem);
1373 if(*ppsiOut)
1375 IShellItem_AddRef(*ppsiOut);
1376 return S_OK;
1379 return S_FALSE;
1382 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1383 IShellItem *psi,
1384 RECT *prect)
1386 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1387 HTREEITEM hitem;
1388 TRACE("%p (%p, %p)\n", This, psi, prect);
1390 if(!psi || !prect)
1391 return E_POINTER;
1393 hitem = treeitem_from_shellitem(This, psi);
1394 if(hitem)
1396 *(HTREEITEM*)prect = hitem;
1397 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1399 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1400 return S_OK;
1404 return E_INVALIDARG;
1407 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1409 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1410 nstc_root *root;
1411 TRACE("%p\n", This);
1413 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1414 collapse_all(This, root->htreeitem);
1416 return S_OK;
1419 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1420 NSTCSTYLE nstcsMask,
1421 NSTCSTYLE nstcsStyle)
1423 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1424 static const DWORD tv_style_flags =
1425 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1426 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1427 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1428 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1429 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1430 static const DWORD nstc_flags =
1431 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1432 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1433 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1434 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1436 /* Fail if there is an attempt to set an unknown style. */
1437 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1438 return E_FAIL;
1440 if(nstcsMask & tv_style_flags)
1442 DWORD new_style;
1443 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1444 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1447 /* Flags affecting the host window */
1448 if(nstcsMask & NSTCS_BORDER)
1450 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1451 new_style &= ~WS_BORDER;
1452 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1453 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1455 if(nstcsMask & NSTCS_TABSTOP)
1457 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1458 new_style &= ~WS_EX_CONTROLPARENT;
1459 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1460 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1463 if((nstcsStyle & nstcsMask) & unsupported_styles)
1464 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1465 (nstcsStyle & nstcsMask),
1466 (nstcsStyle & nstcsMask) & unsupported_styles);
1468 This->style &= ~nstcsMask;
1469 This->style |= (nstcsStyle & nstcsMask);
1471 return S_OK;
1474 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1475 NSTCSTYLE nstcsMask,
1476 NSTCSTYLE *pnstcsStyle)
1478 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1479 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1481 *pnstcsStyle = (This->style & nstcsMask);
1483 return S_OK;
1486 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1487 NSTCSTYLE2 nstcsMask,
1488 NSTCSTYLE2 nstcsStyle)
1490 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1491 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1493 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1494 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1495 (nstcsStyle & nstcsMask),
1496 (nstcsStyle & nstcsMask) & unsupported_styles2);
1498 This->style2 &= ~nstcsMask;
1499 This->style2 |= (nstcsStyle & nstcsMask);
1501 return S_OK;
1504 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1505 NSTCSTYLE2 nstcsMask,
1506 NSTCSTYLE2 *pnstcsStyle)
1508 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1509 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1511 *pnstcsStyle = (This->style2 & nstcsMask);
1513 return S_OK;
1516 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1517 NSTC2_fnQueryInterface,
1518 NSTC2_fnAddRef,
1519 NSTC2_fnRelease,
1520 NSTC2_fnInitialize,
1521 NSTC2_fnTreeAdvise,
1522 NSTC2_fnTreeUnadvise,
1523 NSTC2_fnAppendRoot,
1524 NSTC2_fnInsertRoot,
1525 NSTC2_fnRemoveRoot,
1526 NSTC2_fnRemoveAllRoots,
1527 NSTC2_fnGetRootItems,
1528 NSTC2_fnSetItemState,
1529 NSTC2_fnGetItemState,
1530 NSTC2_fnGetSelectedItems,
1531 NSTC2_fnGetItemCustomState,
1532 NSTC2_fnSetItemCustomState,
1533 NSTC2_fnEnsureItemVisible,
1534 NSTC2_fnSetTheme,
1535 NSTC2_fnGetNextItem,
1536 NSTC2_fnHitTest,
1537 NSTC2_fnGetItemRect,
1538 NSTC2_fnCollapseAll,
1539 NSTC2_fnSetControlStyle,
1540 NSTC2_fnGetControlStyle,
1541 NSTC2_fnSetControlStyle2,
1542 NSTC2_fnGetControlStyle2
1545 /**************************************************************************
1546 * IOleWindow Implementation
1549 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1551 NSTC2Impl *This = impl_from_IOleWindow(iface);
1552 return INameSpaceTreeControl2_QueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1555 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1557 NSTC2Impl *This = impl_from_IOleWindow(iface);
1558 return INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
1561 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1563 NSTC2Impl *This = impl_from_IOleWindow(iface);
1564 return INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
1567 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1569 NSTC2Impl *This = impl_from_IOleWindow(iface);
1570 TRACE("%p (%p)\n", This, phwnd);
1572 *phwnd = This->hwnd_main;
1573 return S_OK;
1576 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1578 NSTC2Impl *This = impl_from_IOleWindow(iface);
1579 TRACE("%p (%d)\n", This, fEnterMode);
1581 /* Not implemented */
1582 return E_NOTIMPL;
1585 static const IOleWindowVtbl vt_IOleWindow = {
1586 IOW_fnQueryInterface,
1587 IOW_fnAddRef,
1588 IOW_fnRelease,
1589 IOW_fnGetWindow,
1590 IOW_fnContextSensitiveHelp
1593 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1595 NSTC2Impl *nstc;
1596 HRESULT ret;
1598 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1600 if(!ppv)
1601 return E_POINTER;
1602 if(pUnkOuter)
1603 return CLASS_E_NOAGGREGATION;
1605 EFRAME_LockModule();
1607 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1608 if (!nstc)
1609 return E_OUTOFMEMORY;
1611 nstc->ref = 1;
1612 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1613 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1615 list_init(&nstc->roots);
1617 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1618 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1620 TRACE("--(%p)\n", ppv);
1621 return ret;