2 * Copyright 2003 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Martin Fuchs, 23.07.2003
29 #include "../utility/utility.h"
31 #include "../explorer.h"
32 #include "../globals.h"
34 #include "../explorer_intres.h"
37 static LPARAM
TreeView_GetItemData(HWND hwndTreeView
, HTREEITEM hItem
)
41 tvItem
.mask
= TVIF_PARAM
;
44 if (!TreeView_GetItem(hwndTreeView
, &tvItem
))
51 ShellBrowserChild::ShellBrowserChild(HWND hwnd
, const ShellChildWndInfo
& info
)
61 ShellBrowserChild::~ShellBrowserChild()
64 _pShellView
->Release();
67 _pDropTarget
->Release();
73 LRESULT
ShellBrowserChild::Init(LPCREATESTRUCT pcs
)
78 _hWndFrame
= GetParent(pcs
->hwndParent
);
80 ClientRect
rect(_hwnd
);
84 _himlSmall
= (HIMAGELIST
)SHGetFileInfo(TEXT("C:\\"), 0, &sfi
, sizeof(SHFILEINFO
), SHGFI_SYSICONINDEX
|SHGFI_SMALLICON
);
85 // _himlLarge = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX|SHGFI_LARGEICON);
88 // create explorer treeview
89 if (_create_info
._mode_explore
)
90 _left_hwnd
= CreateWindowEx(0, WC_TREEVIEW
, NULL
,
91 WS_CHILD
|WS_TABSTOP
|WS_VISIBLE
|WS_CHILD
|TVS_HASLINES
|TVS_LINESATROOT
|TVS_HASBUTTONS
|TVS_NOTOOLTIPS
|TVS_SHOWSELALWAYS
,
92 0, rect
.top
, _split_pos
-SPLIT_WIDTH
/2, rect
.bottom
-rect
.top
,
93 _hwnd
, (HMENU
)IDC_FILETREE
, g_Globals
._hInstance
, 0);
100 UpdateFolderView(_create_info
._shell_path
.get_folder());
106 void ShellBrowserChild::InitializeTree()
108 TreeView_SetImageList(_left_hwnd
, _himlSmall
, TVSIL_NORMAL
);
109 TreeView_SetScrollTime(_left_hwnd
, 100);
111 const String
& root_name
= Desktop().get_name(_create_info
._root_shell_path
);
113 _root
._drive_type
= DRIVE_UNKNOWN
;
114 lstrcpy(_root
._volname
, root_name
); // most of the time "Desktop"
116 lstrcpy(_root
._fs
, TEXT("Shell"));
118 //@@ _root._entry->read_tree(shell_info._root_shell_path.get_folder(), info._shell_path, SORT_NAME/*_sortOrder*/);
121 we should call read_tree() here to iterate through the hierarchy and open all folders from shell_info._root_shell_path to shell_info._shell_path
122 -> see FileChildWindow::FileChildWindow()
124 _root
._entry
= new ShellDirectory(Desktop(), _create_info
._root_shell_path
, _hwnd
);
125 _root
._entry
->read_directory();
127 /* already filled by ShellDirectory constructor
128 lstrcpy(_root._entry->_data.cFileName, TEXT("Desktop")); */
133 tvItem
.mask
= TVIF_PARAM
| TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_CHILDREN
;
134 tvItem
.lParam
= (LPARAM
)_root
._entry
;
135 tvItem
.pszText
= LPSTR_TEXTCALLBACK
;
136 tvItem
.iImage
= tvItem
.iSelectedImage
= I_IMAGECALLBACK
;
137 tvItem
.cChildren
= 1;
139 TV_INSERTSTRUCT tvInsert
;
141 tvInsert
.hParent
= 0;
142 tvInsert
.hInsertAfter
= TVI_LAST
;
143 tvInsert
.item
= tvItem
;
145 HTREEITEM hItem
= TreeView_InsertItem(_left_hwnd
, &tvInsert
);
146 TreeView_SelectItem(_left_hwnd
, hItem
);
147 TreeView_Expand(_left_hwnd
, hItem
, TVE_EXPAND
);
151 bool ShellBrowserChild::InitDragDrop()
153 _pDropTarget
= new TreeDropTarget(_left_hwnd
);
158 _pDropTarget
->AddRef();
160 if (FAILED(RegisterDragDrop(_left_hwnd
, _pDropTarget
))) {//calls addref
161 _pDropTarget
->Release(); // free TreeDropTarget
166 _pDropTarget
->Release();
170 ftetc
.dwAspect
= DVASPECT_CONTENT
;
172 ftetc
.tymed
= TYMED_HGLOBAL
;
173 ftetc
.cfFormat
= CF_HDROP
;
175 _pDropTarget
->AddSuportedFormat(ftetc
);
181 void ShellBrowserChild::OnTreeItemRClick(int idCtrl
, LPNMHDR pnmh
)
185 GetCursorPos(&tvhti
.pt
);
186 ScreenToClient(_left_hwnd
, &tvhti
.pt
);
188 tvhti
.flags
= LVHT_NOWHERE
;
189 TreeView_HitTest(_left_hwnd
, &tvhti
);
191 if (TVHT_ONITEM
& tvhti
.flags
) {
192 ClientToScreen(_left_hwnd
, &tvhti
.pt
);
193 Tree_DoItemMenu(_left_hwnd
, tvhti
.hItem
, &tvhti
.pt
);
197 void ShellBrowserChild::Tree_DoItemMenu(HWND hwndTreeView
, HTREEITEM hItem
, LPPOINT pptScreen
)
199 LPARAM itemData
= TreeView_GetItemData(hwndTreeView
, hItem
);
202 HWND hwndParent
= ::GetParent(hwndTreeView
);
203 Entry
* entry
= (Entry
*)itemData
;
205 IShellFolder
* shell_folder
;
208 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
209 dir
= static_cast<ShellDirectory
*>(entry
);
210 shell_folder
= dir
->_folder
;
212 dir
= static_cast<ShellDirectory
*>(entry
->_up
);
213 shell_folder
= dir
? dir
->_folder
: Desktop();
216 shell_folder
->AddRef();
219 LPCITEMIDLIST pidl
= static_cast<ShellEntry
*>(entry
)->_pidl
;
223 HRESULT hr
= shell_folder
->GetUIObjectOf(hwndParent
, 1, &pidl
, IID_IContextMenu
, NULL
, (LPVOID
*)&pcm
);
224 // HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm);
227 HMENU hPopup
= CreatePopupMenu();
230 hr
= pcm
->QueryContextMenu(hPopup
, 0, 1, 0x7fff, CMF_NORMAL
|CMF_EXPLORE
);
235 pcm
->QueryInterface(IID_IContextMenu2
, (LPVOID
*)&pcm2
);
237 UINT idCmd
= TrackPopupMenu(hPopup
,
238 TPM_LEFTALIGN
| TPM_RETURNCMD
| TPM_RIGHTBUTTON
,
251 CMINVOKECOMMANDINFO cmi
;
252 cmi
.cbSize
= sizeof(CMINVOKECOMMANDINFO
);
254 cmi
.hwnd
= hwndParent
;
255 cmi
.lpVerb
= (LPCSTR
)(INT_PTR
)(idCmd
- 1);
256 cmi
.lpParameters
= NULL
;
257 cmi
.lpDirectory
= NULL
;
258 cmi
.nShow
= SW_SHOWNORMAL
;
261 hr
= pcm
->InvokeCommand(&cmi
);
269 shell_folder
->Release();
274 void ShellBrowserChild::OnTreeGetDispInfo(int idCtrl
, LPNMHDR pnmh
)
276 LPNMTVDISPINFO lpdi
= (LPNMTVDISPINFO
)pnmh
;
277 ShellEntry
* entry
= (ShellEntry
*)lpdi
->item
.lParam
;
279 if (lpdi
->item
.mask
& TVIF_TEXT
) {
280 /* if (SHGetFileInfo((LPCTSTR)&*entry->_pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_DISPLAYNAME))
281 lstrcpy(lpdi->item.pszText, sfi.szDisplayName); */
282 lstrcpy(lpdi
->item
.pszText
, entry
->_data
.cFileName
);
285 if (lpdi
->item
.mask
& (TVIF_IMAGE
|TVIF_SELECTEDIMAGE
)) {
286 LPITEMIDLIST pidl
= entry
->create_absolute_pidl(_hwnd
);
289 if (lpdi
->item
.mask
& TVIF_IMAGE
) {
290 if (SHGetFileInfo((LPCTSTR
)pidl
, 0, &sfi
, sizeof(sfi
), SHGFI_PIDL
|SHGFI_SYSICONINDEX
|SHGFI_SMALLICON
|SHGFI_LINKOVERLAY
))
291 lpdi
->item
.iImage
= sfi
.iIcon
;
294 if (lpdi
->item
.mask
& TVIF_SELECTEDIMAGE
) {
295 if (SHGetFileInfo((LPCTSTR
)pidl
, 0, &sfi
, sizeof(sfi
), SHGFI_PIDL
|SHGFI_SYSICONINDEX
|SHGFI_SMALLICON
|SHGFI_OPENICON
))
296 lpdi
->item
.iSelectedImage
= sfi
.iIcon
;
299 if (pidl
!= &*entry
->_pidl
)
300 ShellMalloc()->Free(pidl
);
304 void ShellBrowserChild::OnTreeItemExpanding(int idCtrl
, LPNMTREEVIEW pnmtv
)
306 if (pnmtv
->action
== TVE_COLLAPSE
)
307 TreeView_Expand(_left_hwnd
, pnmtv
->itemNew
.hItem
, TVE_COLLAPSE
|TVE_COLLAPSERESET
);
308 else if (pnmtv
->action
== TVE_EXPAND
) {
309 ShellDirectory
* entry
= (ShellDirectory
*)TreeView_GetItemData(_left_hwnd
, pnmtv
->itemNew
.hItem
);
312 InsertSubitems(pnmtv
->itemNew
.hItem
, entry
, entry
->_folder
);
316 void ShellBrowserChild::InsertSubitems(HTREEITEM hParentItem
, Entry
* entry
, IShellFolder
* pParentFolder
)
320 SendMessage(_left_hwnd
, WM_SETREDRAW
, FALSE
, 0);
325 TV_INSERTSTRUCT tvInsert
;
327 for(entry
=entry
->_down
; entry
; entry
=entry
->_next
) {
329 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
332 ZeroMemory(&tvItem
, sizeof(tvItem
));
334 tvItem
.mask
= TVIF_PARAM
| TVIF_TEXT
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
| TVIF_CHILDREN
;
335 tvItem
.pszText
= LPSTR_TEXTCALLBACK
;
336 tvItem
.iImage
= tvItem
.iSelectedImage
= I_IMAGECALLBACK
;
337 tvItem
.lParam
= (LPARAM
)entry
;
338 tvItem
.cChildren
= entry
->_shell_attribs
& SFGAO_HASSUBFOLDER
? 1: 0;
340 if (entry
->_shell_attribs
& SFGAO_SHARE
) {
341 tvItem
.mask
|= TVIF_STATE
;
342 tvItem
.stateMask
|= TVIS_OVERLAYMASK
;
343 tvItem
.state
|= INDEXTOOVERLAYMASK(1);
346 tvInsert
.item
= tvItem
;
347 tvInsert
.hInsertAfter
= TVI_LAST
;
348 tvInsert
.hParent
= hParentItem
;
350 TreeView_InsertItem(_left_hwnd
, &tvInsert
);
354 SendMessage(_left_hwnd
, WM_SETREDRAW
, TRUE
, 0);
357 void ShellBrowserChild::OnTreeItemSelected(int idCtrl
, LPNMTREEVIEW pnmtv
)
359 ShellEntry
* entry
= (ShellEntry
*)pnmtv
->itemNew
.lParam
;
361 _last_sel
= pnmtv
->itemNew
.hItem
;
363 IShellFolder
* folder
;
365 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
366 folder
= static_cast<ShellDirectory
*>(entry
)->_folder
;
368 folder
= entry
->get_parent_folder();
375 UpdateFolderView(folder
);
378 void ShellBrowserChild::UpdateFolderView(IShellFolder
* folder
)
381 IShellView
* pLastShellView
= _pShellView
;
384 pLastShellView
->GetCurrentInfo(&fs
);
386 fs
.ViewMode
= _left_hwnd
? FVM_DETAILS
: FVM_ICON
;
387 fs
.fFlags
= FWF_NOCLIENTEDGE
;
390 HRESULT hr
= folder
->CreateViewObject(_hwnd
, IID_IShellView
, (void**)&_pShellView
);
397 RECT rect
= {CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
};
398 hr
= _pShellView
->CreateViewWindow(pLastShellView
, &fs
, static_cast<IShellBrowser
*>(this), &rect
, &_right_hwnd
/*&m_hWndListView*/);
400 if (pLastShellView
) {
401 pLastShellView
->GetCurrentInfo(&fs
);
402 pLastShellView
->UIActivate(SVUIA_DEACTIVATE
);
403 pLastShellView
->DestroyViewWindow();
404 pLastShellView
->Release();
406 ClientRect
clnt(_hwnd
);
407 resize_children(clnt
.right
, clnt
.bottom
);
410 _pShellView
->UIActivate(SVUIA_ACTIVATE_NOFOCUS
);
414 LRESULT
ShellBrowserChild::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
417 case WM_GETISHELLBROWSER
: // for Registry Explorer Plugin
418 return (LRESULT
)static_cast<IShellBrowser
*>(this);
421 return super::WndProc(nmsg
, wparam
, lparam
);
427 int ShellBrowserChild::Notify(int id
, NMHDR
* pnmh
)
430 case TVN_GETDISPINFO
: OnTreeGetDispInfo(id
, pnmh
); break;
431 case TVN_ITEMEXPANDING
: OnTreeItemExpanding(id
, (LPNMTREEVIEW
)pnmh
); break;
432 case TVN_SELCHANGED
: OnTreeItemSelected(id
, (LPNMTREEVIEW
)pnmh
); break;
433 case NM_RCLICK
: OnTreeItemRClick(id
, pnmh
); break;
434 default: return super::Notify(id
, pnmh
);
441 // process default command: look for folders and traverse into them
442 HRESULT
ShellBrowserChild::OnDefaultCommand(IShellView
* ppshv
)
444 static UINT CF_IDLIST
= RegisterClipboardFormat(CFSTR_SHELLIDLIST
);
446 HRESULT ret
= E_NOTIMPL
;
448 IDataObject
* selection
;
449 HRESULT hr
= ppshv
->GetItemObject(SVGIO_SELECTION
, IID_IDataObject
, (void**)&selection
);
455 fetc
.cfFormat
= CF_IDLIST
;
457 fetc
.dwAspect
= DVASPECT_CONTENT
;
459 fetc
.tymed
= TYMED_HGLOBAL
;
461 hr
= selection
->QueryGetData(&fetc
);
466 STGMEDIUM stgm
= {sizeof(STGMEDIUM
), {0}, 0};
468 hr
= selection
->GetData(&fetc
, &stgm
);
473 DWORD pData
= (DWORD
)GlobalLock(stgm
.hGlobal
);
474 CIDA
* pIDList
= (CIDA
*)pData
;
476 if (pIDList
->cidl
>= 1) {
477 //UINT folderOffset = pIDList->aoffset[0];
478 //LPITEMIDLIST folder = (LPITEMIDLIST)(pData+folderOffset);
480 UINT firstOffset
= pIDList
->aoffset
[1];
481 LPITEMIDLIST pidl
= (LPITEMIDLIST
)(pData
+firstOffset
);
483 //HTREEITEM hitem_sel = TreeView_GetSelection(_left_hwnd);
486 ShellDirectory
* parent
= (ShellDirectory
*)TreeView_GetItemData(_left_hwnd
, _last_sel
);
489 parent
->smart_scan();
491 Entry
* entry
= parent
->find_entry(pidl
);
493 if (entry
&& (entry
->_data
.dwFileAttributes
&FILE_ATTRIBUTE_DIRECTORY
))
494 if (expand_folder(static_cast<ShellDirectory
*>(entry
)))
500 GlobalUnlock(stgm
.hGlobal
);
501 ReleaseStgMedium(&stgm
);
503 selection
->Release();
508 bool ShellBrowserChild::expand_folder(ShellDirectory
* entry
)
510 //HTREEITEM hitem_sel = TreeView_GetSelection(_left_hwnd);
514 if (!TreeView_Expand(_left_hwnd
, _last_sel
, TVE_EXPAND
))
517 for(HTREEITEM hitem
=TreeView_GetChild(_left_hwnd
,_last_sel
); hitem
; hitem
=TreeView_GetNextSibling(_left_hwnd
,hitem
)) {
518 if ((ShellDirectory
*)TreeView_GetItemData(_left_hwnd
,hitem
) == entry
) {
519 if (TreeView_SelectItem(_left_hwnd
, hitem
) &&
520 TreeView_Expand(_left_hwnd
, hitem
, TVE_EXPAND
))