ddraw: Do not create implicit depth buffer.
[wine] / dlls / explorerframe / nstc.c
1 /*
2  * NamespaceTreeControl implementation.
3  *
4  * Copyright 2010 David Hedberg
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "shellapi.h"
32
33 #include "wine/list.h"
34 #include "wine/debug.h"
35
36 #include "explorerframe_main.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
39
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;
48
49 typedef struct {
50     INameSpaceTreeControl2 INameSpaceTreeControl2_iface;
51     IOleWindow IOleWindow_iface;
52     LONG ref;
53
54     HWND hwnd_main;
55     HWND hwnd_tv;
56
57     WNDPROC tv_oldwndproc;
58
59     NSTCSTYLE style;
60     NSTCSTYLE2 style2;
61     struct list roots;
62
63     INameSpaceTreeControlEvents *pnstce;
64 } NSTC2Impl;
65
66 static const DWORD unsupported_styles =
67     NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE |
68     NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON |
69     NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS;
70 static const DWORD unsupported_styles2 =
71     NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
72     NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
73
74 static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface)
75 {
76     return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface);
77 }
78
79 static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface)
80 {
81     return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface);
82 }
83
84 /* Forward declarations */
85 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
86
87 /*************************************************************************
88 * NamespaceTree event wrappers
89 */
90 static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
91                                             int *piDefaultIcon, int *piOpenIcon)
92 {
93     HRESULT ret;
94     LONG refcount;
95     if(!This->pnstce) return E_NOTIMPL;
96
97     refcount = IShellItem_AddRef(psi);
98     ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->pnstce, psi, piDefaultIcon, piOpenIcon);
99     if(IShellItem_Release(psi) < refcount - 1)
100         ERR("ShellItem was released by client - please file a bug.\n");
101     return ret;
102 }
103
104 static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
105 {
106     HRESULT ret;
107     LONG refcount;
108     if(!This->pnstce) return S_OK;
109
110     refcount = IShellItem_AddRef(psi);
111     ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
112     if(IShellItem_Release(psi) < refcount - 1)
113         ERR("ShellItem was released by client - please file a bug.\n");
114     return ret;
115 }
116
117 static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
118 {
119     HRESULT ret;
120     LONG refcount;
121     if(!This->pnstce) return S_OK;
122
123     refcount = IShellItem_AddRef(psi);
124     ret = INameSpaceTreeControlEvents_OnItemDeleted(This->pnstce, psi, fIsRoot);
125     if(IShellItem_Release(psi) < refcount - 1)
126         ERR("ShellItem was released by client - please file a bug.\n");
127     return ret;
128 }
129
130 static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi)
131 {
132     HRESULT ret;
133     LONG refcount;
134     if(!This->pnstce) return S_OK;
135
136     refcount = IShellItem_AddRef(psi);
137     ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->pnstce, psi);
138     if(IShellItem_Release(psi) < refcount - 1)
139         ERR("ShellItem was released by client - please file a bug.\n");
140     return ret;
141 }
142
143 static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi)
144 {
145     HRESULT ret;
146     LONG refcount;
147     if(!This->pnstce) return S_OK;
148
149     refcount = IShellItem_AddRef(psi);
150     ret = INameSpaceTreeControlEvents_OnAfterExpand(This->pnstce, psi);
151     if(IShellItem_Release(psi) < refcount - 1)
152         ERR("ShellItem was released by client - please file a bug.\n");
153     return ret;
154 }
155
156 static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi,
157                                   NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType)
158 {
159     HRESULT ret;
160     LONG refcount;
161     if(!This->pnstce) return S_OK;
162
163     refcount = IShellItem_AddRef(psi);
164     ret = INameSpaceTreeControlEvents_OnItemClick(This->pnstce, psi, nstceHitTest, nstceClickType);
165     if(IShellItem_Release(psi) < refcount - 1)
166         ERR("ShellItem was released by client - please file a bug.\n");
167     return ret;
168 }
169
170 static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia)
171 {
172     if(!This->pnstce) return S_OK;
173
174     return INameSpaceTreeControlEvents_OnSelectionChanged(This->pnstce, psia);
175 }
176
177 static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
178 {
179     if(!This->pnstce) return S_OK;
180
181     return INameSpaceTreeControlEvents_OnKeyboardInput(This->pnstce, uMsg, wParam, lParam);
182 }
183
184 /*************************************************************************
185  * NamespaceTree helper functions
186  */
187 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
188                                        NSTCSTYLE nstcs_mask, DWORD *new_style)
189 {
190     DWORD old_style, tv_mask = 0;
191     TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
192
193     if(This->hwnd_tv)
194         old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
195     else
196         old_style = /* The default */
197             WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
198             WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
199             TVS_EDITLABELS | TVS_TRACKSELECT;
200
201     if(nstcs_mask & NSTCS_HASEXPANDOS)         tv_mask |= TVS_HASBUTTONS;
202     if(nstcs_mask & NSTCS_HASLINES)            tv_mask |= TVS_HASLINES;
203     if(nstcs_mask & NSTCS_FULLROWSELECT)       tv_mask |= TVS_FULLROWSELECT;
204     if(nstcs_mask & NSTCS_HORIZONTALSCROLL)    tv_mask |= TVS_NOHSCROLL;
205     if(nstcs_mask & NSTCS_ROOTHASEXPANDO)      tv_mask |= TVS_LINESATROOT;
206     if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
207     if(nstcs_mask & NSTCS_NOINFOTIP)           tv_mask |= TVS_INFOTIP;
208     if(nstcs_mask & NSTCS_EVENHEIGHT)          tv_mask |= TVS_NONEVENHEIGHT;
209     if(nstcs_mask & NSTCS_DISABLEDRAGDROP)     tv_mask |= TVS_DISABLEDRAGDROP;
210     if(nstcs_mask & NSTCS_NOEDITLABELS)        tv_mask |= TVS_EDITLABELS;
211     if(nstcs_mask & NSTCS_CHECKBOXES)          tv_mask |= TVS_CHECKBOXES;
212
213     *new_style = 0;
214
215     if(nstcs & NSTCS_HASEXPANDOS)         *new_style |= TVS_HASBUTTONS;
216     if(nstcs & NSTCS_HASLINES)            *new_style |= TVS_HASLINES;
217     if(nstcs & NSTCS_FULLROWSELECT)       *new_style |= TVS_FULLROWSELECT;
218     if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
219     if(nstcs & NSTCS_ROOTHASEXPANDO)      *new_style |= TVS_LINESATROOT;
220     if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
221     if(!(nstcs & NSTCS_NOINFOTIP))        *new_style |= TVS_INFOTIP;
222     if(!(nstcs & NSTCS_EVENHEIGHT))       *new_style |= TVS_NONEVENHEIGHT;
223     if(nstcs & NSTCS_DISABLEDRAGDROP)     *new_style |= TVS_DISABLEDRAGDROP;
224     if(!(nstcs & NSTCS_NOEDITLABELS))     *new_style |= TVS_EDITLABELS;
225     if(nstcs & NSTCS_CHECKBOXES)          *new_style |= TVS_CHECKBOXES;
226
227     *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask);
228
229     TRACE("old: %08x, new: %08x\n", old_style, *new_style);
230
231     return old_style^*new_style;
232 }
233
234 static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
235 {
236     TVITEMEXW tvi;
237
238     tvi.mask = TVIF_PARAM;
239     tvi.lParam = 0;
240     tvi.hItem = hitem;
241
242     SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
243
244     TRACE("ShellItem: %p\n", (void*)tvi.lParam);
245     return (IShellItem*)tvi.lParam;
246 }
247
248 /* Returns the root that the given treeitem belongs to. */
249 static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem)
250 {
251     HTREEITEM tmp, hroot = hitem;
252     nstc_root *root;
253
254     /* Work our way up the hierarchy */
255     for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot)
256         tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot);
257
258     /* Search through the list of roots for a match */
259     LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
260         if(root->htreeitem == hroot)
261             break;
262
263     TRACE("root is %p\n", root);
264     return root;
265 }
266
267 /* Find a shellitem in the tree, starting from the given node. */
268 static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node,
269                                       IShellItem *psi)
270 {
271     IShellItem *psi_node;
272     HTREEITEM next, result = NULL;
273     HRESULT hr;
274     int cmpo;
275     TRACE("%p, %p, %p\n", This, node, psi);
276
277     /* Check this node */
278     psi_node = shellitem_from_treeitem(This, node);
279     hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo);
280     if(hr == S_OK)
281         return node;
282
283     /* Any children? */
284     next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
285                                    TVGN_CHILD, (LPARAM)node);
286     if(next)
287     {
288         result = search_for_shellitem(This, next, psi);
289         if(result) return result;
290     }
291
292     /* Try our next sibling. */
293     next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
294                                    TVGN_NEXT, (LPARAM)node);
295     if(next)
296         result = search_for_shellitem(This, next, psi);
297
298     return result;
299 }
300
301 static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi)
302 {
303     HTREEITEM root;
304     TRACE("%p, %p\n", This, psi);
305
306     root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM,
307                                    TVGN_ROOT, 0);
308     if(!root)
309         return NULL;
310
311     return search_for_shellitem(This, root, psi);
312 }
313
314 static int get_icon(LPCITEMIDLIST lpi, UINT extra_flags)
315 {
316     SHFILEINFOW sfi;
317     UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
318     SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
319     return sfi.iIcon;
320 }
321
322 /* Insert a shellitem into the given place in the tree and return the
323    resulting treeitem. */
324 static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
325                                   HTREEITEM hParent, HTREEITEM hInsertAfter)
326 {
327     TVINSERTSTRUCTW tvins;
328     TVITEMEXW *tvi = &tvins.u.itemex;
329     HTREEITEM hinserted;
330     TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
331
332     tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
333     tvi->cChildren = I_CHILDRENCALLBACK;
334     tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
335     tvi->pszText = LPSTR_TEXTCALLBACKW;
336
337     /* Every treeitem contains a pointer to the corresponding ShellItem. */
338     tvi->lParam = (LPARAM)psi;
339     tvins.hParent = hParent;
340     tvins.hInsertAfter = hInsertAfter;
341
342     hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
343                                         (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
344     if(hinserted)
345         IShellItem_AddRef(psi);
346
347     return hinserted;
348 }
349
350 /* Enumerates the children of the folder represented by hitem
351  * according to the settings for the root, and adds them to the
352  * treeview. Returns the number of children added. */
353 static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem)
354 {
355     IShellItem *psiParent = shellitem_from_treeitem(This, hitem);
356     nstc_root *root = root_for_treeitem(This, hitem);
357     LPITEMIDLIST pidl_parent;
358     IShellFolder *psf;
359     IEnumIDList *peidl;
360     UINT added = 0;
361     HRESULT hr;
362
363     hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent);
364     if(SUCCEEDED(hr))
365     {
366         hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
367         if(SUCCEEDED(hr))
368         {
369             hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl);
370             if(SUCCEEDED(hr))
371             {
372                 LPITEMIDLIST pidl;
373                 IShellItem *psi;
374                 ULONG fetched;
375
376                 while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) )
377                 {
378                     hr = SHCreateShellItem(NULL, psf , pidl, &psi);
379                     ILFree(pidl);
380                     if(SUCCEEDED(hr))
381                     {
382                         if(insert_shellitem(This, psi, hitem, NULL))
383                         {
384                             events_OnItemAdded(This, psi, FALSE);
385                             added++;
386                         }
387
388                         IShellItem_Release(psi);
389                     }
390                     else
391                         ERR("SHCreateShellItem failed with 0x%08x\n", hr);
392                 }
393                 IEnumIDList_Release(peidl);
394             }
395             else
396                 ERR("EnumObjects failed with 0x%08x\n", hr);
397
398             IShellFolder_Release(psf);
399         }
400         else
401             ERR("BindToHandler failed with 0x%08x\n", hr);
402
403         ILFree(pidl_parent);
404     }
405     else
406         ERR("SHGetIDListFromObject failed with 0x%08x\n", hr);
407
408     return added;
409 }
410
411 static HTREEITEM get_selected_treeitem(NSTC2Impl *This)
412 {
413     return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0);
414 }
415
416 static IShellItem *get_selected_shellitem(NSTC2Impl *This)
417 {
418     return shellitem_from_treeitem(This, get_selected_treeitem(This));
419 }
420
421 static void collapse_all(NSTC2Impl *This, HTREEITEM node)
422 {
423     HTREEITEM next;
424
425     /* Collapse this node first, and then first child/next sibling. */
426     SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node);
427
428     next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
429     if(next) collapse_all(This, next);
430
431     next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node);
432     if(next) collapse_all(This, next);
433 }
434
435 static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag)
436 {
437     TVHITTESTINFO tviht;
438     tviht.pt.x = pt->x;
439     tviht.pt.y = pt->y;
440     tviht.hItem = NULL;
441
442     SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht);
443     if(hitflag) *hitflag = tviht.flags;
444     return tviht.hItem;
445 }
446
447 /*************************************************************************
448  * NamespaceTree window functions
449  */
450 static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
451 {
452     NSTC2Impl *This = crs->lpCreateParams;
453     HIMAGELIST ShellSmallIconList;
454     DWORD treeview_style, treeview_ex_style;
455
456     TRACE("%p (%p)\n", This, crs);
457     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
458     This->hwnd_main = hWnd;
459
460     treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
461
462     This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
463                                     0, 0, crs->cx, crs->cy,
464                                     hWnd, NULL, explorerframe_hinstance, NULL);
465
466     if(!This->hwnd_tv)
467     {
468         ERR("Failed to create treeview!\n");
469         return HRESULT_FROM_WIN32(GetLastError());
470     }
471
472     treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
473         TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
474
475     if(This->style & NSTCS_AUTOHSCROLL)
476         treeview_ex_style |= TVS_EX_AUTOHSCROLL;
477     if(This->style & NSTCS_FADEINOUTEXPANDOS)
478         treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
479     if(This->style & NSTCS_PARTIALCHECKBOXES)
480         treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
481     if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
482         treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
483     if(This->style & NSTCS_DIMMEDCHECKBOXES)
484         treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
485
486     SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
487
488     if(Shell_GetImageLists(NULL, &ShellSmallIconList))
489     {
490         SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
491                      (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
492     }
493     else
494     {
495         ERR("Failed to get the System Image List.\n");
496     }
497
498     INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface);
499
500     /* Subclass the treeview to get the keybord events. */
501     This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC,
502                                                      (ULONG_PTR)tv_wndproc);
503     if(This->tv_oldwndproc)
504         SetPropA(This->hwnd_tv, "PROP_THIS", This);
505
506     return TRUE;
507 }
508
509 static LRESULT resize_namespacetree(NSTC2Impl *This)
510 {
511     RECT rc;
512     TRACE("%p\n", This);
513
514     GetClientRect(This->hwnd_main, &rc);
515     MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE);
516
517     return TRUE;
518 }
519
520 static LRESULT destroy_namespacetree(NSTC2Impl *This)
521 {
522     TRACE("%p\n", This);
523
524     /* Undo the subclassing */
525     if(This->tv_oldwndproc)
526     {
527         SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc);
528         RemovePropA(This->hwnd_tv, "PROP_THIS");
529     }
530
531     INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface);
532
533     /* This reference was added in create_namespacetree */
534     INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface);
535     return TRUE;
536 }
537
538 static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
539 {
540     NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
541     TRACE("%p\n", This);
542
543     IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
544     return TRUE;
545 }
546
547 static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
548 {
549     NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
550     TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item;
551     IShellItem *psi = shellitem_from_treeitem(This, item->hItem);
552     HRESULT hr;
553
554     TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask);
555
556     if(item->mask & TVIF_CHILDREN)
557     {
558         SFGAOF sfgao;
559
560         hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
561         if(SUCCEEDED(hr))
562             item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
563         else
564             item->cChildren = 1;
565
566         item->mask |= TVIF_DI_SETITEM;
567     }
568
569     if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE))
570     {
571         LPITEMIDLIST pidl;
572
573         hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage);
574         if(FAILED(hr))
575         {
576             hr = SHGetIDListFromObject((IUnknown*)psi, &pidl);
577             if(SUCCEEDED(hr))
578             {
579                 item->iImage = item->iSelectedImage = get_icon(pidl, 0);
580                 item->mask |= TVIF_DI_SETITEM;
581                 ILFree(pidl);
582             }
583             else
584                 ERR("Failed to get IDList (%08x).\n", hr);
585         }
586     }
587
588     if(item->mask & TVIF_TEXT)
589     {
590         LPWSTR display_name;
591
592         hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name);
593         if(SUCCEEDED(hr))
594         {
595             lstrcpynW(item->pszText, display_name, MAX_PATH);
596             item->mask |= TVIF_DI_SETITEM;
597             CoTaskMemFree(display_name);
598         }
599         else
600             ERR("Failed to get display name (%08x).\n", hr);
601     }
602
603     return TRUE;
604 }
605
606 static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node)
607 {
608     return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node);
609 }
610
611 static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam)
612 {
613     NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
614     IShellItem *psi;
615     TRACE("%p\n", This);
616
617     psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
618     events_OnBeforeExpand(This, psi);
619
620     if(!treenode_has_subfolders(This, nmtv->itemNew.hItem))
621     {
622         /* The node has no children, try to find some */
623         if(!fill_sublevel(This, nmtv->itemNew.hItem))
624         {
625             TVITEMEXW tvi;
626             /* Failed to enumerate any children, remove the expando
627              * (if any). */
628             tvi.hItem = nmtv->itemNew.hItem;
629             tvi.mask = TVIF_CHILDREN;
630             tvi.cChildren = 0;
631             SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
632
633             return TRUE;
634         }
635     }
636     return FALSE;
637 }
638
639 static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam)
640 {
641     NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
642     IShellItem *psi;
643     TRACE("%p\n", This);
644
645     psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
646     events_OnAfterExpand(This, psi);
647     return TRUE;
648 }
649
650 static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam)
651 {
652     NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
653     IShellItemArray *psia;
654     IShellItem *psi;
655     HRESULT hr;
656     TRACE("%p\n", This);
657
658     /* Note: Only supports one selected item. */
659     psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem);
660     hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
661     if(SUCCEEDED(hr))
662     {
663         events_OnSelectionChanged(This, psia);
664         IShellItemArray_Release(psia);
665     }
666
667     return TRUE;
668 }
669
670 static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr)
671 {
672     TVHITTESTINFO tvhit;
673     IShellItem *psi;
674     HRESULT hr;
675     TRACE("%p (%p)\n", This, nmhdr);
676
677     GetCursorPos(&tvhit.pt);
678     ScreenToClient(This->hwnd_tv, &tvhit.pt);
679     SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
680
681     if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW))
682         return TRUE;
683
684     /* TVHT_ maps onto the corresponding NSTCEHT_ */
685     psi = shellitem_from_treeitem(This, tvhit.hItem);
686     hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON);
687
688     /* The expando should not be expanded unless
689      * double-clicked. */
690     if(tvhit.flags == TVHT_ONITEMBUTTON)
691         return TRUE;
692
693     if(SUCCEEDED(hr))
694         return FALSE;
695     else
696         return TRUE;
697 }
698
699 static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam)
700 {
701     TVHITTESTINFO tvhit;
702     IShellItem *psi;
703     HRESULT hr;
704     TRACE("%p (%lx, %lx)\n", This, wParam, lParam);
705
706     tvhit.pt.x = (int)(short)LOWORD(lParam);
707     tvhit.pt.y = (int)(short)HIWORD(lParam);
708
709     SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit);
710
711     /* Seems to generate only ONITEM and ONITEMICON */
712     if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) )
713         return FALSE;
714
715     psi = shellitem_from_treeitem(This, tvhit.hItem);
716     hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON);
717
718     if(SUCCEEDED(hr))
719         return FALSE;
720     else
721         return TRUE;
722 }
723
724 static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam)
725 {
726     IShellItem *psi;
727     HTREEITEM hitem;
728     TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam);
729
730     /* Handled by the client? */
731     if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam)))
732         return TRUE;
733
734     if(uMsg == WM_KEYDOWN)
735     {
736         switch(wParam)
737         {
738         case VK_DELETE:
739             psi = get_selected_shellitem(This);
740             FIXME("Deletion of file requested (shellitem: %p).\n", psi);
741             return TRUE;
742
743         case VK_F2:
744             hitem = get_selected_treeitem(This);
745             SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem);
746             return TRUE;
747         }
748     }
749
750     /* Let the TreeView handle the key */
751     return FALSE;
752 }
753
754 static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
755 {
756     NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS");
757
758     switch(uMessage) {
759     case WM_KEYDOWN:
760     case WM_KEYUP:
761     case WM_CHAR:
762     case WM_SYSKEYDOWN:
763     case WM_SYSKEYUP:
764     case WM_SYSCHAR:
765         if(on_kbd_event(This, uMessage, wParam, lParam))
766             return TRUE;
767         break;
768
769     case WM_MBUTTONUP:        return on_wm_mbuttonup(This, wParam, lParam);
770     }
771
772     /* Pass the message on to the treeview */
773     return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam);
774 }
775
776 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
777                                       WPARAM wParam, LPARAM lParam)
778 {
779     NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
780     NMHDR *nmhdr;
781
782     switch(uMessage)
783     {
784     case WM_NCCREATE:         return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
785     case WM_SIZE:             return resize_namespacetree(This);
786     case WM_DESTROY:          return destroy_namespacetree(This);
787     case WM_NOTIFY:
788         nmhdr = (NMHDR*)lParam;
789         switch(nmhdr->code)
790         {
791         case NM_CLICK:            return on_nm_click(This, nmhdr);
792         case TVN_DELETEITEMW:     return on_tvn_deleteitemw(This, lParam);
793         case TVN_GETDISPINFOW:    return on_tvn_getdispinfow(This, lParam);
794         case TVN_ITEMEXPANDINGW:  return on_tvn_itemexpandingw(This, lParam);
795         case TVN_ITEMEXPANDEDW:   return on_tvn_itemexpandedw(This, lParam);
796         case TVN_SELCHANGEDW:     return on_tvn_selchangedw(This, lParam);
797         default:                  break;
798         }
799         break;
800     default:                  return DefWindowProcW(hWnd, uMessage, wParam, lParam);
801     }
802     return 0;
803 }
804
805 /**************************************************************************
806  * INameSpaceTreeControl2 Implementation
807  */
808 static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface,
809                                              REFIID riid,
810                                              void **ppvObject)
811 {
812     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
813     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
814
815     *ppvObject = NULL;
816     if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) ||
817        IsEqualIID(riid, &IID_INameSpaceTreeControl) ||
818        IsEqualIID(riid, &IID_IUnknown))
819     {
820         *ppvObject = This;
821     }
822     else if(IsEqualIID(riid, &IID_IOleWindow))
823     {
824         *ppvObject = &This->IOleWindow_iface;
825     }
826
827     if(*ppvObject)
828     {
829         IUnknown_AddRef((IUnknown*)*ppvObject);
830         return S_OK;
831     }
832
833     return E_NOINTERFACE;
834 }
835
836 static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface)
837 {
838     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
839     LONG ref = InterlockedIncrement(&This->ref);
840
841     TRACE("%p - ref %d\n", This, ref);
842
843     return ref;
844 }
845
846 static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface)
847 {
848     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
849     LONG ref = InterlockedDecrement(&This->ref);
850
851     TRACE("%p - ref: %d\n", This, ref);
852
853     if(!ref)
854     {
855         TRACE("Freeing.\n");
856         HeapFree(GetProcessHeap(), 0, This);
857         EFRAME_UnlockModule();
858         return 0;
859     }
860
861     return ref;
862 }
863
864 static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
865                                          HWND hwndParent,
866                                          RECT *prc,
867                                          NSTCSTYLE nstcsFlags)
868 {
869     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
870     WNDCLASSW wc;
871     DWORD window_style, window_ex_style;
872     RECT rc;
873     static const WCHAR NSTC2_CLASS_NAME[] =
874         {'N','a','m','e','s','p','a','c','e','T','r','e','e',
875          'C','o','n','t','r','o','l',0};
876
877     TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
878
879     if(nstcsFlags & unsupported_styles)
880         FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
881               nstcsFlags, nstcsFlags & unsupported_styles);
882
883     This->style = nstcsFlags;
884
885     if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
886     {
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;
897
898         if (!RegisterClassW(&wc)) return E_FAIL;
899     }
900
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;
905
906     if(prc)
907         CopyRect(&rc, prc);
908     else
909         rc.left = rc.right = rc.top = rc.bottom = 0;
910
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);
914
915     if(!This->hwnd_main)
916     {
917         ERR("Failed to create the window.\n");
918         return HRESULT_FROM_WIN32(GetLastError());
919     }
920
921     return S_OK;
922 }
923
924 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface,
925                                          IUnknown *punk,
926                                          DWORD *pdwCookie)
927 {
928     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
929     HRESULT hr;
930     TRACE("%p (%p, %p)\n", This, punk, pdwCookie);
931
932     *pdwCookie = 0;
933
934     /* Only one client supported */
935     if(This->pnstce)
936         return E_FAIL;
937
938     hr = IUnknown_QueryInterface(punk, &IID_INameSpaceTreeControlEvents,(void**)&This->pnstce);
939     if(SUCCEEDED(hr))
940     {
941         *pdwCookie = 1;
942         return hr;
943     }
944
945     return E_FAIL;
946 }
947
948 static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface,
949                                            DWORD dwCookie)
950 {
951     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
952     TRACE("%p (%x)\n", This, dwCookie);
953
954     /* The cookie is ignored. */
955
956     if(This->pnstce)
957     {
958         INameSpaceTreeControlEvents_Release(This->pnstce);
959         This->pnstce = NULL;
960     }
961
962     return S_OK;
963 }
964
965 static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
966                                          int iIndex,
967                                          IShellItem *psiRoot,
968                                          SHCONTF grfEnumFlags,
969                                          NSTCROOTSTYLE grfRootStyle,
970                                          IShellItemFilter *pif)
971 {
972     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
973     nstc_root *new_root;
974     struct list *add_after_entry;
975     HTREEITEM add_after_hitem;
976     UINT i;
977
978     TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
979
980     new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
981     if(!new_root)
982         return E_OUTOFMEMORY;
983
984     new_root->psi = psiRoot;
985     new_root->enum_flags = grfEnumFlags;
986     new_root->root_style = grfRootStyle;
987     new_root->pif = pif;
988
989     /* We want to keep the roots in the internal list and in the
990      * treeview in the same order. */
991     add_after_entry = &This->roots;
992     for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
993         add_after_entry = list_next(&This->roots, add_after_entry);
994
995     if(add_after_entry == &This->roots)
996         add_after_hitem = TVI_FIRST;
997     else
998         add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
999
1000     new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
1001     if(!new_root->htreeitem)
1002     {
1003         WARN("Failed to add the root.\n");
1004         HeapFree(GetProcessHeap(), 0, new_root);
1005         return E_FAIL;
1006     }
1007
1008     list_add_after(add_after_entry, &new_root->entry);
1009     events_OnItemAdded(This, psiRoot, TRUE);
1010
1011     if(grfRootStyle & NSTCRS_HIDDEN)
1012     {
1013         TVITEMEXW tvi;
1014         tvi.mask = TVIF_STATEEX;
1015         tvi.uStateEx = TVIS_EX_FLAT;
1016         tvi.hItem = new_root->htreeitem;
1017
1018         SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1019     }
1020
1021     if(grfRootStyle & NSTCRS_EXPANDED)
1022         SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
1023                      (LPARAM)new_root->htreeitem);
1024
1025     return S_OK;
1026 }
1027
1028 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
1029                                          IShellItem *psiRoot,
1030                                          SHCONTF grfEnumFlags,
1031                                          NSTCROOTSTYLE grfRootStyle,
1032                                          IShellItemFilter *pif)
1033 {
1034     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1035     UINT root_count;
1036     TRACE("%p, %p, %x, %x, %p\n",
1037           This, psiRoot, grfEnumFlags, grfRootStyle, pif);
1038
1039     root_count = list_count(&This->roots);
1040
1041     return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
1042 }
1043
1044 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
1045                                          IShellItem *psiRoot)
1046 {
1047     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1048     nstc_root *cursor, *root = NULL;
1049     TRACE("%p (%p)\n", This, psiRoot);
1050
1051     if(!psiRoot)
1052         return E_NOINTERFACE;
1053
1054     LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
1055     {
1056         HRESULT hr;
1057         int order;
1058         hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
1059         if(hr == S_OK)
1060         {
1061             root = cursor;
1062             break;
1063         }
1064     }
1065
1066     TRACE("root %p\n", root);
1067     if(root)
1068     {
1069         events_OnItemDeleted(This, root->psi, TRUE);
1070         SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
1071         list_remove(&root->entry);
1072         HeapFree(GetProcessHeap(), 0, root);
1073         return S_OK;
1074     }
1075     else
1076     {
1077         WARN("No matching root found.\n");
1078         return E_FAIL;
1079     }
1080 }
1081
1082 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
1083 {
1084     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1085     nstc_root *cur1, *cur2;
1086     UINT removed = 0;
1087     TRACE("%p\n", This);
1088
1089     LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
1090     {
1091         NSTC2_fnRemoveRoot(iface, cur1->psi);
1092         removed++;
1093     }
1094
1095     if(removed)
1096         return S_OK;
1097     else
1098         return E_INVALIDARG;
1099 }
1100
1101 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
1102                                            IShellItemArray **ppsiaRootItems)
1103 {
1104     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1105     IShellFolder *psf;
1106     LPITEMIDLIST *array;
1107     nstc_root *root;
1108     UINT count, i;
1109     HRESULT hr;
1110     TRACE("%p (%p)\n", This, ppsiaRootItems);
1111
1112     count = list_count(&This->roots);
1113
1114     if(!count)
1115         return E_INVALIDARG;
1116
1117     array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST*)*count);
1118
1119     i = 0;
1120     LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1121         SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
1122
1123     SHGetDesktopFolder(&psf);
1124     hr = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
1125                                 ppsiaRootItems);
1126     IShellFolder_Release(psf);
1127
1128     for(i = 0; i < count; i++)
1129         ILFree(array[i]);
1130
1131     HeapFree(GetProcessHeap(), 0, array);
1132
1133     return hr;
1134 }
1135
1136 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
1137                                            IShellItem *psi,
1138                                            NSTCITEMSTATE nstcisMask,
1139                                            NSTCITEMSTATE nstcisFlags)
1140 {
1141     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1142     TVITEMEXW tvi;
1143     HTREEITEM hitem;
1144
1145     TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags);
1146
1147     hitem = treeitem_from_shellitem(This, psi);
1148     if(!hitem) return E_INVALIDARG;
1149
1150     /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results
1151        in two TVM_SETITEMW's */
1152     if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED)
1153     {
1154         SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem);
1155         SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem);
1156     }
1157     if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND)
1158     {
1159         SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem);
1160     }
1161
1162     /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */
1163     if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED)
1164     {
1165         WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE;
1166         SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem);
1167     }
1168
1169     if(nstcisMask & NSTCIS_DISABLED)
1170         tvi.mask = TVIF_STATE | TVIF_STATEEX;
1171     else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) ||
1172              ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) ||
1173              (nstcisFlags & NSTCIS_DISABLED) )
1174         tvi.mask = TVIF_STATE;
1175     else
1176         tvi.mask = 0;
1177
1178     if(tvi.mask)
1179     {
1180         tvi.stateMask = tvi.state = 0;
1181         tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0;
1182         tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1183         tvi.state     |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0;
1184
1185         if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED))
1186         {
1187             tvi.stateMask = 0;
1188         }
1189
1190         tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0;
1191         tvi.hItem = hitem;
1192
1193         SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
1194     }
1195
1196     return S_OK;
1197 }
1198
1199 static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface,
1200                                            IShellItem *psi,
1201                                            NSTCITEMSTATE nstcisMask,
1202                                            NSTCITEMSTATE *pnstcisFlags)
1203 {
1204     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1205     HTREEITEM hitem;
1206     TVITEMEXW tvi;
1207     TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags);
1208
1209     hitem = treeitem_from_shellitem(This, psi);
1210     if(!hitem)
1211         return E_INVALIDARG;
1212
1213     *pnstcisFlags = 0;
1214
1215     tvi.hItem = hitem;
1216     tvi.mask = TVIF_STATE;
1217     tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD;
1218
1219     if(nstcisMask & NSTCIS_DISABLED)
1220         tvi.mask |= TVIF_STATEEX;
1221
1222     SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
1223     *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0;
1224     *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0;
1225     *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0;
1226     *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0;
1227
1228     *pnstcisFlags &= nstcisMask;
1229
1230     return S_OK;
1231 }
1232
1233 static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface,
1234                                                IShellItemArray **psiaItems)
1235 {
1236     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1237     IShellItem *psiselected;
1238     HRESULT hr;
1239     TRACE("%p (%p)\n", This, psiaItems);
1240
1241     psiselected = get_selected_shellitem(This);
1242     if(!psiselected)
1243         return E_FAIL;
1244
1245     hr = SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray,
1246                                              (void**)psiaItems);
1247     return hr;
1248 }
1249
1250 static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface,
1251                                                  IShellItem *psi,
1252                                                  int *piStateNumber)
1253 {
1254     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1255     FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber);
1256     return E_NOTIMPL;
1257 }
1258
1259 static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface,
1260                                                  IShellItem *psi,
1261                                                  int iStateNumber)
1262 {
1263     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1264     FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber);
1265     return E_NOTIMPL;
1266 }
1267
1268 static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface,
1269                                                 IShellItem *psi)
1270 {
1271     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1272     HTREEITEM hitem;
1273
1274     TRACE("%p (%p)\n", This, psi);
1275
1276     hitem = treeitem_from_shellitem(This, psi);
1277     if(hitem)
1278     {
1279         SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem);
1280         return S_OK;
1281     }
1282
1283     return E_INVALIDARG;
1284 }
1285
1286 static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface,
1287                                        LPCWSTR pszTheme)
1288 {
1289     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1290     FIXME("stub, %p (%p)\n", This, pszTheme);
1291     return E_NOTIMPL;
1292 }
1293
1294 static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface,
1295                                           IShellItem *psi,
1296                                           NSTCGNI nstcgi,
1297                                           IShellItem **ppsiNext)
1298 {
1299     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1300     HTREEITEM hitem, hnext;
1301     UINT tvgn;
1302     TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext);
1303
1304     if(!ppsiNext) return E_POINTER;
1305     if(!psi)      return E_FAIL;
1306
1307     *ppsiNext = NULL;
1308
1309     hitem = treeitem_from_shellitem(This, psi);
1310     if(!hitem)
1311         return E_INVALIDARG;
1312
1313     switch(nstcgi)
1314     {
1315     case NSTCGNI_NEXT:         tvgn = TVGN_NEXT; break;
1316     case NSTCGNI_NEXTVISIBLE:  tvgn = TVGN_NEXTVISIBLE; break;
1317     case NSTCGNI_PREV:         tvgn = TVGN_PREVIOUS; break;
1318     case NSTCGNI_PREVVISIBLE:  tvgn = TVGN_PREVIOUSVISIBLE; break;
1319     case NSTCGNI_PARENT:       tvgn = TVGN_PARENT; break;
1320     case NSTCGNI_CHILD:        tvgn = TVGN_CHILD; break;
1321     case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break;
1322     case NSTCGNI_LASTVISIBLE:  tvgn = TVGN_LASTVISIBLE; break;
1323     default:
1324         FIXME("Unknown nstcgi value %d\n", nstcgi);
1325         return E_FAIL;
1326     }
1327
1328     hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem);
1329     if(hnext)
1330     {
1331         *ppsiNext = shellitem_from_treeitem(This, hnext);
1332         IShellItem_AddRef(*ppsiNext);
1333         return S_OK;
1334     }
1335
1336     return E_FAIL;
1337 }
1338
1339 static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface,
1340                                       POINT *ppt,
1341                                       IShellItem **ppsiOut)
1342 {
1343     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1344     HTREEITEM hitem;
1345     TRACE("%p (%p, %p)\n", This, ppsiOut, ppt);
1346
1347     if(!ppt || !ppsiOut)
1348         return E_POINTER;
1349
1350     *ppsiOut = NULL;
1351
1352     hitem = treeitem_from_point(This, ppt, NULL);
1353     if(hitem)
1354         *ppsiOut = shellitem_from_treeitem(This, hitem);
1355
1356     if(*ppsiOut)
1357     {
1358         IShellItem_AddRef(*ppsiOut);
1359         return S_OK;
1360     }
1361
1362     return S_FALSE;
1363 }
1364
1365 static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface,
1366                                           IShellItem *psi,
1367                                           RECT *prect)
1368 {
1369     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1370     HTREEITEM hitem;
1371     TRACE("%p (%p, %p)\n", This, psi, prect);
1372
1373     if(!psi || !prect)
1374         return E_POINTER;
1375
1376     hitem = treeitem_from_shellitem(This, psi);
1377     if(hitem)
1378     {
1379         *(HTREEITEM*)prect = hitem;
1380         if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect))
1381         {
1382             MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2);
1383             return S_OK;
1384         }
1385     }
1386
1387     return E_INVALIDARG;
1388 }
1389
1390 static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface)
1391 {
1392     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1393     nstc_root *root;
1394     TRACE("%p\n", This);
1395
1396     LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
1397         collapse_all(This, root->htreeitem);
1398
1399     return S_OK;
1400 }
1401
1402 static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface,
1403                                               NSTCSTYLE nstcsMask,
1404                                               NSTCSTYLE nstcsStyle)
1405 {
1406     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1407     static const DWORD tv_style_flags =
1408         NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT |
1409         NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO |
1410         NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT |
1411         NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES;
1412     static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER;
1413     static const DWORD nstc_flags =
1414         NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM |
1415         NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS |
1416         NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON;
1417     TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1418
1419     /* Fail if there is an attempt to set an unknown style. */
1420     if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags))
1421         return E_FAIL;
1422
1423     if(nstcsMask & tv_style_flags)
1424     {
1425         DWORD new_style;
1426         treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style);
1427         SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style);
1428     }
1429
1430     /* Flags affecting the host window */
1431     if(nstcsMask & NSTCS_BORDER)
1432     {
1433         DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE);
1434         new_style &= ~WS_BORDER;
1435         new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0;
1436         SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style);
1437     }
1438     if(nstcsMask & NSTCS_TABSTOP)
1439     {
1440         DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE);
1441         new_style &= ~WS_EX_CONTROLPARENT;
1442         new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
1443         SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style);
1444     }
1445
1446     if((nstcsStyle & nstcsMask) & unsupported_styles)
1447         FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1448               (nstcsStyle & nstcsMask),
1449               (nstcsStyle & nstcsMask) & unsupported_styles);
1450
1451     This->style &= ~nstcsMask;
1452     This->style |= (nstcsStyle & nstcsMask);
1453
1454     return S_OK;
1455 }
1456
1457 static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface,
1458                                               NSTCSTYLE nstcsMask,
1459                                               NSTCSTYLE *pnstcsStyle)
1460 {
1461     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1462     TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1463
1464     *pnstcsStyle = (This->style & nstcsMask);
1465
1466     return S_OK;
1467 }
1468
1469 static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface,
1470                                                NSTCSTYLE2 nstcsMask,
1471                                                NSTCSTYLE2 nstcsStyle)
1472 {
1473     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1474     TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle);
1475
1476     if((nstcsStyle & nstcsMask) & unsupported_styles2)
1477         FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n",
1478               (nstcsStyle & nstcsMask),
1479               (nstcsStyle & nstcsMask) & unsupported_styles2);
1480
1481     This->style2 &= ~nstcsMask;
1482     This->style2 |= (nstcsStyle & nstcsMask);
1483
1484     return S_OK;
1485 }
1486
1487 static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface,
1488                                                NSTCSTYLE2 nstcsMask,
1489                                                NSTCSTYLE2 *pnstcsStyle)
1490 {
1491     NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface);
1492     TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle);
1493
1494     *pnstcsStyle = (This->style2 & nstcsMask);
1495
1496     return S_OK;
1497 }
1498
1499 static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = {
1500     NSTC2_fnQueryInterface,
1501     NSTC2_fnAddRef,
1502     NSTC2_fnRelease,
1503     NSTC2_fnInitialize,
1504     NSTC2_fnTreeAdvise,
1505     NSTC2_fnTreeUnadvise,
1506     NSTC2_fnAppendRoot,
1507     NSTC2_fnInsertRoot,
1508     NSTC2_fnRemoveRoot,
1509     NSTC2_fnRemoveAllRoots,
1510     NSTC2_fnGetRootItems,
1511     NSTC2_fnSetItemState,
1512     NSTC2_fnGetItemState,
1513     NSTC2_fnGetSelectedItems,
1514     NSTC2_fnGetItemCustomState,
1515     NSTC2_fnSetItemCustomState,
1516     NSTC2_fnEnsureItemVisible,
1517     NSTC2_fnSetTheme,
1518     NSTC2_fnGetNextItem,
1519     NSTC2_fnHitTest,
1520     NSTC2_fnGetItemRect,
1521     NSTC2_fnCollapseAll,
1522     NSTC2_fnSetControlStyle,
1523     NSTC2_fnGetControlStyle,
1524     NSTC2_fnSetControlStyle2,
1525     NSTC2_fnGetControlStyle2
1526 };
1527
1528 /**************************************************************************
1529  * IOleWindow Implementation
1530  */
1531
1532 static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
1533 {
1534     NSTC2Impl *This = impl_from_IOleWindow(iface);
1535     TRACE("%p\n", This);
1536     return NSTC2_fnQueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject);
1537 }
1538
1539 static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface)
1540 {
1541     NSTC2Impl *This = impl_from_IOleWindow(iface);
1542     TRACE("%p\n", This);
1543     return NSTC2_fnAddRef(&This->INameSpaceTreeControl2_iface);
1544 }
1545
1546 static ULONG WINAPI IOW_fnRelease(IOleWindow *iface)
1547 {
1548     NSTC2Impl *This = impl_from_IOleWindow(iface);
1549     TRACE("%p\n", This);
1550     return NSTC2_fnRelease(&This->INameSpaceTreeControl2_iface);
1551 }
1552
1553 static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd)
1554 {
1555     NSTC2Impl *This = impl_from_IOleWindow(iface);
1556     TRACE("%p (%p)\n", This, phwnd);
1557
1558     *phwnd = This->hwnd_main;
1559     return S_OK;
1560 }
1561
1562 static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
1563 {
1564     NSTC2Impl *This = impl_from_IOleWindow(iface);
1565     TRACE("%p (%d)\n", This, fEnterMode);
1566
1567     /* Not implemented */
1568     return E_NOTIMPL;
1569 }
1570
1571 static const IOleWindowVtbl vt_IOleWindow = {
1572     IOW_fnQueryInterface,
1573     IOW_fnAddRef,
1574     IOW_fnRelease,
1575     IOW_fnGetWindow,
1576     IOW_fnContextSensitiveHelp
1577 };
1578
1579 HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1580 {
1581     NSTC2Impl *nstc;
1582     HRESULT ret;
1583
1584     TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv);
1585
1586     if(!ppv)
1587         return E_POINTER;
1588     if(pUnkOuter)
1589         return CLASS_E_NOAGGREGATION;
1590
1591     EFRAME_LockModule();
1592
1593     nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl));
1594     nstc->ref = 1;
1595     nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2;
1596     nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
1597
1598     list_init(&nstc->roots);
1599
1600     ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv);
1601     INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface);
1602
1603     TRACE("--(%p)\n", ppv);
1604     return ret;
1605 }