explorerframe: Implement GetRootItems.
[wine.git] / dlls / explorerframe / nstc.c
blob5f6de53bc1d293f21761d719a747a77e902ae718
1 /*
2 * NamespaceTreeControl implementation.
4 * Copyright 2010 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "shellapi.h"
33 #include "wine/list.h"
34 #include "wine/debug.h"
36 #include "explorerframe_main.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
40 typedef struct nstc_root {
41 IShellItem *psi;
42 HTREEITEM htreeitem;
43 SHCONTF enum_flags;
44 NSTCROOTSTYLE root_style;
45 IShellItemFilter *pif;
46 struct list entry;
47 } nstc_root;
49 typedef struct {
50 const INameSpaceTreeControl2Vtbl *lpVtbl;
51 const IOleWindowVtbl *lpowVtbl;
52 LONG ref;
54 HWND hwnd_main;
55 HWND hwnd_tv;
57 NSTCSTYLE style;
58 NSTCSTYLE2 style2;
59 struct list roots;
61 INameSpaceTreeControlEvents *pnstce;
62 } NSTC2Impl;
64 static const DWORD unsupported_styles =
65 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
66 NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
67 NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
68 static const DWORD unsupported_styles2 =
69 NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
70 NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
72 /*************************************************************************
73 * NamespaceTree event wrappers
75 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
76 int *piDefaultIcon, int *piOpenIcon)
78 HRESULT ret;
79 LONG refcount;
80 if(!This->pnstce) return E_NOTIMPL;
82 refcount = IShellItem_AddRef(psi);
83 ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->pnstce, psi, piDefaultIcon, piOpenIcon);
84 if(IShellItem_Release(psi) < refcount - 1)
85 ERR("ShellItem was released by client - please file a bug.\n");
86 return ret;
89 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
91 HRESULT ret;
92 LONG refcount;
93 if(!This->pnstce) return S_OK;
95 refcount = IShellItem_AddRef(psi);
96 ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
97 if(IShellItem_Release(psi) < refcount - 1)
98 ERR("ShellItem was released by client - please file a bug.\n");
99 return ret;
102 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
104 HRESULT ret;
105 LONG refcount;
106 if(!This->pnstce) return S_OK;
108 refcount = IShellItem_AddRef(psi);
109 ret = INameSpaceTreeControlEvents_OnItemDeleted(This->pnstce, psi, fIsRoot);
110 if(IShellItem_Release(psi) < refcount - 1)
111 ERR("ShellItem was released by client - please file a bug.\n");
112 return ret;
115 /*************************************************************************
116 * NamespaceTree helper functions
118 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
119 NSTCSTYLE nstcs_mask, DWORD *new_style)
121 DWORD old_style, tv_mask = 0;
122 TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
124 if(This->hwnd_tv)
125 old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
126 else
127 old_style = /* The default */
128 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
129 WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
130 TVS_EDITLABELS | TVS_TRACKSELECT;
132 if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS;
133 if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES;
134 if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT;
135 if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL;
136 if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT;
137 if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
138 if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP;
139 if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT;
140 if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP;
141 if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS;
142 if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES;
144 *new_style = 0;
146 if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS;
147 if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES;
148 if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT;
149 if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
150 if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT;
151 if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
152 if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP;
153 if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT;
154 if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP;
155 if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS;
156 if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES;
158 *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
160 TRACE("old: %08x, new: %08x\n", old_style, *new_style);
162 return old_style^*new_style;
165 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
167 TVITEMEXW tvi;
169 tvi.mask = TVIF_PARAM;
170 tvi.lParam = (LPARAM)NULL;
171 tvi.hItem = hitem;
173 SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
175 TRACE("ShellItem: %p\n", (void*)tvi.lParam);
176 return (IShellItem*)tvi.lParam;
179 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
181 SHFILEINFOW sfi;
182 UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
183 SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
184 return sfi.iIcon;
187 /* Insert a shellitem into the given place in the tree and return the
188 resulting treeitem. */
189 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
190 HTREEITEM hParent, HTREEITEM hInsertAfter)
192 TVINSERTSTRUCTW tvins;
193 TVITEMEXW *tvi = &tvins.u.itemex;
194 HTREEITEM hinserted;
195 TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
197 tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
198 tvi->cChildren = I_CHILDRENCALLBACK;
199 tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
200 tvi->pszText = LPSTR_TEXTCALLBACKW;
202 /* Every treeitem contains a pointer to the corresponding ShellItem. */
203 tvi->lParam = (LPARAM)psi;
204 tvins.hParent = hParent;
205 tvins.hInsertAfter = hInsertAfter;
207 hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
208 (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
209 if(hinserted)
210 IShellItem_AddRef(psi);
212 return hinserted;
215 /*************************************************************************
216 * NamespaceTree window functions
218 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
220 NSTC2Impl *This = crs->lpCreateParams;
221 HIMAGELIST ShellSmallIconList;
222 DWORD treeview_style, treeview_ex_style;
224 TRACE("%p (%p)\n", This, crs);
225 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
226 This->hwnd_main = hWnd;
228 treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
230 This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
231 0, 0, crs->cx, crs->cy,
232 hWnd, NULL, explorerframe_hinstance, NULL);
234 if(!This->hwnd_tv)
236 ERR("Failed to create treeview!\n");
237 return HRESULT_FROM_WIN32(GetLastError());
240 treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
241 TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
243 if(This->style & NSTCS_AUTOHSCROLL)
244 treeview_ex_style |= TVS_EX_AUTOHSCROLL;
245 if(This->style & NSTCS_FADEINOUTEXPANDOS)
246 treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
247 if(This->style & NSTCS_PARTIALCHECKBOXES)
248 treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
249 if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
250 treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
251 if(This->style & NSTCS_DIMMEDCHECKBOXES)
252 treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
254 SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
256 if(Shell_GetImageLists(NULL, &ShellSmallIconList))
258 SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
259 (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
261 else
263 ERR("Failed to get the System Image List.\n");
266 INameSpaceTreeControl_AddRef((INameSpaceTreeControl*)This);
268 return TRUE;
271 static LRESULT resize_namespacetree(NSTC2Impl *This)
273 RECT rc;
274 TRACE("%p\n", This);
276 GetClientRect(This->hwnd_main, &rc);
277 MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
279 return TRUE;
282 static LRESULT destroy_namespacetree(NSTC2Impl *This)
284 TRACE("%p\n", This);
286 INameSpaceTreeControl_RemoveAllRoots((INameSpaceTreeControl*)This);
288 /* This reference was added in create_namespacetree */
289 INameSpaceTreeControl_Release((INameSpaceTreeControl*)This);
290 return TRUE;
293 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
295 NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
296 TRACE("%p\n", This);
298 IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
299 return TRUE;
302 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
304 NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
305 TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
306 IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
307 HRESULT hr;
309 TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
311 if(item->mask & TVIF_CHILDREN)
313 SFGAOF sfgao;
315 hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
316 if(SUCCEEDED(hr))
317 item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
318 else
319 item->cChildren = 1;
321 item->mask |= TVIF_DI_SETITEM;
324 if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
326 LPITEMIDLIST pidl;
328 hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
329 if(FAILED(hr))
331 hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
332 if(SUCCEEDED(hr))
334 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
335 item->mask |= TVIF_DI_SETITEM;
336 ILFree(pidl);
338 else
339 ERR("Failed to get IDList (%08x).\n", hr);
343 if(item->mask & TVIF_TEXT)
345 LPWSTR display_name;
347 hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
348 if(SUCCEEDED(hr))
350 lstrcpynW(item->pszText, display_name, MAX_PATH);
351 item->mask |= TVIF_DI_SETITEM;
352 CoTaskMemFree(display_name);
354 else
355 ERR("Failed to get display name (%08x).\n", hr);
358 return TRUE;
361 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
362 WPARAM wParam, LPARAM lParam)
364 NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
365 NMHDR *nmhdr;
367 switch(uMessage)
369 case WM_NCCREATE: return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
370 case WM_SIZE: return resize_namespacetree(This);
371 case WM_DESTROY: return destroy_namespacetree(This);
372 case WM_NOTIFY:
373 nmhdr = (NMHDR*)lParam;
374 switch(nmhdr->code)
376 case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam);
377 case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam);
378 default: break;
380 break;
381 default: return DefWindowProcW(hWnd, uMessage, wParam, lParam);
383 return 0;
386 /**************************************************************************
387 * INameSpaceTreeControl2 Implementation
389 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
390 REFIID riid,
391 void **ppvObject)
393 NSTC2Impl *This = (NSTC2Impl*)iface;
394 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
396 *ppvObject = NULL;
397 if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
398 IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
399 IsEqualIID(riid, &IID_IUnknown))
401 *ppvObject = This;
403 else if(IsEqualIID(riid, &IID_IOleWindow))
405 *ppvObject = &This->lpowVtbl;
408 if(*ppvObject)
410 IUnknown_AddRef((IUnknown*)*ppvObject);
411 return S_OK;
414 return E_NOINTERFACE;
417 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
419 NSTC2Impl *This = (NSTC2Impl*)iface;
420 LONG ref = InterlockedIncrement(&This->ref);
422 TRACE("%p - ref %d\n", This, ref);
424 return ref;
427 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
429 NSTC2Impl *This = (NSTC2Impl*)iface;
430 LONG ref = InterlockedDecrement(&This->ref);
432 TRACE("%p - ref: %d\n", This, ref);
434 if(!ref)
436 TRACE("Freeing.\n");
437 HeapFree(GetProcessHeap(), 0, This);
438 EFRAME_UnlockModule();
439 return 0;
442 return ref;
445 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
446 HWND hwndParent,
447 RECT *prc,
448 NSTCSTYLE nstcsFlags)
450 NSTC2Impl *This = (NSTC2Impl*)iface;
451 WNDCLASSW wc;
452 DWORD window_style, window_ex_style;
453 RECT rc;
454 static const WCHAR NSTC2_CLASS_NAME[] =
455 {'N','a','m','e','s','p','a','c','e','T','r','e','e',
456 'C','o','n','t','r','o','l',0};
458 TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
460 if(nstcsFlags & unsupported_styles)
461 FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
462 nstcsFlags, nstcsFlags & unsupported_styles);
464 This->style = nstcsFlags;
466 if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
468 wc.style = CS_HREDRAW | CS_VREDRAW;
469 wc.lpfnWndProc = NSTC2_WndProc;
470 wc.cbClsExtra = 0;
471 wc.cbWndExtra = 0;
472 wc.hInstance = explorerframe_hinstance;
473 wc.hIcon = 0;
474 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
475 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
476 wc.lpszMenuName = NULL;
477 wc.lpszClassName = NSTC2_CLASS_NAME;
479 if (!RegisterClassW(&wc)) return E_FAIL;
482 /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
483 window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
484 (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
485 window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
487 if(prc)
488 CopyRect(&rc, prc);
489 else
490 rc.left = rc.right = rc.top = rc.bottom = 0;
492 This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style,
493 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
494 hwndParent, 0, explorerframe_hinstance, This);
496 if(!This->hwnd_main)
498 ERR("Failed to create the window.\n");
499 return HRESULT_FROM_WIN32(GetLastError());
502 return S_OK;
505 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface,
506 IUnknown *punk,
507 DWORD *pdwCookie)
509 NSTC2Impl *This = (NSTC2Impl*)iface;
510 HRESULT hr;
511 TRACE("%p (%p, %p)\n", This, punk, pdwCookie);
513 *pdwCookie = 0;
515 /* Only one client supported */
516 if(This->pnstce)
517 return E_FAIL;
519 hr = IUnknown_QueryInterface(punk, &IID_INameSpaceTreeControlEvents,(void**)&This->pnstce);
520 if(SUCCEEDED(hr))
522 *pdwCookie = 1;
523 return hr;
526 return E_FAIL;
529 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface,
530 DWORD dwCookie)
532 NSTC2Impl *This = (NSTC2Impl*)iface;
533 TRACE("%p (%x)\n", This, dwCookie);
535 /* The cookie is ignored. */
537 if(This->pnstce)
539 INameSpaceTreeControlEvents_Release(This->pnstce);
540 This->pnstce = NULL;
543 return S_OK;
546 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
547 int iIndex,
548 IShellItem *psiRoot,
549 SHCONTF grfEnumFlags,
550 NSTCROOTSTYLE grfRootStyle,
551 IShellItemFilter *pif)
553 NSTC2Impl *This = (NSTC2Impl*)iface;
554 nstc_root *new_root;
555 struct list *add_after_entry;
556 HTREEITEM add_after_hitem;
557 UINT i;
559 TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
561 new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
562 if(!new_root)
563 return E_OUTOFMEMORY;
565 new_root->psi = psiRoot;
566 new_root->enum_flags = grfEnumFlags;
567 new_root->root_style = grfRootStyle;
568 new_root->pif = pif;
570 /* We want to keep the roots in the internal list and in the
571 * treeview in the same order. */
572 add_after_entry = &This->roots;
573 for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
574 add_after_entry = list_next(&This->roots, add_after_entry);
576 if(add_after_entry == &This->roots)
577 add_after_hitem = TVI_FIRST;
578 else
579 add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
581 new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
582 if(!new_root->htreeitem)
584 WARN("Failed to add the root.\n");
585 HeapFree(GetProcessHeap(), 0, new_root);
586 return E_FAIL;
589 list_add_after(add_after_entry, &new_root->entry);
590 events_OnItemAdded(This, psiRoot, TRUE);
592 if(grfRootStyle & NSTCRS_HIDDEN)
594 TVITEMEXW tvi;
595 tvi.mask = TVIF_STATEEX;
596 tvi.uStateEx = TVIS_EX_FLAT;
597 tvi.hItem = new_root->htreeitem;
599 SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
602 if(grfRootStyle & NSTCRS_EXPANDED)
603 SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
604 (LPARAM)new_root->htreeitem);
606 return S_OK;
609 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
610 IShellItem *psiRoot,
611 SHCONTF grfEnumFlags,
612 NSTCROOTSTYLE grfRootStyle,
613 IShellItemFilter *pif)
615 NSTC2Impl *This = (NSTC2Impl*)iface;
616 UINT root_count;
617 TRACE("%p, %p, %x, %x, %p\n",
618 This, psiRoot, grfEnumFlags, grfRootStyle, pif);
620 root_count = list_count(&This->roots);
622 return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
625 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
626 IShellItem *psiRoot)
628 NSTC2Impl *This = (NSTC2Impl*)iface;
629 nstc_root *cursor, *root = NULL;
630 TRACE("%p (%p)\n", This, psiRoot);
632 if(!psiRoot)
633 return E_NOINTERFACE;
635 LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
637 HRESULT hr;
638 int order;
639 hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
640 if(hr == S_OK)
642 root = cursor;
643 break;
647 TRACE("root %p\n", root);
648 if(root)
650 SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
651 events_OnItemDeleted(This, root->psi, TRUE);
652 list_remove(&root->entry);
653 HeapFree(GetProcessHeap(), 0, root);
654 return S_OK;
656 else
658 WARN("No matching root found.\n");
659 return E_FAIL;
663 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
665 NSTC2Impl *This = (NSTC2Impl*)iface;
666 nstc_root *cur1, *cur2;
667 UINT removed = 0;
668 TRACE("%p\n", This);
670 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
672 NSTC2_fnRemoveRoot(iface, cur1->psi);
673 removed++;
676 if(removed)
677 return S_OK;
678 else
679 return E_INVALIDARG;
682 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
683 IShellItemArray **ppsiaRootItems)
685 NSTC2Impl *This = (NSTC2Impl*)iface;
686 IShellFolder *psf;
687 LPITEMIDLIST *array;
688 nstc_root *root;
689 UINT count, i;
690 HRESULT hr;
691 TRACE("%p (%p)\n", This, ppsiaRootItems);
693 count = list_count(&This->roots);
695 if(!count)
696 return E_INVALIDARG;
698 array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST*)*count);
700 i = 0;
701 LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
702 SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
704 SHGetDesktopFolder(&psf);
705 hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
706 ppsiaRootItems);
707 IShellFolder_Release(psf);
709 for(i = 0; i < count; i++)
710 ILFree(array[i]);
712 HeapFree(GetProcessHeap(), 0, array);
714 return hr;
717 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
718 IShellItem *psi,
719 NSTCITEMSTATE nstcisMask,
720 NSTCITEMSTATE nstcisFlags)
722 NSTC2Impl *This = (NSTC2Impl*)iface;
723 FIXME("stub, %p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
724 return E_NOTIMPL;
727 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
728 IShellItem *psi,
729 NSTCITEMSTATE nstcisMask,
730 NSTCITEMSTATE *pnstcisFlags)
732 NSTC2Impl *This = (NSTC2Impl*)iface;
733 FIXME("stub, %p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
734 return E_NOTIMPL;
737 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
738 IShellItemArray **psiaItems)
740 NSTC2Impl *This = (NSTC2Impl*)iface;
741 FIXME("stub, %p (%p)\n", This, psiaItems);
742 return E_NOTIMPL;
745 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
746 IShellItem *psi,
747 int *piStateNumber)
749 NSTC2Impl *This = (NSTC2Impl*)iface;
750 FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
751 return E_NOTIMPL;
754 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
755 IShellItem *psi,
756 int iStateNumber)
758 NSTC2Impl *This = (NSTC2Impl*)iface;
759 FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
760 return E_NOTIMPL;
763 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
764 IShellItem *psi)
766 NSTC2Impl *This = (NSTC2Impl*)iface;
767 FIXME("stub, %p (%p)\n", This, psi);
768 return E_NOTIMPL;
771 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
772 LPCWSTR pszTheme)
774 NSTC2Impl *This = (NSTC2Impl*)iface;
775 FIXME("stub, %p (%p)\n", This, pszTheme);
776 return E_NOTIMPL;
779 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
780 IShellItem *psi,
781 NSTCGNI nstcgi,
782 IShellItem **ppsiNext)
784 NSTC2Impl *This = (NSTC2Impl*)iface;
785 FIXME("stub, %p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
786 return E_NOTIMPL;
789 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
790 POINT *ppt,
791 IShellItem **ppsiOut)
793 NSTC2Impl *This = (NSTC2Impl*)iface;
794 FIXME("stub, %p (%p, %p)\n", This, ppsiOut, ppt);
795 return E_NOTIMPL;
798 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
799 IShellItem *psi,
800 RECT *prect)
802 NSTC2Impl *This = (NSTC2Impl*)iface;
803 FIXME("stub, %p (%p, %p)\n", This, psi, prect);
804 return E_NOTIMPL;
807 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
809 NSTC2Impl *This = (NSTC2Impl*)iface;
810 FIXME("stub, %p\n", This);
811 return E_NOTIMPL;
814 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
815 NSTCSTYLE nstcsMask,
816 NSTCSTYLE nstcsStyle)
818 NSTC2Impl *This = (NSTC2Impl*)iface;
819 static const DWORD tv_style_flags =
820 NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
821 NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
822 NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
823 NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
824 static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
825 static const DWORD nstc_flags =
826 NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
827 NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
828 NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
829 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
831 /* Fail if there is an attempt to set an unknown style. */
832 if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
833 return E_FAIL;
835 if(nstcsMask & tv_style_flags)
837 DWORD new_style;
838 treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
839 SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
842 /* Flags affecting the host window */
843 if(nstcsMask & NSTCS_BORDER)
845 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
846 new_style &= ~WS_BORDER;
847 new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
848 SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
850 if(nstcsMask & NSTCS_TABSTOP)
852 DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
853 new_style &= ~WS_EX_CONTROLPARENT;
854 new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
855 SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
858 if((nstcsStyle & nstcsMask) & unsupported_styles)
859 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
860 (nstcsStyle & nstcsMask),
861 (nstcsStyle & nstcsMask) & unsupported_styles);
863 This->style &= ~nstcsMask;
864 This->style |= (nstcsStyle & nstcsMask);
866 return S_OK;
869 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
870 NSTCSTYLE nstcsMask,
871 NSTCSTYLE *pnstcsStyle)
873 NSTC2Impl *This = (NSTC2Impl*)iface;
874 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
876 *pnstcsStyle = (This->style & nstcsMask);
878 return S_OK;
881 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
882 NSTCSTYLE2 nstcsMask,
883 NSTCSTYLE2 nstcsStyle)
885 NSTC2Impl *This = (NSTC2Impl*)iface;
886 TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
888 if((nstcsStyle & nstcsMask) & unsupported_styles2)
889 FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
890 (nstcsStyle & nstcsMask),
891 (nstcsStyle & nstcsMask) & unsupported_styles2);
893 This->style2 &= ~nstcsMask;
894 This->style2 |= (nstcsStyle & nstcsMask);
896 return S_OK;
899 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
900 NSTCSTYLE2 nstcsMask,
901 NSTCSTYLE2 *pnstcsStyle)
903 NSTC2Impl *This = (NSTC2Impl*)iface;
904 TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
906 *pnstcsStyle = (This->style2 & nstcsMask);
908 return S_OK;
911 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
912 NSTC2_fnQueryInterface,
913 NSTC2_fnAddRef,
914 NSTC2_fnRelease,
915 NSTC2_fnInitialize,
916 NSTC2_fnTreeAdvise,
917 NSTC2_fnTreeUnadvise,
918 NSTC2_fnAppendRoot,
919 NSTC2_fnInsertRoot,
920 NSTC2_fnRemoveRoot,
921 NSTC2_fnRemoveAllRoots,
922 NSTC2_fnGetRootItems,
923 NSTC2_fnSetItemState,
924 NSTC2_fnGetItemState,
925 NSTC2_fnGetSelectedItems,
926 NSTC2_fnGetItemCustomState,
927 NSTC2_fnSetItemCustomState,
928 NSTC2_fnEnsureItemVisible,
929 NSTC2_fnSetTheme,
930 NSTC2_fnGetNextItem,
931 NSTC2_fnHitTest,
932 NSTC2_fnGetItemRect,
933 NSTC2_fnCollapseAll,
934 NSTC2_fnSetControlStyle,
935 NSTC2_fnGetControlStyle,
936 NSTC2_fnSetControlStyle2,
937 NSTC2_fnGetControlStyle2
940 /**************************************************************************
941 * IOleWindow Implementation
944 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
946 return (NSTC2Impl *)((char*)iface - FIELD_OFFSET(NSTC2Impl, lpowVtbl));
949 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
951 NSTC2Impl *This = impl_from_IOleWindow(iface);
952 TRACE("%p\n", This);
953 return NSTC2_fnQueryInterface((INameSpaceTreeControl2*)This, riid, ppvObject);
956 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
958 NSTC2Impl *This = impl_from_IOleWindow(iface);
959 TRACE("%p\n", This);
960 return NSTC2_fnAddRef((INameSpaceTreeControl2*)This);
963 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
965 NSTC2Impl *This = impl_from_IOleWindow(iface);
966 TRACE("%p\n", This);
967 return NSTC2_fnRelease((INameSpaceTreeControl2*)This);
970 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
972 NSTC2Impl *This = impl_from_IOleWindow(iface);
973 TRACE("%p (%p)\n", This, phwnd);
975 *phwnd = This->hwnd_main;
976 return S_OK;
979 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
981 NSTC2Impl *This = impl_from_IOleWindow(iface);
982 TRACE("%p (%d)\n", This, fEnterMode);
984 /* Not implemented */
985 return E_NOTIMPL;
988 static const IOleWindowVtbl vt_IOleWindow = {
989 IOW_fnQueryInterface,
990 IOW_fnAddRef,
991 IOW_fnRelease,
992 IOW_fnGetWindow,
993 IOW_fnContextSensitiveHelp
996 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
998 NSTC2Impl *nstc;
999 HRESULT ret;
1001 TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1003 if(!ppv)
1004 return E_POINTER;
1005 if(pUnkOuter)
1006 return CLASS_E_NOAGGREGATION;
1008 EFRAME_LockModule();
1010 nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1011 nstc->ref = 1;
1012 nstc->lpVtbl = &vt_INameSpaceTreeControl2;
1013 nstc->lpowVtbl = &vt_IOleWindow;
1015 list_init(&nstc->roots);
1017 ret = INameSpaceTreeControl_QueryInterface((INameSpaceTreeControl*)nstc, riid, ppv);
1018 INameSpaceTreeControl_Release((INameSpaceTreeControl*)nstc);
1020 TRACE("--(%p)\n", ppv);
1021 return ret;