[BROWSEUI] - explorerband: get the caption string from resource file instead of hardc...
[reactos.git] / reactos / dll / win32 / browseui / explorerband.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2016 Sylvain Deverre <deverre dot sylv at gmail dot com>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "precomp.h"
22 #include <commoncontrols.h>
23 #include <undocshell.h>
24
25 #if 1
26 #undef UNIMPLEMENTED
27
28 #define UNIMPLEMENTED DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
29 #endif
30
31 extern "C"
32 HRESULT WINAPI CExplorerBand_Constructor(REFIID riid, LPVOID *ppv)
33 {
34 return ShellObjectCreator<CExplorerBand>(riid, ppv);
35 }
36
37 CExplorerBand::CExplorerBand() :
38 pSite(NULL), fVisible(FALSE), bNavigating(FALSE), dwBandID(0)
39 {
40 }
41
42 CExplorerBand::~CExplorerBand()
43 {
44 }
45
46 void CExplorerBand::InitializeExplorerBand()
47 {
48 // Init the treeview here
49 HRESULT hr;
50 LPITEMIDLIST pidl;
51 CComPtr<IWebBrowser2> browserService;
52 SHChangeNotifyEntry shcne;
53
54 hr = SHGetDesktopFolder(&pDesktop);
55 if (FAILED_UNEXPECTEDLY(hr))
56 return;
57
58 hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidl);
59 if (FAILED_UNEXPECTEDLY(hr))
60 return;
61
62 IImageList * piml;
63 hr = SHGetImageList(SHIL_SMALL, IID_PPV_ARG(IImageList, &piml));
64 if (FAILED_UNEXPECTEDLY(hr))
65 return;
66
67 TreeView_SetImageList(m_hWnd, (HIMAGELIST)piml, TVSIL_NORMAL);
68
69 // Insert the root node
70 hRoot = InsertItem(0, pDesktop, pidl, pidl, FALSE);
71 if (!hRoot)
72 {
73 ERR("Failed to create root item\n");
74 return;
75 }
76
77 NodeInfo* pNodeInfo = GetNodeInfo(hRoot);
78
79 // Insert child nodes
80 InsertSubitems(hRoot, pNodeInfo);
81 TreeView_Expand(m_hWnd, hRoot, TVE_EXPAND);
82
83 // Navigate to current folder position
84 NavigateToCurrentFolder();
85
86 // Register shell notification
87 shcne.pidl = pidl;
88 shcne.fRecursive = TRUE;
89 shellRegID = SHChangeNotifyRegister(
90 m_hWnd,
91 SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt,
92 SHCNE_DISKEVENTS | SHCNE_RENAMEFOLDER | SHCNE_RMDIR | SHCNE_MKDIR,
93 WM_USER_SHELLEVENT,
94 1,
95 &shcne);
96 if (!shellRegID)
97 {
98 ERR("Something went wrong, error %08x\n", GetLastError());
99 }
100 // Register browser connection endpoint
101 hr = IUnknown_QueryService(pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &browserService));
102 if (FAILED_UNEXPECTEDLY(hr))
103 return;
104
105 hr = AtlAdvise(browserService, dynamic_cast<IDispatch*>(this), DIID_DWebBrowserEvents, &adviseCookie);
106 if (FAILED_UNEXPECTEDLY(hr))
107 return;
108
109 ILFree(pidl);
110 }
111
112 void CExplorerBand::DestroyExplorerBand()
113 {
114 HRESULT hr;
115 CComPtr <IWebBrowser2> browserService;
116
117 TRACE("Cleaning up explorer band ...\n");
118
119 hr = IUnknown_QueryService(pSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &browserService));
120 if (FAILED_UNEXPECTEDLY(hr))
121 return;
122
123 hr = AtlUnadvise(browserService, DIID_DWebBrowserEvents, adviseCookie);
124 /* Remove all items of the treeview */
125 RevokeDragDrop(m_hWnd);
126 TreeView_DeleteAllItems(m_hWnd);
127 pDesktop = NULL;
128 hRoot = NULL;
129 TRACE("Cleanup done !\n");
130 }
131
132 CExplorerBand::NodeInfo* CExplorerBand::GetNodeInfo(HTREEITEM hItem)
133 {
134 TVITEM tvItem;
135
136 tvItem.mask = TVIF_PARAM;
137 tvItem.hItem = hItem;
138
139 if (!TreeView_GetItem(m_hWnd, &tvItem))
140 return 0;
141
142 return reinterpret_cast<NodeInfo*>(tvItem.lParam);
143 }
144
145 HRESULT CExplorerBand::ExecuteCommand(CComPtr<IContextMenu>& menu, UINT nCmd)
146 {
147 CComPtr<IOleWindow> pBrowserOleWnd;
148 CMINVOKECOMMANDINFO cmi;
149 HWND browserWnd;
150 HRESULT hr;
151
152 hr = IUnknown_QueryService(pSite, SID_SShellBrowser, IID_PPV_ARG(IOleWindow, &pBrowserOleWnd));
153 if (FAILED_UNEXPECTEDLY(hr))
154 return hr;
155
156 hr = pBrowserOleWnd->GetWindow(&browserWnd);
157 if (FAILED_UNEXPECTEDLY(hr))
158 return hr;
159
160 ZeroMemory(&cmi, sizeof(cmi));
161 cmi.cbSize = sizeof(cmi);
162 cmi.lpVerb = MAKEINTRESOURCEA(nCmd);
163 cmi.hwnd = browserWnd;
164 if (GetKeyState(VK_SHIFT) & 0x8000)
165 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
166 if (GetKeyState(VK_CONTROL) & 0x8000)
167 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
168
169 return menu->InvokeCommand(&cmi);
170 }
171
172 HRESULT CExplorerBand::UpdateBrowser(LPITEMIDLIST pidlGoto)
173 {
174 CComPtr<IShellBrowser> pBrowserService;
175 HRESULT hr;
176
177 hr = IUnknown_QueryService(pSite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &pBrowserService));
178 if (FAILED_UNEXPECTEDLY(hr))
179 return hr;
180
181 hr = pBrowserService->BrowseObject(pidlGoto, SBSP_SAMEBROWSER | SBSP_ABSOLUTE);
182 if (FAILED_UNEXPECTEDLY(hr))
183 return hr;
184
185 return hr;
186 }
187
188 // *** notifications handling ***
189 BOOL CExplorerBand::OnTreeItemExpanding(LPNMTREEVIEW pnmtv)
190 {
191 NodeInfo *pNodeInfo;
192
193 if (pnmtv->action == TVE_COLLAPSE) {
194 if (pnmtv->itemNew.hItem == hRoot)
195 {
196 // Prenvent root from collapsing
197 pnmtv->itemNew.mask |= TVIF_STATE;
198 pnmtv->itemNew.stateMask |= TVIS_EXPANDED;
199 pnmtv->itemNew.state &= ~TVIS_EXPANDED;
200 pnmtv->action = TVE_EXPAND;
201 return TRUE;
202 }
203 }
204 if (pnmtv->action == TVE_EXPAND) {
205 // Grab our directory PIDL
206 pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
207 // We have it, let's try
208 if (pNodeInfo && !pNodeInfo->expanded)
209 if (!InsertSubitems(pnmtv->itemNew.hItem, pNodeInfo)) {
210 // remove subitem "+" since we failed to add subitems
211 TV_ITEM tvItem;
212
213 tvItem.mask = TVIF_CHILDREN;
214 tvItem.hItem = pnmtv->itemNew.hItem;
215 tvItem.cChildren = 0;
216
217 TreeView_SetItem(m_hWnd, &tvItem);
218 }
219 }
220 return FALSE;
221 }
222
223 void CExplorerBand::OnSelectionChanged(LPNMTREEVIEW pnmtv)
224 {
225 NodeInfo* pNodeInfo = GetNodeInfo(pnmtv->itemNew.hItem);
226
227 /* Prevents navigation if selection is initiated inside the band */
228 if (bNavigating)
229 return;
230
231 UpdateBrowser(pNodeInfo->absolutePidl);
232
233 SetFocus();
234 // Expand the node
235 //TreeView_Expand(m_hWnd, pnmtv->itemNew.hItem, TVE_EXPAND);
236 }
237
238
239 // *** ATL event handlers ***
240 LRESULT CExplorerBand::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
241 {
242 HTREEITEM item;
243 NodeInfo *info;
244 HMENU treeMenu;
245 WORD x;
246 WORD y;
247 CComPtr<IShellFolder> pFolder;
248 CComPtr<IContextMenu> contextMenu;
249 HRESULT hr;
250 UINT uCommand;
251 LPITEMIDLIST pidlChild;
252
253 treeMenu = NULL;
254 item = TreeView_GetSelection(m_hWnd);
255 bHandled = TRUE;
256 if (!item)
257 {
258 goto Cleanup;
259 }
260
261 x = LOWORD(lParam);
262 y = HIWORD(lParam);
263 if (x == -1 && y == -1)
264 {
265 // TODO: grab position of tree item and position it correctly
266 }
267
268 info = GetNodeInfo(item);
269 if (!info)
270 {
271 ERR("No node data, something has gone wrong !\n");
272 goto Cleanup;
273 }
274 hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pFolder),
275 (LPCITEMIDLIST*)&pidlChild);
276 if (!SUCCEEDED(hr))
277 {
278 ERR("Can't bind to folder!\n");
279 goto Cleanup;
280 }
281 hr = pFolder->GetUIObjectOf(m_hWnd, 1, (LPCITEMIDLIST*)&pidlChild, IID_IContextMenu,
282 NULL, reinterpret_cast<void**>(&contextMenu));
283 if (!SUCCEEDED(hr))
284 {
285 ERR("Can't get IContextMenu interface\n");
286 goto Cleanup;
287 }
288 treeMenu = CreatePopupMenu();
289 hr = contextMenu->QueryContextMenu(treeMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST,
290 CMF_EXPLORE);
291 if (!SUCCEEDED(hr))
292 {
293 WARN("Can't get context menu for item\n");
294 DestroyMenu(treeMenu);
295 goto Cleanup;
296 }
297 uCommand = TrackPopupMenu(treeMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
298 x, y, 0, m_hWnd, NULL);
299
300 ExecuteCommand(contextMenu, uCommand);
301 Cleanup:
302 if (treeMenu)
303 DestroyMenu(treeMenu);
304 bNavigating = TRUE;
305 TreeView_SelectItem(m_hWnd, oldSelected);
306 bNavigating = FALSE;
307 return TRUE;
308 }
309
310 LRESULT CExplorerBand::ContextMenuHack(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
311 {
312 bHandled = FALSE;
313 if (uMsg == WM_RBUTTONDOWN)
314 {
315 TVHITTESTINFO info;
316 info.pt.x = LOWORD(lParam);
317 info.pt.y = HIWORD(lParam);
318 info.flags = TVHT_ONITEM;
319 info.hItem = NULL;
320
321 // Save the current location
322 oldSelected = TreeView_GetSelection(m_hWnd);
323
324 // Move to the item selected by the treeview (don't change right pane)
325 TreeView_HitTest(m_hWnd, &info);
326 bNavigating = TRUE;
327 TreeView_SelectItem(m_hWnd, info.hItem);
328 bNavigating = FALSE;
329 }
330 return FALSE; /* let the wndproc process the message */
331 }
332 // *** Helper functions ***
333 HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, IShellFolder *psfParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort)
334 {
335 TV_INSERTSTRUCT tvInsert;
336 HTREEITEM htiCreated;
337
338 /* Get the attributes of the node */
339 SFGAOF attrs = SFGAO_STREAM | SFGAO_HASSUBFOLDER;
340 HRESULT hr = psfParent->GetAttributesOf(1, &pEltRelative, &attrs);
341 if (FAILED_UNEXPECTEDLY(hr))
342 return NULL;
343
344 /* Ignore streams */
345 if ((attrs & SFGAO_STREAM))
346 {
347 TRACE("Ignoring stream\n");
348 return NULL;
349 }
350
351 /* Get the name of the node */
352 WCHAR wszDisplayName[MAX_PATH];
353 if (!ILGetDisplayNameEx(psfParent, pEltRelative, wszDisplayName, ILGDN_INFOLDER))
354 {
355 ERR("Failed to get node name\n");
356 return NULL;
357 }
358
359 /* Get the icon of the node */
360 INT iIcon = SHMapPIDLToSystemImageListIndex(psfParent, pEltRelative, NULL);
361
362 NodeInfo* pChildInfo = new NodeInfo;
363 if (!pChildInfo)
364 {
365 ERR("Failed to allocate NodeInfo\n");
366 return FALSE;
367 }
368
369 // Store our node info
370 pChildInfo->absolutePidl = ILClone(pElt);
371 pChildInfo->relativePidl = ILClone(pEltRelative);
372 pChildInfo->expanded = FALSE;
373
374 // Set up our treeview template
375 tvInsert.hParent = hParent;
376 tvInsert.hInsertAfter = TVI_LAST;
377 tvInsert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
378 tvInsert.item.cchTextMax = MAX_PATH;
379 tvInsert.item.pszText = wszDisplayName;
380 tvInsert.item.iImage = tvInsert.item.iSelectedImage = iIcon;
381 tvInsert.item.cChildren = (attrs & SFGAO_HASSUBFOLDER) ? 1 : 0;
382 tvInsert.item.lParam = (LPARAM)pChildInfo;
383
384 htiCreated = TreeView_InsertItem(m_hWnd, &tvInsert);
385
386 return htiCreated;
387 }
388
389 /* This is the slow version of the above method */
390 HTREEITEM CExplorerBand::InsertItem(HTREEITEM hParent, LPITEMIDLIST pElt, LPITEMIDLIST pEltRelative, BOOL bSort)
391 {
392 CComPtr<IShellFolder> psfFolder;
393 HRESULT hr = SHBindToParent(pElt, IID_PPV_ARG(IShellFolder, &psfFolder), NULL);
394 if (FAILED_UNEXPECTEDLY(hr))
395 return NULL;
396
397 return InsertItem(hParent, psfFolder, pElt, pEltRelative, bSort);
398 }
399
400 BOOL CExplorerBand::InsertSubitems(HTREEITEM hItem, NodeInfo *pNodeInfo)
401 {
402 CComPtr<IEnumIDList> pEnumIDList;
403 LPITEMIDLIST pidlSub;
404 LPITEMIDLIST entry;
405 SHCONTF EnumFlags;
406 HRESULT hr;
407 ULONG fetched;
408 ULONG uItemCount;
409 CComPtr<IShellFolder> pFolder;
410
411 entry = pNodeInfo->absolutePidl;
412 fetched = 1;
413 uItemCount = 0;
414 EnumFlags = SHCONTF_FOLDERS;
415
416 hr = SHGetFolderLocation(m_hWnd, CSIDL_DESKTOP, NULL, 0, &pidlSub);
417 if (!SUCCEEDED(hr))
418 {
419 ERR("Can't get desktop PIDL !\n");
420 return FALSE;
421 }
422
423 if (!pDesktop->CompareIDs(NULL, pidlSub, entry))
424 {
425 // We are the desktop, so use pDesktop as pFolder
426 pFolder = pDesktop;
427 }
428 else
429 {
430 // Get an IShellFolder of our pidl
431 hr = pDesktop->BindToObject(entry, NULL, IID_PPV_ARG(IShellFolder, &pFolder));
432 if (!SUCCEEDED(hr))
433 {
434 ILFree(pidlSub);
435 ERR("Can't bind folder to desktop !\n");
436 return FALSE;
437 }
438 }
439 ILFree(pidlSub);
440
441 // TODO: handle hidden folders according to settings !
442 EnumFlags |= SHCONTF_INCLUDEHIDDEN;
443
444 // Enum through objects
445 hr = pFolder->EnumObjects(NULL,EnumFlags,&pEnumIDList);
446
447 // avoid broken IShellFolder implementations that return null pointer with success
448 if (!SUCCEEDED(hr) || !pEnumIDList)
449 {
450 ERR("Can't enum the folder !\n");
451 return FALSE;
452 }
453
454 /* Don't redraw while we add stuff into the tree */
455 SendMessage(WM_SETREDRAW, FALSE, 0);
456 while(SUCCEEDED(pEnumIDList->Next(1, &pidlSub, &fetched)) && pidlSub && fetched)
457 {
458 LPITEMIDLIST pidlSubComplete;
459 pidlSubComplete = ILCombine(entry, pidlSub);
460
461 if (InsertItem(hItem, pFolder, pidlSubComplete, pidlSub, FALSE))
462 uItemCount++;
463 ILFree(pidlSubComplete);
464 ILFree(pidlSub);
465 }
466 pNodeInfo->expanded = TRUE;
467
468 /* Now we can redraw */
469 SendMessage(WM_SETREDRAW, TRUE, 0);
470
471 return (uItemCount > 0) ? TRUE : FALSE;
472 }
473
474 /**
475 * Navigate to a given PIDL in the treeview, and return matching tree item handle
476 * - dest: The absolute PIDL we should navigate in the treeview
477 * - item: Handle of the tree item matching the PIDL
478 * - bExpand: expand collapsed nodes in order to find the right element
479 * - bInsert: insert the element at the right place if we don't find it
480 * - bSelect: select the item after we found it
481 */
482 BOOL CExplorerBand::NavigateToPIDL(LPITEMIDLIST dest, HTREEITEM *item, BOOL bExpand, BOOL bInsert,
483 BOOL bSelect)
484 {
485 HTREEITEM current;
486 HTREEITEM tmp;
487 HTREEITEM parent;
488 BOOL found;
489 NodeInfo *nodeData;
490 LPITEMIDLIST relativeChild;
491 TVITEM tvItem;
492
493 if (!item)
494 return FALSE;
495
496 found = FALSE;
497 current = hRoot;
498 parent = NULL;
499 while(!found)
500 {
501 nodeData = GetNodeInfo(current);
502 if (!nodeData)
503 {
504 ERR("Something has gone wrong, no data associated to node !\n");
505 *item = NULL;
506 return FALSE;
507 }
508 // If we found our node, give it back
509 if (!pDesktop->CompareIDs(0, nodeData->absolutePidl, dest))
510 {
511 if (bSelect)
512 TreeView_SelectItem(m_hWnd, current);
513 *item = current;
514 return TRUE;
515 }
516
517 // Check if we are a parent of the requested item
518 relativeChild = ILFindChild(nodeData->absolutePidl, dest);
519 if (relativeChild != 0)
520 {
521 // Notify treeview we have children
522 tvItem.mask = TVIF_CHILDREN;
523 tvItem.hItem = current;
524 tvItem.cChildren = 1;
525 TreeView_SetItem(m_hWnd, &tvItem);
526
527 // If we can expand and the node isn't expanded yet, do it
528 if (bExpand)
529 {
530 if (!nodeData->expanded)
531 InsertSubitems(current, nodeData);
532 TreeView_Expand(m_hWnd, current, TVE_EXPAND);
533 }
534
535 // Try to get a child
536 tmp = TreeView_GetChild(m_hWnd, current);
537 if (tmp)
538 {
539 // We have a child, let's continue with it
540 parent = current;
541 current = tmp;
542 continue;
543 }
544
545 if (bInsert && nodeData->expanded)
546 {
547 // Happens when we have to create a subchild inside a child
548 current = InsertItem(current, dest, relativeChild, TRUE);
549 }
550 // We end up here, without any children, so we found nothing
551 // Tell the parent node it has children
552 ZeroMemory(&tvItem, sizeof(tvItem));
553 *item = NULL;
554 return FALSE;
555 }
556
557 // Find sibling
558 tmp = TreeView_GetNextSibling(m_hWnd, current);
559 if (tmp)
560 {
561 current = tmp;
562 continue;
563 }
564 if (bInsert)
565 {
566 current = InsertItem(parent, dest, ILFindLastID(dest), TRUE);
567 *item = current;
568 return TRUE;
569 }
570 *item = NULL;
571 return FALSE;
572 }
573 return FALSE;
574 }
575
576 BOOL CExplorerBand::NavigateToCurrentFolder()
577 {
578 LPITEMIDLIST explorerPidl;
579 CComPtr<IBrowserService> pBrowserService;
580 HRESULT hr;
581 HTREEITEM dummy;
582 BOOL result;
583 explorerPidl = NULL;
584
585 hr = IUnknown_QueryService(pSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pBrowserService));
586 if (!SUCCEEDED(hr))
587 {
588 ERR("Can't get IBrowserService !\n");
589 return FALSE;
590 }
591
592 hr = pBrowserService->GetPidl(&explorerPidl);
593 if (!SUCCEEDED(hr) || !explorerPidl)
594 {
595 ERR("Unable to get browser PIDL !\n");
596 return FALSE;
597 }
598 bNavigating = TRUE;
599 /* find PIDL into our explorer */
600 result = NavigateToPIDL(explorerPidl, &dummy, TRUE, FALSE, TRUE);
601 bNavigating = FALSE;
602 return result;
603 }
604
605 // *** IOleWindow methods ***
606 HRESULT STDMETHODCALLTYPE CExplorerBand::GetWindow(HWND *lphwnd)
607 {
608 if (!lphwnd)
609 return E_INVALIDARG;
610 *lphwnd = m_hWnd;
611 return S_OK;
612 }
613
614 HRESULT STDMETHODCALLTYPE CExplorerBand::ContextSensitiveHelp(BOOL fEnterMode)
615 {
616 UNIMPLEMENTED;
617 return E_NOTIMPL;
618 }
619
620
621 // *** IDockingWindow methods ***
622 HRESULT STDMETHODCALLTYPE CExplorerBand::CloseDW(DWORD dwReserved)
623 {
624 // We do nothing, we don't have anything to save yet
625 TRACE("CloseDW called\n");
626 return S_OK;
627 }
628
629 HRESULT STDMETHODCALLTYPE CExplorerBand::ResizeBorderDW(const RECT *prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
630 {
631 /* Must return E_NOTIMPL according to MSDN */
632 return E_NOTIMPL;
633 }
634
635 HRESULT STDMETHODCALLTYPE CExplorerBand::ShowDW(BOOL fShow)
636 {
637 fVisible = fShow;
638 ShowWindow(fShow);
639 return S_OK;
640 }
641
642
643 // *** IDeskBand methods ***
644 HRESULT STDMETHODCALLTYPE CExplorerBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi)
645 {
646 if (!pdbi)
647 {
648 return E_INVALIDARG;
649 }
650 this->dwBandID = dwBandID;
651
652 if (pdbi->dwMask & DBIM_MINSIZE)
653 {
654 pdbi->ptMinSize.x = 200;
655 pdbi->ptMinSize.y = 30;
656 }
657
658 if (pdbi->dwMask & DBIM_MAXSIZE)
659 {
660 pdbi->ptMaxSize.y = -1;
661 }
662
663 if (pdbi->dwMask & DBIM_INTEGRAL)
664 {
665 pdbi->ptIntegral.y = 1;
666 }
667
668 if (pdbi->dwMask & DBIM_ACTUAL)
669 {
670 pdbi->ptActual.x = 200;
671 pdbi->ptActual.y = 30;
672 }
673
674 if (pdbi->dwMask & DBIM_TITLE)
675 {
676 if (!LoadStringW(_AtlBaseModule.GetResourceInstance(), IDS_FOLDERSLABEL, pdbi->wszTitle, _countof(pdbi->wszTitle)))
677 return HRESULT_FROM_WIN32(GetLastError());
678 }
679
680 if (pdbi->dwMask & DBIM_MODEFLAGS)
681 {
682 pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT;
683 }
684
685 if (pdbi->dwMask & DBIM_BKCOLOR)
686 {
687 pdbi->dwMask &= ~DBIM_BKCOLOR;
688 }
689 return S_OK;
690 }
691
692
693 // *** IObjectWithSite methods ***
694 HRESULT STDMETHODCALLTYPE CExplorerBand::SetSite(IUnknown *pUnkSite)
695 {
696 HRESULT hr;
697 HWND parentWnd;
698
699 if (pUnkSite == pSite)
700 return S_OK;
701
702 TRACE("SetSite called \n");
703 if (!pUnkSite)
704 {
705 DestroyExplorerBand();
706 DestroyWindow();
707 m_hWnd = NULL;
708 }
709
710 if (pUnkSite != pSite)
711 {
712 pSite = NULL;
713 }
714
715 if(!pUnkSite)
716 return S_OK;
717
718 hr = IUnknown_GetWindow(pUnkSite, &parentWnd);
719 if (!SUCCEEDED(hr))
720 {
721 ERR("Could not get parent's window ! Status: %08lx\n", hr);
722 return E_INVALIDARG;
723 }
724
725 pSite = pUnkSite;
726
727 if (m_hWnd)
728 {
729 // Change its parent
730 SetParent(parentWnd);
731 }
732 else
733 {
734 HWND wnd = CreateWindow(WC_TREEVIEW, NULL,
735 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_EDITLABELS /* | TVS_SINGLEEXPAND*/ , // remove TVS_SINGLEEXPAND for now since it has strange behaviour
736 0, 0, 0, 0, parentWnd, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
737
738 // Subclass the window
739 SubclassWindow(wnd);
740
741 // Initialize our treeview now
742 InitializeExplorerBand();
743 RegisterDragDrop(m_hWnd, dynamic_cast<IDropTarget*>(this));
744 }
745 return S_OK;
746 }
747
748 HRESULT STDMETHODCALLTYPE CExplorerBand::GetSite(REFIID riid, void **ppvSite)
749 {
750 if (!ppvSite)
751 return E_POINTER;
752 *ppvSite = pSite;
753 return S_OK;
754 }
755
756
757 // *** IOleCommandTarget methods ***
758 HRESULT STDMETHODCALLTYPE CExplorerBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
759 {
760 UNIMPLEMENTED;
761 return E_NOTIMPL;
762 }
763
764 HRESULT STDMETHODCALLTYPE CExplorerBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
765 {
766 UNIMPLEMENTED;
767 return E_NOTIMPL;
768 }
769
770
771 // *** IServiceProvider methods ***
772 HRESULT STDMETHODCALLTYPE CExplorerBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
773 {
774 UNIMPLEMENTED;
775 return E_NOTIMPL;
776 }
777
778
779 // *** IInputObject methods ***
780 HRESULT STDMETHODCALLTYPE CExplorerBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
781 {
782 if (fActivate)
783 {
784 //SetFocus();
785 SetActiveWindow();
786 }
787 // TODO: handle message
788 if(lpMsg)
789 {
790 TranslateMessage(lpMsg);
791 DispatchMessage(lpMsg);
792 }
793 return S_OK;
794 }
795
796 HRESULT STDMETHODCALLTYPE CExplorerBand::HasFocusIO()
797 {
798 return bFocused ? S_OK : S_FALSE;
799 }
800
801 HRESULT STDMETHODCALLTYPE CExplorerBand::TranslateAcceleratorIO(LPMSG lpMsg)
802 {
803 if (lpMsg->hwnd == m_hWnd)
804 {
805 TranslateMessage(lpMsg);
806 DispatchMessage(lpMsg);
807 return S_OK;
808 }
809
810 return S_FALSE;
811 }
812
813 // *** IPersist methods ***
814 HRESULT STDMETHODCALLTYPE CExplorerBand::GetClassID(CLSID *pClassID)
815 {
816 if (!pClassID)
817 return E_POINTER;
818 memcpy(pClassID, &CLSID_ExplorerBand, sizeof(CLSID));
819 return S_OK;
820 }
821
822
823 // *** IPersistStream methods ***
824 HRESULT STDMETHODCALLTYPE CExplorerBand::IsDirty()
825 {
826 UNIMPLEMENTED;
827 return E_NOTIMPL;
828 }
829
830 HRESULT STDMETHODCALLTYPE CExplorerBand::Load(IStream *pStm)
831 {
832 UNIMPLEMENTED;
833 return E_NOTIMPL;
834 }
835
836 HRESULT STDMETHODCALLTYPE CExplorerBand::Save(IStream *pStm, BOOL fClearDirty)
837 {
838 UNIMPLEMENTED;
839 return E_NOTIMPL;
840 }
841
842 HRESULT STDMETHODCALLTYPE CExplorerBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
843 {
844 UNIMPLEMENTED;
845 return E_NOTIMPL;
846 }
847
848
849 // *** IWinEventHandler methods ***
850 HRESULT STDMETHODCALLTYPE CExplorerBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
851 {
852 BOOL bHandled;
853 if (uMsg == WM_NOTIFY)
854 {
855 NMHDR *pNotifyHeader = (NMHDR*)lParam;
856 switch (pNotifyHeader->code)
857 {
858 case TVN_ITEMEXPANDING:
859 *theResult = OnTreeItemExpanding((LPNMTREEVIEW)lParam);
860 break;
861 case TVN_SELCHANGED:
862 OnSelectionChanged((LPNMTREEVIEW)lParam);
863 break;
864 case NM_RCLICK:
865 OnContextMenu(WM_CONTEXTMENU, (WPARAM)m_hWnd, GetMessagePos(), bHandled);
866 *theResult = 1;
867 break;
868 case TVN_BEGINLABELEDITW:
869 {
870 // TODO: put this in a function ? (mostly copypasta from CDefView)
871 DWORD dwAttr = SFGAO_CANRENAME;
872 LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
873 CComPtr<IShellFolder> pParent;
874 LPCITEMIDLIST pChild;
875 HRESULT hr;
876
877 *theResult = 1;
878 NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
879 if (!info)
880 return E_FAIL;
881 hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent), &pChild);
882 if (!SUCCEEDED(hr) || !pParent.p)
883 return E_FAIL;
884
885 hr = pParent->GetAttributesOf(1, &pChild, &dwAttr);
886 if (SUCCEEDED(hr) && (dwAttr & SFGAO_CANRENAME))
887 *theResult = 0;
888 return S_OK;
889 }
890 case TVN_ENDLABELEDITW:
891 {
892 LPNMTVDISPINFO dispInfo = (LPNMTVDISPINFO)lParam;
893 NodeInfo *info = GetNodeInfo(dispInfo->item.hItem);
894 HRESULT hr;
895
896 *theResult = 0;
897 if (dispInfo->item.pszText)
898 {
899 LPITEMIDLIST pidlNew;
900 CComPtr<IShellFolder> pParent;
901 LPCITEMIDLIST pidlChild;
902
903 hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent), &pidlChild);
904 if (!SUCCEEDED(hr) || !pParent.p)
905 return E_FAIL;
906
907 hr = pParent->SetNameOf(0, pidlChild, dispInfo->item.pszText, SHGDN_INFOLDER, &pidlNew);
908 if(SUCCEEDED(hr) && pidlNew)
909 {
910 CComPtr<IPersistFolder2> pPersist;
911 LPITEMIDLIST pidlParent, pidlNewAbs;
912
913 hr = pParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pPersist));
914 if(!SUCCEEDED(hr))
915 return E_FAIL;
916
917 hr = pPersist->GetCurFolder(&pidlParent);
918 if(!SUCCEEDED(hr))
919 return E_FAIL;
920 pidlNewAbs = ILCombine(pidlParent, pidlNew);
921
922 // Navigate to our new location
923 UpdateBrowser(pidlNewAbs);
924
925 ILFree(pidlNewAbs);
926 ILFree(pidlNew);
927 *theResult = 1;
928 }
929 return S_OK;
930 }
931 }
932 default:
933 break;
934 }
935 }
936 return S_OK;
937 }
938
939 HRESULT STDMETHODCALLTYPE CExplorerBand::IsWindowOwner(HWND hWnd)
940 {
941 return (hWnd == m_hWnd) ? S_OK : S_FALSE;
942 }
943
944 // *** IBandNavigate methods ***
945 HRESULT STDMETHODCALLTYPE CExplorerBand::Select(long paramC)
946 {
947 UNIMPLEMENTED;
948 return E_NOTIMPL;
949 }
950
951 // *** INamespaceProxy ***
952 HRESULT STDMETHODCALLTYPE CExplorerBand::GetNavigateTarget(long paramC, long param10, long param14)
953 {
954 UNIMPLEMENTED;
955 return E_NOTIMPL;
956 }
957
958 HRESULT STDMETHODCALLTYPE CExplorerBand::Invoke(long paramC)
959 {
960 UNIMPLEMENTED;
961 return E_NOTIMPL;
962 }
963
964 HRESULT STDMETHODCALLTYPE CExplorerBand::OnSelectionChanged(long paramC)
965 {
966 UNIMPLEMENTED;
967 return E_NOTIMPL;
968 }
969
970 HRESULT STDMETHODCALLTYPE CExplorerBand::RefreshFlags(long paramC, long param10, long param14)
971 {
972 UNIMPLEMENTED;
973 return E_NOTIMPL;
974 }
975
976 HRESULT STDMETHODCALLTYPE CExplorerBand::CacheItem(long paramC)
977 {
978 UNIMPLEMENTED;
979 return E_NOTIMPL;
980 }
981
982 // *** IDispatch methods ***
983 HRESULT STDMETHODCALLTYPE CExplorerBand::GetTypeInfoCount(UINT *pctinfo)
984 {
985 UNIMPLEMENTED;
986 return E_NOTIMPL;
987 }
988
989 HRESULT STDMETHODCALLTYPE CExplorerBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
990 {
991 UNIMPLEMENTED;
992 return E_NOTIMPL;
993 }
994
995 HRESULT STDMETHODCALLTYPE CExplorerBand::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
996 {
997 UNIMPLEMENTED;
998 return E_NOTIMPL;
999 }
1000
1001 HRESULT STDMETHODCALLTYPE CExplorerBand::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1002 {
1003 switch (dispIdMember)
1004 {
1005 case DISPID_DOWNLOADCOMPLETE:
1006 case DISPID_NAVIGATECOMPLETE2:
1007 TRACE("DISPID_NAVIGATECOMPLETE2 received\n");
1008 NavigateToCurrentFolder();
1009 return S_OK;
1010 }
1011 TRACE("Unknown dispid requested: %08x\n", dispIdMember);
1012 return E_INVALIDARG;
1013 }
1014
1015 // *** IDropTarget methods ***
1016 HRESULT STDMETHODCALLTYPE CExplorerBand::DragEnter(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
1017 {
1018 UNIMPLEMENTED;
1019 return E_NOTIMPL;
1020 }
1021
1022 HRESULT STDMETHODCALLTYPE CExplorerBand::DragOver(DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
1023 {
1024 UNIMPLEMENTED;
1025 return E_NOTIMPL;
1026 }
1027
1028 HRESULT STDMETHODCALLTYPE CExplorerBand::DragLeave()
1029 {
1030 UNIMPLEMENTED;
1031 return E_NOTIMPL;
1032 }
1033
1034 HRESULT STDMETHODCALLTYPE CExplorerBand::Drop(IDataObject *pObj, DWORD glfKeyState, POINTL pt, DWORD *pdwEffect)
1035 {
1036 UNIMPLEMENTED;
1037 return E_NOTIMPL;
1038 }
1039
1040 // *** IDropSource methods ***
1041 HRESULT STDMETHODCALLTYPE CExplorerBand::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
1042 {
1043 UNIMPLEMENTED;
1044 return E_NOTIMPL;
1045 }
1046
1047 HRESULT STDMETHODCALLTYPE CExplorerBand::GiveFeedback(DWORD dwEffect)
1048 {
1049 UNIMPLEMENTED;
1050 return E_NOTIMPL;
1051 }