comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / explorerframe / nstc.c
blob3b56d33367af4d0f2629ec47e06e0a61b2f5324b
1 /*
2 * NamespaceTreeControl implementation.
4 * Copyright 2010 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "shellapi.h"
31 #include "commctrl.h"
32 #include "commoncontrols.h"
34 #include "wine/list.h"
35 #include "wine/debug.h"
37 #include "explorerframe_main.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
41 typedef struct nstc_root {
42 IShellItem *psi;
43 HTREEITEM htreeitem;
44 SHCONTF enum_flags;
45 NSTCROOTSTYLE root_style;
46 IShellItemFilter *pif;
47 struct list entry;
48 } nstc_root;
50 typedef struct {
51 INameSpaceTreeControl2 INameSpaceTreeControl2_iface;
52 IOleWindow IOleWindow_iface;
53 LONG ref;
55 HWND hwnd_main;
56 HWND hwnd_tv;
58 WNDPROC tv_oldwndproc;
60 NSTCSTYLE style;
61 NSTCSTYLE2 style2;
62 struct list roots;
64 INameSpaceTreeControlCustomDraw *customdraw;
65 INameSpaceTreeControlDropHandler *dragdrop;
66 INameSpaceTreeControlEvents *events;
67 } NSTC2Impl;
69 static const DWORD unsupported_styles =
70 NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
71 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
72 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
73 static const DWORD unsupported_styles2 =
74 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
75 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
77 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
79 return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
82 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
84 return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
87 /* Forward declarations */
88 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
90 /*************************************************************************
91 * NamespaceTree event wrappers
93 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
94 int *piDefaultIcon, int *piOpenIcon)
96 HRESULT ret;
97 LONG refcount;
98 if(!This->events) return E_NOTIMPL;
100 refcount = IShellItem_AddRef(psi);
101 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->events, psi, piDefaultIcon, piOpenIcon);
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_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
109 HRESULT ret;
110 LONG refcount;
111 if(!This->events) return S_OK;
113 refcount = IShellItem_AddRef(psi);
114 ret = INameSpaceTreeControlEvents_OnItemAdded(This->events, 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_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
122 HRESULT ret;
123 LONG refcount;
124 if(!This->events) return S_OK;
126 refcount = IShellItem_AddRef(psi);
127 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->events, psi, fIsRoot);
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_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
135 HRESULT ret;
136 LONG refcount;
137 if(!This->events) return S_OK;
139 refcount = IShellItem_AddRef(psi);
140 ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->events, 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_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
148 HRESULT ret;
149 LONG refcount;
150 if(!This->events) return S_OK;
152 refcount = IShellItem_AddRef(psi);
153 ret = INameSpaceTreeControlEvents_OnAfterExpand(This->events, psi);
154 if(IShellItem_Release(psi) < refcount - 1)
155 ERR("ShellItem was released by client - please file a bug.\n");
156 return ret;
159 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
160 NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
162 HRESULT ret;
163 LONG refcount;
164 if(!This->events) return S_OK;
166 refcount = IShellItem_AddRef(psi);
167 ret = INameSpaceTreeControlEvents_OnItemClick(This->events, psi, nstceHitTest, nstceClickType);
168 if(IShellItem_Release(psi) < refcount - 1)
169 ERR("ShellItem was released by client - please file a bug.\n");
170 return ret;
173 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
175 if(!This->events) return S_OK;
177 return INameSpaceTreeControlEvents_OnSelectionChanged(This->events, psia);
180 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
182 if(!This->events) return S_OK;
184 return INameSpaceTreeControlEvents_OnKeyboardInput(This->events, uMsg, wParam, lParam);
187 /*************************************************************************
188 * NamespaceTree helper functions
190 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
191 NSTCSTYLE nstcs_mask, DWORD *new_style)
193 DWORD old_style, tv_mask = 0;
194 TRACE("%p, %lx, %lx, %p\n", This, nstcs, nstcs_mask, new_style);
196 if(This->hwnd_tv)
197 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
198 else
199 old_style = /* The default */
200 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
201 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
202 TVS_EDITLABELS | TVS_TRACKSELECT;
204 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
205 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
206 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
207 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
208 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
209 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
210 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
211 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
212 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
213 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
214 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
215 if(nstcs_mask & NSTCS_SINGLECLICKEXPAND) tv_mask |= TVS_SINGLEEXPAND;
217 *new_style = 0;
219 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
220 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
221 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
222 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
223 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
224 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
225 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
226 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
227 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
228 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
229 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
230 if(nstcs & NSTCS_SINGLECLICKEXPAND) *new_style |= TVS_SINGLEEXPAND;
232 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
234 TRACE("old: %08lx, new: %08lx\n", old_style, *new_style);
236 return old_style^*new_style;
239 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
241 TVITEMEXW tvi;
243 tvi.mask = TVIF_PARAM;
244 tvi.lParam = 0;
245 tvi.hItem = hitem;
247 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
249 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
250 return (IShellItem*)tvi.lParam;
253 /* Returns the root that the given treeitem belongs to. */
254 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
256 HTREEITEM tmp, hroot = hitem;
257 nstc_root *root;
259 /* Work our way up the hierarchy */
260 for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
261 tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
263 /* Search through the list of roots for a match */
264 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
265 if(root->htreeitem == hroot)
266 break;
268 TRACE("root is %p\n", root);
269 return root;
272 /* Find a shellitem in the tree, starting from the given node. */
273 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
274 IShellItem *psi)
276 IShellItem *psi_node;
277 HTREEITEM next, result = NULL;
278 HRESULT hr;
279 int cmpo;
280 TRACE("%p, %p, %p\n", This, node, psi);
282 /* Check this node */
283 psi_node = shellitem_from_treeitem(This, node);
284 hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
285 if(hr == S_OK)
286 return node;
288 /* Any children? */
289 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
290 TVGN_CHILD, (LPARAM)node);
291 if(next)
293 result = search_for_shellitem(This, next, psi);
294 if(result) return result;
297 /* Try our next sibling. */
298 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
299 TVGN_NEXT, (LPARAM)node);
300 if(next)
301 result = search_for_shellitem(This, next, psi);
303 return result;
306 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
308 HTREEITEM root;
309 TRACE("%p, %p\n", This, psi);
311 root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
312 TVGN_ROOT, 0);
313 if(!root)
314 return NULL;
316 return search_for_shellitem(This, root, psi);
319 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
321 SHFILEINFOW sfi;
322 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
323 IImageList *list;
325 list = (IImageList *)SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
326 if (list) IImageList_Release(list);
327 return sfi.iIcon;
330 /* Insert a shellitem into the given place in the tree and return the
331 resulting treeitem. */
332 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
333 HTREEITEM hParent, HTREEITEM hInsertAfter)
335 TVINSERTSTRUCTW tvins;
336 TVITEMEXW *tvi = &tvins.u.itemex;
337 HTREEITEM hinserted;
338 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
340 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
341 tvi->cChildren = I_CHILDRENCALLBACK;
342 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
343 tvi->pszText = LPSTR_TEXTCALLBACKW;
345 /* Every treeitem contains a pointer to the corresponding ShellItem. */
346 tvi->lParam = (LPARAM)psi;
347 tvins.hParent = hParent;
348 tvins.hInsertAfter = hInsertAfter;
350 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
351 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
352 if(hinserted)
353 IShellItem_AddRef(psi);
355 return hinserted;
358 /* Enumerates the children of the folder represented by hitem
359 * according to the settings for the root, and adds them to the
360 * treeview. Returns the number of children added. */
361 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
363 IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
364 nstc_root *root = root_for_treeitem(This, hitem);
365 LPITEMIDLIST pidl_parent;
366 IShellFolder *psf;
367 IEnumIDList *peidl;
368 UINT added = 0;
369 HRESULT hr;
371 hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
372 if(SUCCEEDED(hr))
374 hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
375 if(SUCCEEDED(hr))
377 hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
378 if(SUCCEEDED(hr))
380 LPITEMIDLIST pidl;
381 IShellItem *psi;
382 ULONG fetched;
384 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
386 hr = SHCreateShellItem(NULL, psf , pidl, &psi);
387 ILFree(pidl);
388 if(SUCCEEDED(hr))
390 if(insert_shellitem(This, psi, hitem, NULL))
392 events_OnItemAdded(This, psi, FALSE);
393 added++;
396 IShellItem_Release(psi);
398 else
399 ERR("SHCreateShellItem failed with 0x%08lx\n", hr);
401 IEnumIDList_Release(peidl);
403 else
404 ERR("EnumObjects failed with 0x%08lx\n", hr);
406 IShellFolder_Release(psf);
408 else
409 ERR("BindToHandler failed with 0x%08lx\n", hr);
411 ILFree(pidl_parent);
413 else
414 ERR("SHGetIDListFromObject failed with 0x%08lx\n", hr);
416 return added;
419 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
421 return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
424 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
426 return shellitem_from_treeitem(This, get_selected_treeitem(This));
429 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
431 HTREEITEM next;
433 /* Collapse this node first, and then first child/next sibling. */
434 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
436 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
437 if(next) collapse_all(This, next);
439 next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
440 if(next) collapse_all(This, next);
443 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
445 TVHITTESTINFO tviht;
446 tviht.pt.x = pt->x;
447 tviht.pt.y = pt->y;
448 tviht.hItem = NULL;
450 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
451 if(hitflag) *hitflag = tviht.flags;
452 return tviht.hItem;
455 /*************************************************************************
456 * NamespaceTree window functions
458 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
460 NSTC2Impl *This = crs->lpCreateParams;
461 HIMAGELIST ShellSmallIconList;
462 DWORD treeview_style, treeview_ex_style;
464 TRACE("%p (%p)\n", This, crs);
465 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
466 This->hwnd_main = hWnd;
468 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
470 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
471 0, 0, crs->cx, crs->cy,
472 hWnd, NULL, explorerframe_hinstance, NULL);
474 if(!This->hwnd_tv)
476 ERR("Failed to create treeview!\n");
477 return HRESULT_FROM_WIN32(GetLastError());
480 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
481 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
483 if(This->style & NSTCS_AUTOHSCROLL)
484 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
485 if(This->style & NSTCS_FADEINOUTEXPANDOS)
486 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
487 if(This->style & NSTCS_PARTIALCHECKBOXES)
488 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
489 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
490 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
491 if(This->style & NSTCS_DIMMEDCHECKBOXES)
492 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
494 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
496 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
498 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
499 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
501 else
503 ERR("Failed to get the System Image List.\n");
506 INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
508 /* Subclass the treeview to get the keyboard events. */
509 This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
510 (ULONG_PTR)tv_wndproc);
511 if(This->tv_oldwndproc)
512 SetPropW(This->hwnd_tv, L"PROP_THIS", This);
514 return TRUE;
517 static LRESULT resize_namespacetree(NSTC2Impl *This)
519 RECT rc;
520 TRACE("%p\n", This);
522 GetClientRect(This->hwnd_main, &rc);
523 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
525 return TRUE;
528 static LRESULT destroy_namespacetree(NSTC2Impl *This)
530 TRACE("%p\n", This);
532 /* Undo the subclassing */
533 if(This->tv_oldwndproc)
535 SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
536 RemovePropW(This->hwnd_tv, L"PROP_THIS");
539 INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
541 /* This reference was added in create_namespacetree */
542 INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
543 return TRUE;
546 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
548 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
549 TRACE("%p\n", This);
551 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
552 return TRUE;
555 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
557 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
558 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
559 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
560 HRESULT hr;
562 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
564 if(item->mask & TVIF_CHILDREN)
566 SFGAOF sfgao;
568 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
569 if(SUCCEEDED(hr))
570 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
571 else
572 item->cChildren = 1;
574 item->mask |= TVIF_DI_SETITEM;
577 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
579 LPITEMIDLIST pidl;
581 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
582 if(FAILED(hr))
584 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
585 if(SUCCEEDED(hr))
587 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
588 item->mask |= TVIF_DI_SETITEM;
589 ILFree(pidl);
591 else
592 ERR("Failed to get IDList (%08lx).\n", hr);
596 if(item->mask & TVIF_TEXT)
598 LPWSTR display_name;
600 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
601 if(SUCCEEDED(hr))
603 lstrcpynW(item->pszText, display_name, MAX_PATH);
604 item->mask |= TVIF_DI_SETITEM;
605 CoTaskMemFree(display_name);
607 else
608 ERR("Failed to get display name (%08lx).\n", hr);
611 return TRUE;
614 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
616 return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
619 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
621 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
622 IShellItem *psi;
623 TRACE("%p\n", This);
625 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
626 events_OnBeforeExpand(This, psi);
628 if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
630 /* The node has no children, try to find some */
631 if(!fill_sublevel(This, nmtv->itemNew.hItem))
633 TVITEMEXW tvi;
634 /* Failed to enumerate any children, remove the expando
635 * (if any). */
636 tvi.hItem = nmtv->itemNew.hItem;
637 tvi.mask = TVIF_CHILDREN;
638 tvi.cChildren = 0;
639 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
641 return TRUE;
644 return FALSE;
647 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
649 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
650 IShellItem *psi;
651 TRACE("%p\n", This);
653 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
654 events_OnAfterExpand(This, psi);
655 return TRUE;
658 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
660 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
661 IShellItemArray *psia;
662 IShellItem *psi;
663 HRESULT hr;
664 TRACE("%p\n", This);
666 /* Note: Only supports one selected item. */
667 psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
668 hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
669 if(SUCCEEDED(hr))
671 events_OnSelectionChanged(This, psia);
672 IShellItemArray_Release(psia);
675 return TRUE;
678 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
680 TVHITTESTINFO tvhit;
681 IShellItem *psi;
683 TRACE("%p (%p)\n", This, nmhdr);
685 GetCursorPos(&tvhit.pt);
686 ScreenToClient(This->hwnd_tv, &tvhit.pt);
687 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
689 if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
690 return TRUE;
692 /* TVHT_ maps onto the corresponding NSTCEHT_ */
693 psi = shellitem_from_treeitem(This, tvhit.hItem);
694 return FAILED(events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON));
697 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
699 TVHITTESTINFO tvhit;
700 IShellItem *psi;
701 HRESULT hr;
702 TRACE("%p (%Ix, %Ix)\n", This, wParam, lParam);
704 tvhit.pt.x = (int)(short)LOWORD(lParam);
705 tvhit.pt.y = (int)(short)HIWORD(lParam);
707 SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
709 /* Seems to generate only ONITEM and ONITEMICON */
710 if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
711 return FALSE;
713 psi = shellitem_from_treeitem(This, tvhit.hItem);
714 hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
716 if(SUCCEEDED(hr))
717 return FALSE;
718 else
719 return TRUE;
722 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
724 IShellItem *psi;
725 HTREEITEM hitem;
726 TRACE("%p : %d, %Ix, %Ix\n", This, uMsg, wParam, lParam);
728 /* Handled by the client? */
729 if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
730 return TRUE;
732 if(uMsg == WM_KEYDOWN)
734 switch(wParam)
736 case VK_DELETE:
737 psi = get_selected_shellitem(This);
738 FIXME("Deletion of file requested (shellitem: %p).\n", psi);
739 return TRUE;
741 case VK_F2:
742 hitem = get_selected_treeitem(This);
743 SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
744 return TRUE;
748 /* Let the TreeView handle the key */
749 return FALSE;
752 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
754 NSTC2Impl *This = (NSTC2Impl*)GetPropW(hWnd, L"PROP_THIS");
756 switch(uMessage) {
757 case WM_KEYDOWN:
758 case WM_KEYUP:
759 case WM_CHAR:
760 case WM_SYSKEYDOWN:
761 case WM_SYSKEYUP:
762 case WM_SYSCHAR:
763 if(on_kbd_event(This, uMessage, wParam, lParam))
764 return TRUE;
765 break;
767 case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam);
770 /* Pass the message on to the treeview */
771 return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
774 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
775 WPARAM wParam, LPARAM lParam)
777 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
778 NMHDR *nmhdr;
780 switch(uMessage)
782 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
783 case WM_SIZE: return resize_namespacetree(This);
784 case WM_DESTROY: return destroy_namespacetree(This);
785 case WM_NOTIFY:
786 nmhdr = (NMHDR*)lParam;
787 switch(nmhdr->code)
789 case NM_CLICK: return on_nm_click(This, nmhdr);
790 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
791 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
792 case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam);
793 case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam);
794 case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam);
795 default: break;
797 break;
798 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
800 return 0;
803 /**************************************************************************
804 * INameSpaceTreeControl2 Implementation
806 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
807 REFIID riid,
808 void **ppvObject)
810 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
811 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
813 *ppvObject = NULL;
814 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
815 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
816 IsEqualIID(riid, &IID_IUnknown))
818 *ppvObject = &This->INameSpaceTreeControl2_iface;
820 else if(IsEqualIID(riid, &IID_IOleWindow))
822 *ppvObject = &This->IOleWindow_iface;
825 if(*ppvObject)
827 IUnknown_AddRef((IUnknown*)*ppvObject);
828 return S_OK;
831 return E_NOINTERFACE;
834 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
836 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
837 LONG ref = InterlockedIncrement(&This->ref);
839 TRACE("%p - ref %ld\n", This, ref);
841 return ref;
844 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
846 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
847 LONG ref = InterlockedDecrement(&This->ref);
849 TRACE("%p - ref: %ld\n", This, ref);
851 if(!ref)
853 TRACE("Freeing.\n");
854 free(This);
855 EFRAME_UnlockModule();
858 return ref;
861 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
862 HWND hwndParent,
863 RECT *prc,
864 NSTCSTYLE nstcsFlags)
866 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
867 WNDCLASSW wc;
868 DWORD window_style, window_ex_style;
869 INITCOMMONCONTROLSEX icex;
870 RECT rc;
871 static const WCHAR NSTC2_CLASS_NAME[] = L"NamespaceTreeControl";
873 TRACE("%p (%p, %p, %lx)\n", This, hwndParent, prc, nstcsFlags);
875 if(nstcsFlags & unsupported_styles)
876 FIXME("0x%08lx contains the unsupported style(s) 0x%08lx\n",
877 nstcsFlags, nstcsFlags & unsupported_styles);
879 This->style = nstcsFlags;
881 icex.dwSize = sizeof( icex );
882 icex.dwICC = ICC_TREEVIEW_CLASSES;
883 InitCommonControlsEx( &icex );
885 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
887 wc.style = CS_HREDRAW | CS_VREDRAW;
888 wc.lpfnWndProc = NSTC2_WndProc;
889 wc.cbClsExtra = 0;
890 wc.cbWndExtra = 0;
891 wc.hInstance = explorerframe_hinstance;
892 wc.hIcon = 0;
893 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
894 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
895 wc.lpszMenuName = NULL;
896 wc.lpszClassName = NSTC2_CLASS_NAME;
898 if (!RegisterClassW(&wc)) return E_FAIL;
901 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
902 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
903 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
904 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
906 if(prc)
907 rc = *prc;
908 else
909 SetRectEmpty(&rc);
911 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
912 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
913 hwndParent, 0, explorerframe_hinstance, This);
915 if(!This->hwnd_main)
917 ERR("Failed to create the window.\n");
918 return HRESULT_FROM_WIN32(GetLastError());
921 return S_OK;
924 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, IUnknown *handler, DWORD *cookie)
926 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
928 TRACE("%p (%p, %p)\n", This, handler, cookie);
930 *cookie = 0;
932 /* Only one client supported */
933 if (This->events || This->customdraw || This->dragdrop)
934 return E_FAIL;
936 /* FIXME: request INameSpaceTreeAccessible too */
937 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlEvents, (void**)&This->events);
938 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlCustomDraw, (void**)&This->customdraw);
939 IUnknown_QueryInterface(handler, &IID_INameSpaceTreeControlDropHandler, (void**)&This->dragdrop);
941 if (This->events || This->customdraw || This->dragdrop)
942 *cookie = 1;
944 return *cookie ? S_OK : E_FAIL;
947 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, DWORD cookie)
949 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
951 TRACE("%p (%lx)\n", This, cookie);
953 /* The cookie is ignored. */
955 if (This->events)
957 INameSpaceTreeControlEvents_Release(This->events);
958 This->events = NULL;
961 if (This->customdraw)
963 INameSpaceTreeControlCustomDraw_Release(This->customdraw);
964 This->customdraw = NULL;
967 if (This->dragdrop)
969 INameSpaceTreeControlDropHandler_Release(This->dragdrop);
970 This->dragdrop = NULL;
973 return S_OK;
976 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
977 int iIndex,
978 IShellItem *psiRoot,
979 SHCONTF grfEnumFlags,
980 NSTCROOTSTYLE grfRootStyle,
981 IShellItemFilter *pif)
983 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
984 nstc_root *new_root;
985 struct list *add_after_entry;
986 HTREEITEM add_after_hitem;
987 int i;
989 TRACE("%p, %d, %p, %lx, %lx, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
991 new_root = malloc(sizeof(*new_root));
992 if(!new_root)
993 return E_OUTOFMEMORY;
995 new_root->psi = psiRoot;
996 new_root->enum_flags = grfEnumFlags;
997 new_root->root_style = grfRootStyle;
998 new_root->pif = pif;
1000 /* We want to keep the roots in the internal list and in the
1001 * treeview in the same order. */
1002 add_after_entry = &This->roots;
1003 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
1004 add_after_entry = list_next(&This->roots, add_after_entry);
1006 if(add_after_entry == &This->roots)
1007 add_after_hitem = TVI_FIRST;
1008 else
1009 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
1011 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1012 if(!new_root->htreeitem)
1014 WARN("Failed to add the root.\n");
1015 free(new_root);
1016 return E_FAIL;
1019 list_add_after(add_after_entry, &new_root->entry);
1020 events_OnItemAdded(This, psiRoot, TRUE);
1022 if(grfRootStyle & NSTCRS_HIDDEN)
1024 TVITEMEXW tvi;
1025 tvi.mask = TVIF_STATEEX;
1026 tvi.uStateEx = TVIS_EX_FLAT;
1027 tvi.hItem = new_root->htreeitem;
1029 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1032 if(grfRootStyle & NSTCRS_EXPANDED)
1033 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1034 (LPARAM)new_root->htreeitem);
1036 return S_OK;
1039 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1040 IShellItem *psiRoot,
1041 SHCONTF grfEnumFlags,
1042 NSTCROOTSTYLE grfRootStyle,
1043 IShellItemFilter *pif)
1045 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1046 UINT root_count;
1047 TRACE("%p, %p, %lx, %lx, %p\n",
1048 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1050 root_count = list_count(&This->roots);
1052 return INameSpaceTreeControl2_InsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1055 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1056 IShellItem *psiRoot)
1058 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1059 nstc_root *cursor, *root = NULL;
1060 TRACE("%p (%p)\n", This, psiRoot);
1062 if(!psiRoot)
1063 return E_NOINTERFACE;
1065 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1067 HRESULT hr;
1068 int order;
1069 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1070 if(hr == S_OK)
1072 root = cursor;
1073 break;
1077 TRACE("root %p\n", root);
1078 if(root)
1080 events_OnItemDeleted(This, root->psi, TRUE);
1081 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1082 list_remove(&root->entry);
1083 free(root);
1084 return S_OK;
1086 else
1088 WARN("No matching root found.\n");
1089 return E_FAIL;
1093 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1095 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1096 nstc_root *cur1, *cur2;
1098 TRACE("%p\n", This);
1100 if (list_empty(&This->roots))
1101 return E_INVALIDARG;
1103 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1104 INameSpaceTreeControl2_RemoveRoot(iface, cur1->psi);
1106 return S_OK;
1109 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1110 IShellItemArray **ppsiaRootItems)
1112 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1113 IShellFolder *psf;
1114 LPITEMIDLIST *array;
1115 nstc_root *root;
1116 UINT count, i;
1117 HRESULT hr;
1118 TRACE("%p (%p)\n", This, ppsiaRootItems);
1120 count = list_count(&This->roots);
1122 if(!count)
1123 return E_INVALIDARG;
1125 array = malloc(sizeof(LPITEMIDLIST)*count);
1127 i = 0;
1128 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1129 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1131 SHGetDesktopFolder(&psf);
1132 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1133 ppsiaRootItems);
1134 IShellFolder_Release(psf);
1136 for(i = 0; i < count; i++)
1137 ILFree(array[i]);
1139 free(array);
1141 return hr;
1144 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1145 IShellItem *psi,
1146 NSTCITEMSTATE nstcisMask,
1147 NSTCITEMSTATE nstcisFlags)
1149 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1150 TVITEMEXW tvi;
1151 HTREEITEM hitem;
1153 TRACE("%p (%p, %lx, %lx)\n", This, psi, nstcisMask, nstcisFlags);
1155 hitem = treeitem_from_shellitem(This, psi);
1156 if(!hitem) return E_INVALIDARG;
1158 /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1159 in two TVM_SETITEMW's */
1160 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1162 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1163 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1165 if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1167 SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1170 /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1171 if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1173 WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1174 SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1177 if(nstcisMask & NSTCIS_DISABLED)
1178 tvi.mask = TVIF_STATE | TVIF_STATEEX;
1179 else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1180 ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1181 (nstcisFlags & NSTCIS_DISABLED) )
1182 tvi.mask = TVIF_STATE;
1183 else
1184 tvi.mask = 0;
1186 if(tvi.mask)
1188 tvi.stateMask = tvi.state = 0;
1189 tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1190 tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1191 tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1193 if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1195 tvi.stateMask = 0;
1198 tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1199 tvi.hItem = hitem;
1201 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1204 return S_OK;
1207 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1208 IShellItem *psi,
1209 NSTCITEMSTATE nstcisMask,
1210 NSTCITEMSTATE *pnstcisFlags)
1212 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1213 HTREEITEM hitem;
1214 TVITEMEXW tvi;
1215 TRACE("%p (%p, %lx, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1217 hitem = treeitem_from_shellitem(This, psi);
1218 if(!hitem)
1219 return E_INVALIDARG;
1221 *pnstcisFlags = 0;
1223 tvi.hItem = hitem;
1224 tvi.mask = TVIF_STATE;
1225 tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1227 if(nstcisMask & NSTCIS_DISABLED)
1228 tvi.mask |= TVIF_STATEEX;
1230 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1231 *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1232 *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1233 *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1234 *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1236 *pnstcisFlags &= nstcisMask;
1238 return S_OK;
1241 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1242 IShellItemArray **psiaItems)
1244 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1245 IShellItem *psiselected;
1247 TRACE("%p (%p)\n", This, psiaItems);
1249 psiselected = get_selected_shellitem(This);
1250 if(!psiselected)
1252 *psiaItems = NULL;
1253 return E_FAIL;
1256 return SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1257 (void**)psiaItems);
1260 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1261 IShellItem *psi,
1262 int *piStateNumber)
1264 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1265 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1266 return E_NOTIMPL;
1269 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1270 IShellItem *psi,
1271 int iStateNumber)
1273 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1274 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1275 return E_NOTIMPL;
1278 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1279 IShellItem *psi)
1281 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1282 HTREEITEM hitem;
1284 TRACE("%p (%p)\n", This, psi);
1286 hitem = treeitem_from_shellitem(This, psi);
1287 if(hitem)
1289 SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1290 return S_OK;
1293 return E_INVALIDARG;
1296 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1297 LPCWSTR pszTheme)
1299 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1300 FIXME("stub, %p (%p)\n", This, pszTheme);
1301 return E_NOTIMPL;
1304 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1305 IShellItem *psi,
1306 NSTCGNI nstcgi,
1307 IShellItem **ppsiNext)
1309 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1310 HTREEITEM hitem, hnext;
1311 UINT tvgn;
1312 TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1314 if(!ppsiNext) return E_POINTER;
1315 if(!psi) return E_FAIL;
1317 *ppsiNext = NULL;
1319 hitem = treeitem_from_shellitem(This, psi);
1320 if(!hitem)
1321 return E_INVALIDARG;
1323 switch(nstcgi)
1325 case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break;
1326 case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break;
1327 case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break;
1328 case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break;
1329 case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break;
1330 case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break;
1331 case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1332 case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break;
1333 default:
1334 FIXME("Unknown nstcgi value %d\n", nstcgi);
1335 return E_FAIL;
1338 hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1339 if(hnext)
1341 *ppsiNext = shellitem_from_treeitem(This, hnext);
1342 IShellItem_AddRef(*ppsiNext);
1343 return S_OK;
1346 return E_FAIL;
1349 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1350 POINT *ppt,
1351 IShellItem **ppsiOut)
1353 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1354 HTREEITEM hitem;
1355 TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1357 if(!ppt || !ppsiOut)
1358 return E_POINTER;
1360 *ppsiOut = NULL;
1362 hitem = treeitem_from_point(This, ppt, NULL);
1363 if(hitem)
1364 *ppsiOut = shellitem_from_treeitem(This, hitem);
1366 if(*ppsiOut)
1368 IShellItem_AddRef(*ppsiOut);
1369 return S_OK;
1372 return S_FALSE;
1375 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1376 IShellItem *psi,
1377 RECT *prect)
1379 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1380 HTREEITEM hitem;
1381 TRACE("%p (%p, %p)\n", This, psi, prect);
1383 if(!psi || !prect)
1384 return E_POINTER;
1386 hitem = treeitem_from_shellitem(This, psi);
1387 if(hitem)
1389 *(HTREEITEM*)prect = hitem;
1390 if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1392 MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1393 return S_OK;
1397 return E_INVALIDARG;
1400 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1402 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1403 nstc_root *root;
1404 TRACE("%p\n", This);
1406 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1407 collapse_all(This, root->htreeitem);
1409 return S_OK;
1412 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1413 NSTCSTYLE nstcsMask,
1414 NSTCSTYLE nstcsStyle)
1416 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1417 static const DWORD tv_style_flags =
1418 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1419 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1420 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1421 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1422 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1423 static const DWORD nstc_flags =
1424 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1425 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1426 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1427 TRACE("%p (%lx, %lx)\n", This, nstcsMask, nstcsStyle);
1429 /* Fail if there is an attempt to set an unknown style. */
1430 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1431 return E_FAIL;
1433 if(nstcsMask & tv_style_flags)
1435 DWORD new_style;
1436 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1437 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1440 /* Flags affecting the host window */
1441 if(nstcsMask & NSTCS_BORDER)
1443 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1444 new_style &= ~WS_BORDER;
1445 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1446 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1448 if(nstcsMask & NSTCS_TABSTOP)
1450 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1451 new_style &= ~WS_EX_CONTROLPARENT;
1452 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1453 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1456 if((nstcsStyle & nstcsMask) & unsupported_styles)
1457 FIXME("mask & style (0x%08lx) contains unsupported style(s): 0x%08lx\n",
1458 (nstcsStyle & nstcsMask),
1459 (nstcsStyle & nstcsMask) & unsupported_styles);
1461 This->style &= ~nstcsMask;
1462 This->style |= (nstcsStyle & nstcsMask);
1464 return S_OK;
1467 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1468 NSTCSTYLE nstcsMask,
1469 NSTCSTYLE *pnstcsStyle)
1471 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1472 TRACE("%p (%lx, %p)\n", This, nstcsMask, pnstcsStyle);
1474 *pnstcsStyle = (This->style & nstcsMask);
1476 return S_OK;
1479 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1480 NSTCSTYLE2 nstcsMask,
1481 NSTCSTYLE2 nstcsStyle)
1483 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1484 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1486 if((nstcsStyle & nstcsMask) & unsupported_styles2)
1487 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08lx\n",
1488 (nstcsStyle & nstcsMask),
1489 (nstcsStyle & nstcsMask) & unsupported_styles2);
1491 This->style2 &= ~nstcsMask;
1492 This->style2 |= (nstcsStyle & nstcsMask);
1494 return S_OK;
1497 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1498 NSTCSTYLE2 nstcsMask,
1499 NSTCSTYLE2 *pnstcsStyle)
1501 NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1502 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1504 *pnstcsStyle = (This->style2 & nstcsMask);
1506 return S_OK;
1509 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1510 NSTC2_fnQueryInterface,
1511 NSTC2_fnAddRef,
1512 NSTC2_fnRelease,
1513 NSTC2_fnInitialize,
1514 NSTC2_fnTreeAdvise,
1515 NSTC2_fnTreeUnadvise,
1516 NSTC2_fnAppendRoot,
1517 NSTC2_fnInsertRoot,
1518 NSTC2_fnRemoveRoot,
1519 NSTC2_fnRemoveAllRoots,
1520 NSTC2_fnGetRootItems,
1521 NSTC2_fnSetItemState,
1522 NSTC2_fnGetItemState,
1523 NSTC2_fnGetSelectedItems,
1524 NSTC2_fnGetItemCustomState,
1525 NSTC2_fnSetItemCustomState,
1526 NSTC2_fnEnsureItemVisible,
1527 NSTC2_fnSetTheme,
1528 NSTC2_fnGetNextItem,
1529 NSTC2_fnHitTest,
1530 NSTC2_fnGetItemRect,
1531 NSTC2_fnCollapseAll,
1532 NSTC2_fnSetControlStyle,
1533 NSTC2_fnGetControlStyle,
1534 NSTC2_fnSetControlStyle2,
1535 NSTC2_fnGetControlStyle2
1538 /**************************************************************************
1539 * IOleWindow Implementation
1542 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1544 NSTC2Impl *This = impl_from_IOleWindow(iface);
1545 return INameSpaceTreeControl2_QueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1548 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1550 NSTC2Impl *This = impl_from_IOleWindow(iface);
1551 return INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
1554 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1556 NSTC2Impl *This = impl_from_IOleWindow(iface);
1557 return INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
1560 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1562 NSTC2Impl *This = impl_from_IOleWindow(iface);
1563 TRACE("%p (%p)\n", This, phwnd);
1565 *phwnd = This->hwnd_main;
1566 return S_OK;
1569 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1571 NSTC2Impl *This = impl_from_IOleWindow(iface);
1572 TRACE("%p (%d)\n", This, fEnterMode);
1574 /* Not implemented */
1575 return E_NOTIMPL;
1578 static const IOleWindowVtbl vt_IOleWindow = {
1579 IOW_fnQueryInterface,
1580 IOW_fnAddRef,
1581 IOW_fnRelease,
1582 IOW_fnGetWindow,
1583 IOW_fnContextSensitiveHelp
1586 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1588 NSTC2Impl *nstc;
1589 HRESULT ret;
1591 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1593 if(!ppv)
1594 return E_POINTER;
1595 if(pUnkOuter)
1596 return CLASS_E_NOAGGREGATION;
1598 EFRAME_LockModule();
1600 nstc = calloc(1, sizeof(*nstc));
1601 if (!nstc)
1602 return E_OUTOFMEMORY;
1604 nstc->ref = 1;
1605 nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1606 nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1608 list_init(&nstc->roots);
1610 ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1611 INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1613 TRACE("--(%p)\n", ppv);
1614 return ret;