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
30 #include "commoncontrols.h"
32 #include "wine/list.h"
33 #include "wine/debug.h"
35 #include "explorerframe_main.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(nstc
);
39 typedef struct nstc_root
{
43 NSTCROOTSTYLE root_style
;
44 IShellItemFilter
*pif
;
49 INameSpaceTreeControl2 INameSpaceTreeControl2_iface
;
50 IOleWindow IOleWindow_iface
;
56 WNDPROC tv_oldwndproc
;
62 INameSpaceTreeControlCustomDraw
*customdraw
;
63 INameSpaceTreeControlDropHandler
*dragdrop
;
64 INameSpaceTreeControlEvents
*events
;
67 static const DWORD unsupported_styles
=
68 NSTCS_NOREPLACEOPEN
| NSTCS_NOORDERSTREAM
| NSTCS_FAVORITESMODE
|
69 NSTCS_EMPTYTEXT
| NSTCS_ALLOWJUNCTIONS
| NSTCS_SHOWTABSBUTTON
| NSTCS_SHOWDELETEBUTTON
|
70 NSTCS_SHOWREFRESHBUTTON
| NSTCS_SPRINGEXPAND
| NSTCS_RICHTOOLTIP
| NSTCS_NOINDENTCHECKS
;
71 static const DWORD unsupported_styles2
=
72 NSTCS2_INTERRUPTNOTIFICATIONS
| NSTCS2_SHOWNULLSPACEMENU
| NSTCS2_DISPLAYPADDING
|
73 NSTCS2_DISPLAYPINNEDONLY
| NTSCS2_NOSINGLETONAUTOEXPAND
| NTSCS2_NEVERINSERTNONENUMERATED
;
75 static inline NSTC2Impl
*impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2
*iface
)
77 return CONTAINING_RECORD(iface
, NSTC2Impl
, INameSpaceTreeControl2_iface
);
80 static inline NSTC2Impl
*impl_from_IOleWindow(IOleWindow
*iface
)
82 return CONTAINING_RECORD(iface
, NSTC2Impl
, IOleWindow_iface
);
85 /* Forward declarations */
86 static LRESULT CALLBACK
tv_wndproc(HWND hWnd
, UINT uMessage
, WPARAM wParam
, LPARAM lParam
);
88 /*************************************************************************
89 * NamespaceTree event wrappers
91 static HRESULT
events_OnGetDefaultIconIndex(NSTC2Impl
*This
, IShellItem
*psi
,
92 int *piDefaultIcon
, int *piOpenIcon
)
96 if(!This
->events
) return E_NOTIMPL
;
98 refcount
= IShellItem_AddRef(psi
);
99 ret
= INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This
->events
, psi
, piDefaultIcon
, piOpenIcon
);
100 if(IShellItem_Release(psi
) < refcount
- 1)
101 ERR("ShellItem was released by client - please file a bug.\n");
105 static HRESULT
events_OnItemAdded(NSTC2Impl
*This
, IShellItem
*psi
, BOOL fIsRoot
)
109 if(!This
->events
) return S_OK
;
111 refcount
= IShellItem_AddRef(psi
);
112 ret
= INameSpaceTreeControlEvents_OnItemAdded(This
->events
, psi
, fIsRoot
);
113 if(IShellItem_Release(psi
) < refcount
- 1)
114 ERR("ShellItem was released by client - please file a bug.\n");
118 static HRESULT
events_OnItemDeleted(NSTC2Impl
*This
, IShellItem
*psi
, BOOL fIsRoot
)
122 if(!This
->events
) return S_OK
;
124 refcount
= IShellItem_AddRef(psi
);
125 ret
= INameSpaceTreeControlEvents_OnItemDeleted(This
->events
, psi
, fIsRoot
);
126 if(IShellItem_Release(psi
) < refcount
- 1)
127 ERR("ShellItem was released by client - please file a bug.\n");
131 static HRESULT
events_OnBeforeExpand(NSTC2Impl
*This
, IShellItem
*psi
)
135 if(!This
->events
) return S_OK
;
137 refcount
= IShellItem_AddRef(psi
);
138 ret
= INameSpaceTreeControlEvents_OnBeforeExpand(This
->events
, psi
);
139 if(IShellItem_Release(psi
) < refcount
- 1)
140 ERR("ShellItem was released by client - please file a bug.\n");
144 static HRESULT
events_OnAfterExpand(NSTC2Impl
*This
, IShellItem
*psi
)
148 if(!This
->events
) return S_OK
;
150 refcount
= IShellItem_AddRef(psi
);
151 ret
= INameSpaceTreeControlEvents_OnAfterExpand(This
->events
, psi
);
152 if(IShellItem_Release(psi
) < refcount
- 1)
153 ERR("ShellItem was released by client - please file a bug.\n");
157 static HRESULT
events_OnItemClick(NSTC2Impl
*This
, IShellItem
*psi
,
158 NSTCEHITTEST nstceHitTest
, NSTCECLICKTYPE nstceClickType
)
162 if(!This
->events
) return S_OK
;
164 refcount
= IShellItem_AddRef(psi
);
165 ret
= INameSpaceTreeControlEvents_OnItemClick(This
->events
, psi
, nstceHitTest
, nstceClickType
);
166 if(IShellItem_Release(psi
) < refcount
- 1)
167 ERR("ShellItem was released by client - please file a bug.\n");
171 static HRESULT
events_OnSelectionChanged(NSTC2Impl
*This
, IShellItemArray
*psia
)
173 if(!This
->events
) return S_OK
;
175 return INameSpaceTreeControlEvents_OnSelectionChanged(This
->events
, psia
);
178 static HRESULT
events_OnKeyboardInput(NSTC2Impl
*This
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
180 if(!This
->events
) return S_OK
;
182 return INameSpaceTreeControlEvents_OnKeyboardInput(This
->events
, uMsg
, wParam
, lParam
);
185 /*************************************************************************
186 * NamespaceTree helper functions
188 static DWORD
treeview_style_from_nstcs(NSTC2Impl
*This
, NSTCSTYLE nstcs
,
189 NSTCSTYLE nstcs_mask
, DWORD
*new_style
)
191 DWORD old_style
, tv_mask
= 0;
192 TRACE("%p, %lx, %lx, %p\n", This
, nstcs
, nstcs_mask
, new_style
);
195 old_style
= GetWindowLongPtrW(This
->hwnd_tv
, GWL_STYLE
);
197 old_style
= /* The default */
198 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
199 WS_TABSTOP
| TVS_NOHSCROLL
| TVS_NONEVENHEIGHT
| TVS_INFOTIP
|
200 TVS_EDITLABELS
| TVS_TRACKSELECT
;
202 if(nstcs_mask
& NSTCS_HASEXPANDOS
) tv_mask
|= TVS_HASBUTTONS
;
203 if(nstcs_mask
& NSTCS_HASLINES
) tv_mask
|= TVS_HASLINES
;
204 if(nstcs_mask
& NSTCS_FULLROWSELECT
) tv_mask
|= TVS_FULLROWSELECT
;
205 if(nstcs_mask
& NSTCS_HORIZONTALSCROLL
) tv_mask
|= TVS_NOHSCROLL
;
206 if(nstcs_mask
& NSTCS_ROOTHASEXPANDO
) tv_mask
|= TVS_LINESATROOT
;
207 if(nstcs_mask
& NSTCS_SHOWSELECTIONALWAYS
) tv_mask
|= TVS_SHOWSELALWAYS
;
208 if(nstcs_mask
& NSTCS_NOINFOTIP
) tv_mask
|= TVS_INFOTIP
;
209 if(nstcs_mask
& NSTCS_EVENHEIGHT
) tv_mask
|= TVS_NONEVENHEIGHT
;
210 if(nstcs_mask
& NSTCS_DISABLEDRAGDROP
) tv_mask
|= TVS_DISABLEDRAGDROP
;
211 if(nstcs_mask
& NSTCS_NOEDITLABELS
) tv_mask
|= TVS_EDITLABELS
;
212 if(nstcs_mask
& NSTCS_CHECKBOXES
) tv_mask
|= TVS_CHECKBOXES
;
213 if(nstcs_mask
& NSTCS_SINGLECLICKEXPAND
) tv_mask
|= TVS_SINGLEEXPAND
;
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
;
228 if(nstcs
& NSTCS_SINGLECLICKEXPAND
) *new_style
|= TVS_SINGLEEXPAND
;
230 *new_style
= (old_style
& ~tv_mask
) | (*new_style
& tv_mask
);
232 TRACE("old: %08lx, new: %08lx\n", old_style
, *new_style
);
234 return old_style
^*new_style
;
237 static IShellItem
*shellitem_from_treeitem(NSTC2Impl
*This
, HTREEITEM hitem
)
241 tvi
.mask
= TVIF_PARAM
;
245 SendMessageW(This
->hwnd_tv
, TVM_GETITEMW
, 0, (LPARAM
)&tvi
);
247 TRACE("ShellItem: %p\n", (void*)tvi
.lParam
);
248 return (IShellItem
*)tvi
.lParam
;
251 /* Returns the root that the given treeitem belongs to. */
252 static nstc_root
*root_for_treeitem(NSTC2Impl
*This
, HTREEITEM hitem
)
254 HTREEITEM tmp
, hroot
= hitem
;
257 /* Work our way up the hierarchy */
258 for(tmp
= hitem
; tmp
!= NULL
; hroot
= tmp
?tmp
:hroot
)
259 tmp
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, TVGN_PARENT
, (LPARAM
)hroot
);
261 /* Search through the list of roots for a match */
262 LIST_FOR_EACH_ENTRY(root
, &This
->roots
, nstc_root
, entry
)
263 if(root
->htreeitem
== hroot
)
266 TRACE("root is %p\n", root
);
270 /* Find a shellitem in the tree, starting from the given node. */
271 static HTREEITEM
search_for_shellitem(NSTC2Impl
*This
, HTREEITEM node
,
274 IShellItem
*psi_node
;
275 HTREEITEM next
, result
= NULL
;
278 TRACE("%p, %p, %p\n", This
, node
, psi
);
280 /* Check this node */
281 psi_node
= shellitem_from_treeitem(This
, node
);
282 hr
= IShellItem_Compare(psi
, psi_node
, SICHINT_DISPLAY
, &cmpo
);
287 next
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
,
288 TVGN_CHILD
, (LPARAM
)node
);
291 result
= search_for_shellitem(This
, next
, psi
);
292 if(result
) return result
;
295 /* Try our next sibling. */
296 next
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
,
297 TVGN_NEXT
, (LPARAM
)node
);
299 result
= search_for_shellitem(This
, next
, psi
);
304 static HTREEITEM
treeitem_from_shellitem(NSTC2Impl
*This
, IShellItem
*psi
)
307 TRACE("%p, %p\n", This
, psi
);
309 root
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
,
314 return search_for_shellitem(This
, root
, psi
);
317 static int get_icon(LPCITEMIDLIST lpi
, UINT extra_flags
)
320 UINT flags
= SHGFI_PIDL
| SHGFI_SYSICONINDEX
| SHGFI_SMALLICON
;
323 list
= (IImageList
*)SHGetFileInfoW((LPCWSTR
)lpi
, 0 ,&sfi
, sizeof(SHFILEINFOW
), flags
| extra_flags
);
324 if (list
) IImageList_Release(list
);
328 /* Insert a shellitem into the given place in the tree and return the
329 resulting treeitem. */
330 static HTREEITEM
insert_shellitem(NSTC2Impl
*This
, IShellItem
*psi
,
331 HTREEITEM hParent
, HTREEITEM hInsertAfter
)
333 TVINSERTSTRUCTW tvins
;
334 TVITEMEXW
*tvi
= &tvins
.itemex
;
336 TRACE("%p (%p, %p)\n", psi
, hParent
, hInsertAfter
);
338 tvi
->mask
= TVIF_PARAM
| TVIF_CHILDREN
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_TEXT
;
339 tvi
->cChildren
= I_CHILDRENCALLBACK
;
340 tvi
->iImage
= tvi
->iSelectedImage
= I_IMAGECALLBACK
;
341 tvi
->pszText
= LPSTR_TEXTCALLBACKW
;
343 /* Every treeitem contains a pointer to the corresponding ShellItem. */
344 tvi
->lParam
= (LPARAM
)psi
;
345 tvins
.hParent
= hParent
;
346 tvins
.hInsertAfter
= hInsertAfter
;
348 hinserted
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_INSERTITEMW
, 0,
349 (LPARAM
)(LPTVINSERTSTRUCTW
)&tvins
);
351 IShellItem_AddRef(psi
);
356 /* Enumerates the children of the folder represented by hitem
357 * according to the settings for the root, and adds them to the
358 * treeview. Returns the number of children added. */
359 static UINT
fill_sublevel(NSTC2Impl
*This
, HTREEITEM hitem
)
361 IShellItem
*psiParent
= shellitem_from_treeitem(This
, hitem
);
362 nstc_root
*root
= root_for_treeitem(This
, hitem
);
363 LPITEMIDLIST pidl_parent
;
369 hr
= SHGetIDListFromObject((IUnknown
*)psiParent
, &pidl_parent
);
372 hr
= IShellItem_BindToHandler(psiParent
, NULL
, &BHID_SFObject
, &IID_IShellFolder
, (void**)&psf
);
375 hr
= IShellFolder_EnumObjects(psf
, NULL
, root
->enum_flags
, &peidl
);
382 while( S_OK
== IEnumIDList_Next(peidl
, 1, &pidl
, &fetched
) )
384 hr
= SHCreateShellItem(NULL
, psf
, pidl
, &psi
);
388 if(insert_shellitem(This
, psi
, hitem
, NULL
))
390 events_OnItemAdded(This
, psi
, FALSE
);
394 IShellItem_Release(psi
);
397 ERR("SHCreateShellItem failed with 0x%08lx\n", hr
);
399 IEnumIDList_Release(peidl
);
402 ERR("EnumObjects failed with 0x%08lx\n", hr
);
404 IShellFolder_Release(psf
);
407 ERR("BindToHandler failed with 0x%08lx\n", hr
);
412 ERR("SHGetIDListFromObject failed with 0x%08lx\n", hr
);
417 static HTREEITEM
get_selected_treeitem(NSTC2Impl
*This
)
419 return (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, TVGN_CARET
, 0);
422 static IShellItem
*get_selected_shellitem(NSTC2Impl
*This
)
424 return shellitem_from_treeitem(This
, get_selected_treeitem(This
));
427 static void collapse_all(NSTC2Impl
*This
, HTREEITEM node
)
431 /* Collapse this node first, and then first child/next sibling. */
432 SendMessageW(This
->hwnd_tv
, TVM_EXPAND
, TVE_COLLAPSE
, (LPARAM
)node
);
434 next
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)node
);
435 if(next
) collapse_all(This
, next
);
437 next
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, TVGN_NEXT
, (LPARAM
)node
);
438 if(next
) collapse_all(This
, next
);
441 static HTREEITEM
treeitem_from_point(NSTC2Impl
*This
, const POINT
*pt
, UINT
*hitflag
)
448 SendMessageW(This
->hwnd_tv
, TVM_HITTEST
, 0, (LPARAM
)&tviht
);
449 if(hitflag
) *hitflag
= tviht
.flags
;
453 /*************************************************************************
454 * NamespaceTree window functions
456 static LRESULT
create_namespacetree(HWND hWnd
, CREATESTRUCTW
*crs
)
458 NSTC2Impl
*This
= crs
->lpCreateParams
;
459 HIMAGELIST ShellSmallIconList
;
460 DWORD treeview_style
, treeview_ex_style
;
462 TRACE("%p (%p)\n", This
, crs
);
463 SetWindowLongPtrW(hWnd
, GWLP_USERDATA
, (LPARAM
)This
);
464 This
->hwnd_main
= hWnd
;
466 treeview_style_from_nstcs(This
, This
->style
, 0xFFFFFFFF, &treeview_style
);
468 This
->hwnd_tv
= CreateWindowExW(0, WC_TREEVIEWW
, NULL
, treeview_style
,
469 0, 0, crs
->cx
, crs
->cy
,
470 hWnd
, NULL
, explorerframe_hinstance
, NULL
);
474 ERR("Failed to create treeview!\n");
475 return HRESULT_FROM_WIN32(GetLastError());
478 treeview_ex_style
= TVS_EX_DRAWIMAGEASYNC
| TVS_EX_RICHTOOLTIP
|
479 TVS_EX_DOUBLEBUFFER
| TVS_EX_NOSINGLECOLLAPSE
;
481 if(This
->style
& NSTCS_AUTOHSCROLL
)
482 treeview_ex_style
|= TVS_EX_AUTOHSCROLL
;
483 if(This
->style
& NSTCS_FADEINOUTEXPANDOS
)
484 treeview_ex_style
|= TVS_EX_FADEINOUTEXPANDOS
;
485 if(This
->style
& NSTCS_PARTIALCHECKBOXES
)
486 treeview_ex_style
|= TVS_EX_PARTIALCHECKBOXES
;
487 if(This
->style
& NSTCS_EXCLUSIONCHECKBOXES
)
488 treeview_ex_style
|= TVS_EX_EXCLUSIONCHECKBOXES
;
489 if(This
->style
& NSTCS_DIMMEDCHECKBOXES
)
490 treeview_ex_style
|= TVS_EX_DIMMEDCHECKBOXES
;
492 SendMessageW(This
->hwnd_tv
, TVM_SETEXTENDEDSTYLE
, treeview_ex_style
, 0xffff);
494 if(Shell_GetImageLists(NULL
, &ShellSmallIconList
))
496 SendMessageW(This
->hwnd_tv
, TVM_SETIMAGELIST
,
497 (WPARAM
)TVSIL_NORMAL
, (LPARAM
)ShellSmallIconList
);
501 ERR("Failed to get the System Image List.\n");
504 INameSpaceTreeControl2_AddRef(&This
->INameSpaceTreeControl2_iface
);
506 /* Subclass the treeview to get the keyboard events. */
507 This
->tv_oldwndproc
= (WNDPROC
)SetWindowLongPtrW(This
->hwnd_tv
, GWLP_WNDPROC
,
508 (ULONG_PTR
)tv_wndproc
);
509 if(This
->tv_oldwndproc
)
510 SetPropW(This
->hwnd_tv
, L
"PROP_THIS", This
);
515 static LRESULT
resize_namespacetree(NSTC2Impl
*This
)
520 GetClientRect(This
->hwnd_main
, &rc
);
521 MoveWindow(This
->hwnd_tv
, 0, 0, rc
.right
-rc
.left
, rc
.bottom
-rc
.top
, TRUE
);
526 static LRESULT
destroy_namespacetree(NSTC2Impl
*This
)
530 /* Undo the subclassing */
531 if(This
->tv_oldwndproc
)
533 SetWindowLongPtrW(This
->hwnd_tv
, GWLP_WNDPROC
, (ULONG_PTR
)This
->tv_oldwndproc
);
534 RemovePropW(This
->hwnd_tv
, L
"PROP_THIS");
537 INameSpaceTreeControl2_RemoveAllRoots(&This
->INameSpaceTreeControl2_iface
);
539 /* This reference was added in create_namespacetree */
540 INameSpaceTreeControl2_Release(&This
->INameSpaceTreeControl2_iface
);
544 static LRESULT
on_tvn_deleteitemw(NSTC2Impl
*This
, LPARAM lParam
)
546 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)lParam
;
549 IShellItem_Release((IShellItem
*)nmtv
->itemOld
.lParam
);
553 static LRESULT
on_tvn_getdispinfow(NSTC2Impl
*This
, LPARAM lParam
)
555 NMTVDISPINFOW
*dispinfo
= (NMTVDISPINFOW
*)lParam
;
556 TVITEMEXW
*item
= (TVITEMEXW
*)&dispinfo
->item
;
557 IShellItem
*psi
= shellitem_from_treeitem(This
, item
->hItem
);
560 TRACE("%p, %p (mask: %x)\n", This
, dispinfo
, item
->mask
);
562 if(item
->mask
& TVIF_CHILDREN
)
566 hr
= IShellItem_GetAttributes(psi
, SFGAO_HASSUBFOLDER
, &sfgao
);
568 item
->cChildren
= (sfgao
& SFGAO_HASSUBFOLDER
)?1:0;
572 item
->mask
|= TVIF_DI_SETITEM
;
575 if(item
->mask
& (TVIF_IMAGE
|TVIF_SELECTEDIMAGE
))
579 hr
= events_OnGetDefaultIconIndex(This
, psi
, &item
->iImage
, &item
->iSelectedImage
);
582 hr
= SHGetIDListFromObject((IUnknown
*)psi
, &pidl
);
585 item
->iImage
= item
->iSelectedImage
= get_icon(pidl
, 0);
586 item
->mask
|= TVIF_DI_SETITEM
;
590 ERR("Failed to get IDList (%08lx).\n", hr
);
594 if(item
->mask
& TVIF_TEXT
)
598 hr
= IShellItem_GetDisplayName(psi
, SIGDN_NORMALDISPLAY
, &display_name
);
601 lstrcpynW(item
->pszText
, display_name
, MAX_PATH
);
602 item
->mask
|= TVIF_DI_SETITEM
;
603 CoTaskMemFree(display_name
);
606 ERR("Failed to get display name (%08lx).\n", hr
);
612 static BOOL
treenode_has_subfolders(NSTC2Impl
*This
, HTREEITEM node
)
614 return SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)node
);
617 static LRESULT
on_tvn_itemexpandingw(NSTC2Impl
*This
, LPARAM lParam
)
619 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)lParam
;
623 psi
= shellitem_from_treeitem(This
, nmtv
->itemNew
.hItem
);
624 events_OnBeforeExpand(This
, psi
);
626 if(!treenode_has_subfolders(This
, nmtv
->itemNew
.hItem
))
628 /* The node has no children, try to find some */
629 if(!fill_sublevel(This
, nmtv
->itemNew
.hItem
))
632 /* Failed to enumerate any children, remove the expando
634 tvi
.hItem
= nmtv
->itemNew
.hItem
;
635 tvi
.mask
= TVIF_CHILDREN
;
637 SendMessageW(This
->hwnd_tv
, TVM_SETITEMW
, 0, (LPARAM
)&tvi
);
645 static LRESULT
on_tvn_itemexpandedw(NSTC2Impl
*This
, LPARAM lParam
)
647 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)lParam
;
651 psi
= shellitem_from_treeitem(This
, nmtv
->itemNew
.hItem
);
652 events_OnAfterExpand(This
, psi
);
656 static LRESULT
on_tvn_selchangedw(NSTC2Impl
*This
, LPARAM lParam
)
658 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)lParam
;
659 IShellItemArray
*psia
;
664 /* Note: Only supports one selected item. */
665 psi
= shellitem_from_treeitem(This
, nmtv
->itemNew
.hItem
);
666 hr
= SHCreateShellItemArrayFromShellItem(psi
, &IID_IShellItemArray
, (void**)&psia
);
669 events_OnSelectionChanged(This
, psia
);
670 IShellItemArray_Release(psia
);
676 static LRESULT
on_nm_click(NSTC2Impl
*This
, NMHDR
*nmhdr
)
681 TRACE("%p (%p)\n", This
, nmhdr
);
683 GetCursorPos(&tvhit
.pt
);
684 ScreenToClient(This
->hwnd_tv
, &tvhit
.pt
);
685 SendMessageW(This
->hwnd_tv
, TVM_HITTEST
, 0, (LPARAM
)&tvhit
);
687 if(tvhit
.flags
& (TVHT_NOWHERE
|TVHT_ABOVE
|TVHT_BELOW
))
690 /* TVHT_ maps onto the corresponding NSTCEHT_ */
691 psi
= shellitem_from_treeitem(This
, tvhit
.hItem
);
692 return FAILED(events_OnItemClick(This
, psi
, tvhit
.flags
, NSTCECT_LBUTTON
));
695 static LRESULT
on_wm_mbuttonup(NSTC2Impl
*This
, WPARAM wParam
, LPARAM lParam
)
700 TRACE("%p (%Ix, %Ix)\n", This
, wParam
, lParam
);
702 tvhit
.pt
.x
= (int)(short)LOWORD(lParam
);
703 tvhit
.pt
.y
= (int)(short)HIWORD(lParam
);
705 SendMessageW(This
->hwnd_tv
, TVM_HITTEST
, 0, (LPARAM
)&tvhit
);
707 /* Seems to generate only ONITEM and ONITEMICON */
708 if( !(tvhit
.flags
& (TVHT_ONITEM
|TVHT_ONITEMICON
)) )
711 psi
= shellitem_from_treeitem(This
, tvhit
.hItem
);
712 hr
= events_OnItemClick(This
, psi
, tvhit
.flags
, NSTCECT_MBUTTON
);
720 static LRESULT
on_kbd_event(NSTC2Impl
*This
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
724 TRACE("%p : %d, %Ix, %Ix\n", This
, uMsg
, wParam
, lParam
);
726 /* Handled by the client? */
727 if(FAILED(events_OnKeyboardInput(This
, uMsg
, wParam
, lParam
)))
730 if(uMsg
== WM_KEYDOWN
)
735 psi
= get_selected_shellitem(This
);
736 FIXME("Deletion of file requested (shellitem: %p).\n", psi
);
740 hitem
= get_selected_treeitem(This
);
741 SendMessageW(This
->hwnd_tv
, TVM_EDITLABELW
, 0, (LPARAM
)hitem
);
746 /* Let the TreeView handle the key */
750 static LRESULT CALLBACK
tv_wndproc(HWND hWnd
, UINT uMessage
, WPARAM wParam
, LPARAM lParam
)
752 NSTC2Impl
*This
= (NSTC2Impl
*)GetPropW(hWnd
, L
"PROP_THIS");
761 if(on_kbd_event(This
, uMessage
, wParam
, lParam
))
765 case WM_MBUTTONUP
: return on_wm_mbuttonup(This
, wParam
, lParam
);
768 /* Pass the message on to the treeview */
769 return CallWindowProcW(This
->tv_oldwndproc
, hWnd
, uMessage
, wParam
, lParam
);
772 static LRESULT CALLBACK
NSTC2_WndProc(HWND hWnd
, UINT uMessage
,
773 WPARAM wParam
, LPARAM lParam
)
775 NSTC2Impl
*This
= (NSTC2Impl
*)GetWindowLongPtrW(hWnd
, GWLP_USERDATA
);
780 case WM_NCCREATE
: return create_namespacetree(hWnd
, (CREATESTRUCTW
*)lParam
);
781 case WM_SIZE
: return resize_namespacetree(This
);
782 case WM_DESTROY
: return destroy_namespacetree(This
);
784 nmhdr
= (NMHDR
*)lParam
;
787 case NM_CLICK
: return on_nm_click(This
, nmhdr
);
788 case TVN_DELETEITEMW
: return on_tvn_deleteitemw(This
, lParam
);
789 case TVN_GETDISPINFOW
: return on_tvn_getdispinfow(This
, lParam
);
790 case TVN_ITEMEXPANDINGW
: return on_tvn_itemexpandingw(This
, lParam
);
791 case TVN_ITEMEXPANDEDW
: return on_tvn_itemexpandedw(This
, lParam
);
792 case TVN_SELCHANGEDW
: return on_tvn_selchangedw(This
, lParam
);
796 default: return DefWindowProcW(hWnd
, uMessage
, wParam
, lParam
);
801 /**************************************************************************
802 * INameSpaceTreeControl2 Implementation
804 static HRESULT WINAPI
NSTC2_fnQueryInterface(INameSpaceTreeControl2
* iface
,
808 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
809 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
812 if(IsEqualIID(riid
, &IID_INameSpaceTreeControl2
) ||
813 IsEqualIID(riid
, &IID_INameSpaceTreeControl
) ||
814 IsEqualIID(riid
, &IID_IUnknown
))
816 *ppvObject
= &This
->INameSpaceTreeControl2_iface
;
818 else if(IsEqualIID(riid
, &IID_IOleWindow
))
820 *ppvObject
= &This
->IOleWindow_iface
;
825 IUnknown_AddRef((IUnknown
*)*ppvObject
);
829 return E_NOINTERFACE
;
832 static ULONG WINAPI
NSTC2_fnAddRef(INameSpaceTreeControl2
* iface
)
834 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
835 LONG ref
= InterlockedIncrement(&This
->ref
);
837 TRACE("%p - ref %ld\n", This
, ref
);
842 static ULONG WINAPI
NSTC2_fnRelease(INameSpaceTreeControl2
* iface
)
844 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
845 LONG ref
= InterlockedDecrement(&This
->ref
);
847 TRACE("%p - ref: %ld\n", This
, ref
);
853 EFRAME_UnlockModule();
859 static HRESULT WINAPI
NSTC2_fnInitialize(INameSpaceTreeControl2
* iface
,
862 NSTCSTYLE nstcsFlags
)
864 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
866 DWORD window_style
, window_ex_style
;
867 INITCOMMONCONTROLSEX icex
;
869 static const WCHAR NSTC2_CLASS_NAME
[] = L
"NamespaceTreeControl";
871 TRACE("%p (%p, %p, %lx)\n", This
, hwndParent
, prc
, nstcsFlags
);
873 if(nstcsFlags
& unsupported_styles
)
874 FIXME("0x%08lx contains the unsupported style(s) 0x%08lx\n",
875 nstcsFlags
, nstcsFlags
& unsupported_styles
);
877 This
->style
= nstcsFlags
;
879 icex
.dwSize
= sizeof( icex
);
880 icex
.dwICC
= ICC_TREEVIEW_CLASSES
;
881 InitCommonControlsEx( &icex
);
883 if(!GetClassInfoW(explorerframe_hinstance
, NSTC2_CLASS_NAME
, &wc
))
885 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
886 wc
.lpfnWndProc
= NSTC2_WndProc
;
889 wc
.hInstance
= explorerframe_hinstance
;
891 wc
.hCursor
= LoadCursorW(0, (LPWSTR
)IDC_ARROW
);
892 wc
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
893 wc
.lpszMenuName
= NULL
;
894 wc
.lpszClassName
= NSTC2_CLASS_NAME
;
896 if (!RegisterClassW(&wc
)) return E_FAIL
;
899 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
900 window_style
= WS_VISIBLE
| WS_CHILD
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
|
901 (nstcsFlags
& NSTCS_BORDER
? WS_BORDER
: 0);
902 window_ex_style
= nstcsFlags
& NSTCS_TABSTOP
? WS_EX_CONTROLPARENT
: 0;
909 This
->hwnd_main
= CreateWindowExW(window_ex_style
, NSTC2_CLASS_NAME
, NULL
, window_style
,
910 rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
911 hwndParent
, 0, explorerframe_hinstance
, This
);
915 ERR("Failed to create the window.\n");
916 return HRESULT_FROM_WIN32(GetLastError());
922 static HRESULT WINAPI
NSTC2_fnTreeAdvise(INameSpaceTreeControl2
* iface
, IUnknown
*handler
, DWORD
*cookie
)
924 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
926 TRACE("%p (%p, %p)\n", This
, handler
, cookie
);
930 /* Only one client supported */
931 if (This
->events
|| This
->customdraw
|| This
->dragdrop
)
934 /* FIXME: request INameSpaceTreeAccessible too */
935 IUnknown_QueryInterface(handler
, &IID_INameSpaceTreeControlEvents
, (void**)&This
->events
);
936 IUnknown_QueryInterface(handler
, &IID_INameSpaceTreeControlCustomDraw
, (void**)&This
->customdraw
);
937 IUnknown_QueryInterface(handler
, &IID_INameSpaceTreeControlDropHandler
, (void**)&This
->dragdrop
);
939 if (This
->events
|| This
->customdraw
|| This
->dragdrop
)
942 return *cookie
? S_OK
: E_FAIL
;
945 static HRESULT WINAPI
NSTC2_fnTreeUnadvise(INameSpaceTreeControl2
* iface
, DWORD cookie
)
947 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
949 TRACE("%p (%lx)\n", This
, cookie
);
951 /* The cookie is ignored. */
955 INameSpaceTreeControlEvents_Release(This
->events
);
959 if (This
->customdraw
)
961 INameSpaceTreeControlCustomDraw_Release(This
->customdraw
);
962 This
->customdraw
= NULL
;
967 INameSpaceTreeControlDropHandler_Release(This
->dragdrop
);
968 This
->dragdrop
= NULL
;
974 static HRESULT WINAPI
NSTC2_fnInsertRoot(INameSpaceTreeControl2
* iface
,
977 SHCONTF grfEnumFlags
,
978 NSTCROOTSTYLE grfRootStyle
,
979 IShellItemFilter
*pif
)
981 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
983 struct list
*add_after_entry
;
984 HTREEITEM add_after_hitem
;
987 TRACE("%p, %d, %p, %lx, %lx, %p\n", This
, iIndex
, psiRoot
, grfEnumFlags
, grfRootStyle
, pif
);
989 new_root
= malloc(sizeof(*new_root
));
991 return E_OUTOFMEMORY
;
993 new_root
->psi
= psiRoot
;
994 new_root
->enum_flags
= grfEnumFlags
;
995 new_root
->root_style
= grfRootStyle
;
998 /* We want to keep the roots in the internal list and in the
999 * treeview in the same order. */
1000 add_after_entry
= &This
->roots
;
1001 for(i
= 0; i
< max(0, iIndex
) && list_next(&This
->roots
, add_after_entry
); i
++)
1002 add_after_entry
= list_next(&This
->roots
, add_after_entry
);
1004 if(add_after_entry
== &This
->roots
)
1005 add_after_hitem
= TVI_FIRST
;
1007 add_after_hitem
= LIST_ENTRY(add_after_entry
, nstc_root
, entry
)->htreeitem
;
1009 new_root
->htreeitem
= insert_shellitem(This
, psiRoot
, TVI_ROOT
, add_after_hitem
);
1010 if(!new_root
->htreeitem
)
1012 WARN("Failed to add the root.\n");
1017 list_add_after(add_after_entry
, &new_root
->entry
);
1018 events_OnItemAdded(This
, psiRoot
, TRUE
);
1020 if(grfRootStyle
& NSTCRS_HIDDEN
)
1023 tvi
.mask
= TVIF_STATEEX
;
1024 tvi
.uStateEx
= TVIS_EX_FLAT
;
1025 tvi
.hItem
= new_root
->htreeitem
;
1027 SendMessageW(This
->hwnd_tv
, TVM_SETITEMW
, 0, (LPARAM
)&tvi
);
1030 if(grfRootStyle
& NSTCRS_EXPANDED
)
1031 SendMessageW(This
->hwnd_tv
, TVM_EXPAND
, TVE_EXPAND
,
1032 (LPARAM
)new_root
->htreeitem
);
1037 static HRESULT WINAPI
NSTC2_fnAppendRoot(INameSpaceTreeControl2
* iface
,
1038 IShellItem
*psiRoot
,
1039 SHCONTF grfEnumFlags
,
1040 NSTCROOTSTYLE grfRootStyle
,
1041 IShellItemFilter
*pif
)
1043 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1045 TRACE("%p, %p, %lx, %lx, %p\n",
1046 This
, psiRoot
, grfEnumFlags
, grfRootStyle
, pif
);
1048 root_count
= list_count(&This
->roots
);
1050 return INameSpaceTreeControl2_InsertRoot(iface
, root_count
, psiRoot
, grfEnumFlags
, grfRootStyle
, pif
);
1053 static HRESULT WINAPI
NSTC2_fnRemoveRoot(INameSpaceTreeControl2
* iface
,
1054 IShellItem
*psiRoot
)
1056 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1057 nstc_root
*cursor
, *root
= NULL
;
1058 TRACE("%p (%p)\n", This
, psiRoot
);
1061 return E_NOINTERFACE
;
1063 LIST_FOR_EACH_ENTRY(cursor
, &This
->roots
, nstc_root
, entry
)
1067 hr
= IShellItem_Compare(psiRoot
, cursor
->psi
, SICHINT_DISPLAY
, &order
);
1075 TRACE("root %p\n", root
);
1078 events_OnItemDeleted(This
, root
->psi
, TRUE
);
1079 SendMessageW(This
->hwnd_tv
, TVM_DELETEITEM
, 0, (LPARAM
)root
->htreeitem
);
1080 list_remove(&root
->entry
);
1086 WARN("No matching root found.\n");
1091 static HRESULT WINAPI
NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2
* iface
)
1093 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1094 nstc_root
*cur1
, *cur2
;
1096 TRACE("%p\n", This
);
1098 if (list_empty(&This
->roots
))
1099 return E_INVALIDARG
;
1101 LIST_FOR_EACH_ENTRY_SAFE(cur1
, cur2
, &This
->roots
, nstc_root
, entry
)
1102 INameSpaceTreeControl2_RemoveRoot(iface
, cur1
->psi
);
1107 static HRESULT WINAPI
NSTC2_fnGetRootItems(INameSpaceTreeControl2
* iface
,
1108 IShellItemArray
**ppsiaRootItems
)
1110 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1112 LPITEMIDLIST
*array
;
1116 TRACE("%p (%p)\n", This
, ppsiaRootItems
);
1118 count
= list_count(&This
->roots
);
1121 return E_INVALIDARG
;
1123 array
= malloc(sizeof(LPITEMIDLIST
)*count
);
1126 LIST_FOR_EACH_ENTRY(root
, &This
->roots
, nstc_root
, entry
)
1127 SHGetIDListFromObject((IUnknown
*)root
->psi
, &array
[i
++]);
1129 SHGetDesktopFolder(&psf
);
1130 hr
= SHCreateShellItemArray(NULL
, psf
, count
, (PCUITEMID_CHILD_ARRAY
)array
,
1132 IShellFolder_Release(psf
);
1134 for(i
= 0; i
< count
; i
++)
1142 static HRESULT WINAPI
NSTC2_fnSetItemState(INameSpaceTreeControl2
* iface
,
1144 NSTCITEMSTATE nstcisMask
,
1145 NSTCITEMSTATE nstcisFlags
)
1147 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1151 TRACE("%p (%p, %lx, %lx)\n", This
, psi
, nstcisMask
, nstcisFlags
);
1153 hitem
= treeitem_from_shellitem(This
, psi
);
1154 if(!hitem
) return E_INVALIDARG
;
1156 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1157 in two TVM_SETITEMW's */
1158 if((nstcisMask
&nstcisFlags
) & NSTCIS_SELECTED
)
1160 SendMessageW(This
->hwnd_tv
, TVM_SELECTITEM
, TVGN_CARET
, (LPARAM
)hitem
);
1161 SendMessageW(This
->hwnd_tv
, TVM_ENSUREVISIBLE
, 0, (LPARAM
)hitem
);
1163 if((nstcisMask
&nstcisFlags
) & NSTCIS_SELECTEDNOEXPAND
)
1165 SendMessageW(This
->hwnd_tv
, TVM_SELECTITEM
, TVGN_CARET
|TVSI_NOSINGLEEXPAND
, (LPARAM
)hitem
);
1168 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1169 if((nstcisMask
|nstcisFlags
) & NSTCIS_EXPANDED
)
1171 WPARAM arg
= nstcisFlags
&NSTCIS_EXPANDED
? TVE_EXPAND
:TVE_COLLAPSE
;
1172 SendMessageW(This
->hwnd_tv
, TVM_EXPAND
, arg
, (LPARAM
)hitem
);
1175 if(nstcisMask
& NSTCIS_DISABLED
)
1176 tvi
.mask
= TVIF_STATE
| TVIF_STATEEX
;
1177 else if( ((nstcisMask
^nstcisFlags
) & (NSTCIS_SELECTED
|NSTCIS_EXPANDED
|NSTCIS_SELECTEDNOEXPAND
)) ||
1178 ((nstcisMask
|nstcisFlags
) & NSTCIS_BOLD
) ||
1179 (nstcisFlags
& NSTCIS_DISABLED
) )
1180 tvi
.mask
= TVIF_STATE
;
1186 tvi
.stateMask
= tvi
.state
= 0;
1187 tvi
.stateMask
|= ((nstcisFlags
^nstcisMask
)&NSTCIS_SELECTED
) ? TVIS_SELECTED
: 0;
1188 tvi
.stateMask
|= (nstcisMask
|nstcisFlags
)&NSTCIS_BOLD
? TVIS_BOLD
:0;
1189 tvi
.state
|= (nstcisMask
&nstcisFlags
)&NSTCIS_BOLD
? TVIS_BOLD
:0;
1191 if((nstcisMask
&NSTCIS_EXPANDED
)^(nstcisFlags
&NSTCIS_EXPANDED
))
1196 tvi
.uStateEx
= (nstcisFlags
&nstcisMask
)&NSTCIS_DISABLED
?TVIS_EX_DISABLED
:0;
1199 SendMessageW(This
->hwnd_tv
, TVM_SETITEMW
, 0, (LPARAM
)&tvi
);
1205 static HRESULT WINAPI
NSTC2_fnGetItemState(INameSpaceTreeControl2
* iface
,
1207 NSTCITEMSTATE nstcisMask
,
1208 NSTCITEMSTATE
*pnstcisFlags
)
1210 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1213 TRACE("%p (%p, %lx, %p)\n", This
, psi
, nstcisMask
, pnstcisFlags
);
1215 hitem
= treeitem_from_shellitem(This
, psi
);
1217 return E_INVALIDARG
;
1222 tvi
.mask
= TVIF_STATE
;
1223 tvi
.stateMask
= TVIS_SELECTED
|TVIS_EXPANDED
|TVIS_BOLD
;
1225 if(nstcisMask
& NSTCIS_DISABLED
)
1226 tvi
.mask
|= TVIF_STATEEX
;
1228 SendMessageW(This
->hwnd_tv
, TVM_GETITEMW
, 0, (LPARAM
)&tvi
);
1229 *pnstcisFlags
|= (tvi
.state
& TVIS_SELECTED
)?NSTCIS_SELECTED
:0;
1230 *pnstcisFlags
|= (tvi
.state
& TVIS_EXPANDED
)?NSTCIS_EXPANDED
:0;
1231 *pnstcisFlags
|= (tvi
.state
& TVIS_BOLD
)?NSTCIS_BOLD
:0;
1232 *pnstcisFlags
|= (tvi
.uStateEx
& TVIS_EX_DISABLED
)?NSTCIS_DISABLED
:0;
1234 *pnstcisFlags
&= nstcisMask
;
1239 static HRESULT WINAPI
NSTC2_fnGetSelectedItems(INameSpaceTreeControl2
* iface
,
1240 IShellItemArray
**psiaItems
)
1242 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1243 IShellItem
*psiselected
;
1245 TRACE("%p (%p)\n", This
, psiaItems
);
1247 psiselected
= get_selected_shellitem(This
);
1254 return SHCreateShellItemArrayFromShellItem(psiselected
, &IID_IShellItemArray
,
1258 static HRESULT WINAPI
NSTC2_fnGetItemCustomState(INameSpaceTreeControl2
* iface
,
1262 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1263 FIXME("stub, %p (%p, %p)\n", This
, psi
, piStateNumber
);
1267 static HRESULT WINAPI
NSTC2_fnSetItemCustomState(INameSpaceTreeControl2
* iface
,
1271 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1272 FIXME("stub, %p (%p, %d)\n", This
, psi
, iStateNumber
);
1276 static HRESULT WINAPI
NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2
* iface
,
1279 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1282 TRACE("%p (%p)\n", This
, psi
);
1284 hitem
= treeitem_from_shellitem(This
, psi
);
1287 SendMessageW(This
->hwnd_tv
, TVM_ENSUREVISIBLE
, 0, (WPARAM
)hitem
);
1291 return E_INVALIDARG
;
1294 static HRESULT WINAPI
NSTC2_fnSetTheme(INameSpaceTreeControl2
* iface
,
1297 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1298 FIXME("stub, %p (%p)\n", This
, pszTheme
);
1302 static HRESULT WINAPI
NSTC2_fnGetNextItem(INameSpaceTreeControl2
* iface
,
1305 IShellItem
**ppsiNext
)
1307 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1308 HTREEITEM hitem
, hnext
;
1310 TRACE("%p (%p, %x, %p)\n", This
, psi
, nstcgi
, ppsiNext
);
1312 if(!ppsiNext
) return E_POINTER
;
1313 if(!psi
) return E_FAIL
;
1317 hitem
= treeitem_from_shellitem(This
, psi
);
1319 return E_INVALIDARG
;
1323 case NSTCGNI_NEXT
: tvgn
= TVGN_NEXT
; break;
1324 case NSTCGNI_NEXTVISIBLE
: tvgn
= TVGN_NEXTVISIBLE
; break;
1325 case NSTCGNI_PREV
: tvgn
= TVGN_PREVIOUS
; break;
1326 case NSTCGNI_PREVVISIBLE
: tvgn
= TVGN_PREVIOUSVISIBLE
; break;
1327 case NSTCGNI_PARENT
: tvgn
= TVGN_PARENT
; break;
1328 case NSTCGNI_CHILD
: tvgn
= TVGN_CHILD
; break;
1329 case NSTCGNI_FIRSTVISIBLE
: tvgn
= TVGN_FIRSTVISIBLE
; break;
1330 case NSTCGNI_LASTVISIBLE
: tvgn
= TVGN_LASTVISIBLE
; break;
1332 FIXME("Unknown nstcgi value %d\n", nstcgi
);
1336 hnext
= (HTREEITEM
)SendMessageW(This
->hwnd_tv
, TVM_GETNEXTITEM
, tvgn
, (WPARAM
)hitem
);
1339 *ppsiNext
= shellitem_from_treeitem(This
, hnext
);
1340 IShellItem_AddRef(*ppsiNext
);
1347 static HRESULT WINAPI
NSTC2_fnHitTest(INameSpaceTreeControl2
* iface
,
1349 IShellItem
**ppsiOut
)
1351 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1353 TRACE("%p (%p, %p)\n", This
, ppsiOut
, ppt
);
1355 if(!ppt
|| !ppsiOut
)
1360 hitem
= treeitem_from_point(This
, ppt
, NULL
);
1362 *ppsiOut
= shellitem_from_treeitem(This
, hitem
);
1366 IShellItem_AddRef(*ppsiOut
);
1373 static HRESULT WINAPI
NSTC2_fnGetItemRect(INameSpaceTreeControl2
* iface
,
1377 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1379 TRACE("%p (%p, %p)\n", This
, psi
, prect
);
1384 hitem
= treeitem_from_shellitem(This
, psi
);
1387 *(HTREEITEM
*)prect
= hitem
;
1388 if(SendMessageW(This
->hwnd_tv
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)prect
))
1390 MapWindowPoints(This
->hwnd_tv
, HWND_DESKTOP
, (POINT
*)prect
, 2);
1395 return E_INVALIDARG
;
1398 static HRESULT WINAPI
NSTC2_fnCollapseAll(INameSpaceTreeControl2
* iface
)
1400 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1402 TRACE("%p\n", This
);
1404 LIST_FOR_EACH_ENTRY(root
, &This
->roots
, nstc_root
, entry
)
1405 collapse_all(This
, root
->htreeitem
);
1410 static HRESULT WINAPI
NSTC2_fnSetControlStyle(INameSpaceTreeControl2
* iface
,
1411 NSTCSTYLE nstcsMask
,
1412 NSTCSTYLE nstcsStyle
)
1414 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1415 static const DWORD tv_style_flags
=
1416 NSTCS_HASEXPANDOS
| NSTCS_HASLINES
| NSTCS_FULLROWSELECT
|
1417 NSTCS_HORIZONTALSCROLL
| NSTCS_ROOTHASEXPANDO
|
1418 NSTCS_SHOWSELECTIONALWAYS
| NSTCS_NOINFOTIP
| NSTCS_EVENHEIGHT
|
1419 NSTCS_DISABLEDRAGDROP
| NSTCS_NOEDITLABELS
| NSTCS_CHECKBOXES
;
1420 static const DWORD host_style_flags
= NSTCS_TABSTOP
| NSTCS_BORDER
;
1421 static const DWORD nstc_flags
=
1422 NSTCS_SINGLECLICKEXPAND
| NSTCS_NOREPLACEOPEN
| NSTCS_NOORDERSTREAM
|
1423 NSTCS_FAVORITESMODE
| NSTCS_EMPTYTEXT
| NSTCS_ALLOWJUNCTIONS
|
1424 NSTCS_SHOWTABSBUTTON
| NSTCS_SHOWDELETEBUTTON
| NSTCS_SHOWREFRESHBUTTON
;
1425 TRACE("%p (%lx, %lx)\n", This
, nstcsMask
, nstcsStyle
);
1427 /* Fail if there is an attempt to set an unknown style. */
1428 if(nstcsMask
& ~(tv_style_flags
| host_style_flags
| nstc_flags
))
1431 if(nstcsMask
& tv_style_flags
)
1434 treeview_style_from_nstcs(This
, nstcsStyle
, nstcsMask
, &new_style
);
1435 SetWindowLongPtrW(This
->hwnd_tv
, GWL_STYLE
, new_style
);
1438 /* Flags affecting the host window */
1439 if(nstcsMask
& NSTCS_BORDER
)
1441 DWORD new_style
= GetWindowLongPtrW(This
->hwnd_main
, GWL_STYLE
);
1442 new_style
&= ~WS_BORDER
;
1443 new_style
|= nstcsStyle
& NSTCS_BORDER
? WS_BORDER
: 0;
1444 SetWindowLongPtrW(This
->hwnd_main
, GWL_STYLE
, new_style
);
1446 if(nstcsMask
& NSTCS_TABSTOP
)
1448 DWORD new_style
= GetWindowLongPtrW(This
->hwnd_main
, GWL_EXSTYLE
);
1449 new_style
&= ~WS_EX_CONTROLPARENT
;
1450 new_style
|= nstcsStyle
& NSTCS_TABSTOP
? WS_EX_CONTROLPARENT
: 0;
1451 SetWindowLongPtrW(This
->hwnd_main
, GWL_EXSTYLE
, new_style
);
1454 if((nstcsStyle
& nstcsMask
) & unsupported_styles
)
1455 FIXME("mask & style (0x%08lx) contains unsupported style(s): 0x%08lx\n",
1456 (nstcsStyle
& nstcsMask
),
1457 (nstcsStyle
& nstcsMask
) & unsupported_styles
);
1459 This
->style
&= ~nstcsMask
;
1460 This
->style
|= (nstcsStyle
& nstcsMask
);
1465 static HRESULT WINAPI
NSTC2_fnGetControlStyle(INameSpaceTreeControl2
* iface
,
1466 NSTCSTYLE nstcsMask
,
1467 NSTCSTYLE
*pnstcsStyle
)
1469 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1470 TRACE("%p (%lx, %p)\n", This
, nstcsMask
, pnstcsStyle
);
1472 *pnstcsStyle
= (This
->style
& nstcsMask
);
1477 static HRESULT WINAPI
NSTC2_fnSetControlStyle2(INameSpaceTreeControl2
* iface
,
1478 NSTCSTYLE2 nstcsMask
,
1479 NSTCSTYLE2 nstcsStyle
)
1481 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1482 TRACE("%p (%x, %x)\n", This
, nstcsMask
, nstcsStyle
);
1484 if((nstcsStyle
& nstcsMask
) & unsupported_styles2
)
1485 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08lx\n",
1486 (nstcsStyle
& nstcsMask
),
1487 (nstcsStyle
& nstcsMask
) & unsupported_styles2
);
1489 This
->style2
&= ~nstcsMask
;
1490 This
->style2
|= (nstcsStyle
& nstcsMask
);
1495 static HRESULT WINAPI
NSTC2_fnGetControlStyle2(INameSpaceTreeControl2
* iface
,
1496 NSTCSTYLE2 nstcsMask
,
1497 NSTCSTYLE2
*pnstcsStyle
)
1499 NSTC2Impl
*This
= impl_from_INameSpaceTreeControl2(iface
);
1500 TRACE("%p (%x, %p)\n", This
, nstcsMask
, pnstcsStyle
);
1502 *pnstcsStyle
= (This
->style2
& nstcsMask
);
1507 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2
= {
1508 NSTC2_fnQueryInterface
,
1513 NSTC2_fnTreeUnadvise
,
1517 NSTC2_fnRemoveAllRoots
,
1518 NSTC2_fnGetRootItems
,
1519 NSTC2_fnSetItemState
,
1520 NSTC2_fnGetItemState
,
1521 NSTC2_fnGetSelectedItems
,
1522 NSTC2_fnGetItemCustomState
,
1523 NSTC2_fnSetItemCustomState
,
1524 NSTC2_fnEnsureItemVisible
,
1526 NSTC2_fnGetNextItem
,
1528 NSTC2_fnGetItemRect
,
1529 NSTC2_fnCollapseAll
,
1530 NSTC2_fnSetControlStyle
,
1531 NSTC2_fnGetControlStyle
,
1532 NSTC2_fnSetControlStyle2
,
1533 NSTC2_fnGetControlStyle2
1536 /**************************************************************************
1537 * IOleWindow Implementation
1540 static HRESULT WINAPI
IOW_fnQueryInterface(IOleWindow
*iface
, REFIID riid
, void **ppvObject
)
1542 NSTC2Impl
*This
= impl_from_IOleWindow(iface
);
1543 return INameSpaceTreeControl2_QueryInterface(&This
->INameSpaceTreeControl2_iface
, riid
, ppvObject
);
1546 static ULONG WINAPI
IOW_fnAddRef(IOleWindow
*iface
)
1548 NSTC2Impl
*This
= impl_from_IOleWindow(iface
);
1549 return INameSpaceTreeControl2_AddRef(&This
->INameSpaceTreeControl2_iface
);
1552 static ULONG WINAPI
IOW_fnRelease(IOleWindow
*iface
)
1554 NSTC2Impl
*This
= impl_from_IOleWindow(iface
);
1555 return INameSpaceTreeControl2_Release(&This
->INameSpaceTreeControl2_iface
);
1558 static HRESULT WINAPI
IOW_fnGetWindow(IOleWindow
*iface
, HWND
*phwnd
)
1560 NSTC2Impl
*This
= impl_from_IOleWindow(iface
);
1561 TRACE("%p (%p)\n", This
, phwnd
);
1563 *phwnd
= This
->hwnd_main
;
1567 static HRESULT WINAPI
IOW_fnContextSensitiveHelp(IOleWindow
*iface
, BOOL fEnterMode
)
1569 NSTC2Impl
*This
= impl_from_IOleWindow(iface
);
1570 TRACE("%p (%d)\n", This
, fEnterMode
);
1572 /* Not implemented */
1576 static const IOleWindowVtbl vt_IOleWindow
= {
1577 IOW_fnQueryInterface
,
1581 IOW_fnContextSensitiveHelp
1584 HRESULT
NamespaceTreeControl_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, void **ppv
)
1589 TRACE ("%p %s %p\n", pUnkOuter
, debugstr_guid(riid
), ppv
);
1594 return CLASS_E_NOAGGREGATION
;
1596 EFRAME_LockModule();
1598 nstc
= calloc(1, sizeof(*nstc
));
1600 return E_OUTOFMEMORY
;
1603 nstc
->INameSpaceTreeControl2_iface
.lpVtbl
= &vt_INameSpaceTreeControl2
;
1604 nstc
->IOleWindow_iface
.lpVtbl
= &vt_IOleWindow
;
1606 list_init(&nstc
->roots
);
1608 ret
= INameSpaceTreeControl2_QueryInterface(&nstc
->INameSpaceTreeControl2_iface
, riid
, ppv
);
1609 INameSpaceTreeControl2_Release(&nstc
->INameSpaceTreeControl2_iface
);
1611 TRACE("--(%p)\n", ppv
);