1 /*
2  * Copyright 2003, 2004, 2005, 2006 Martin Fuchs
3  *
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.
8  *
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.
13  *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 
20  //
21  // Explorer clone
22  //
23  // shellbrowser.cpp
24  //
25  // Martin Fuchs, 23.07.2003
26  //
27 
28 
29 #include <precomp.h>
30 
31  // work around GCC's wide string constant bug
32 #ifdef __GNUC__
33 const LPCTSTR C_DRIVE = C_DRIVE_STR;
34 #endif
35 
ShellBrowser(HWND hwnd,HWND hwndFrame,HWND left_hwnd,WindowHandle & right_hwnd,ShellPathInfo & create_info,BrowserCallback * cb,CtxMenuInterfaces & cm_ifs)36 ShellBrowser::ShellBrowser(HWND hwnd, HWND hwndFrame, HWND left_hwnd, WindowHandle& right_hwnd, ShellPathInfo& create_info,
37 							BrowserCallback* cb, CtxMenuInterfaces& cm_ifs)
38  :	super(IID_IShellFolderViewCB),
39 	_hwnd(hwnd),
40 	_hwndFrame(hwndFrame),
41 	_left_hwnd(left_hwnd),
42 	_right_hwnd(right_hwnd),
43 	_create_info(create_info),
44 	_callback(cb),
45 	_cm_ifs(cm_ifs)
46 {
47 	_pShellView = NULL;
48 	_pDropTarget = NULL;
49 	_last_sel = 0;
50 
51 	_cur_dir = NULL;
52 
53     HDC hDC = GetDC(NULL);
54     if (hDC)
55     {
56         INT bpp = GetDeviceCaps(hDC, BITSPIXEL);
57         ReleaseDC(NULL, hDC);
58 
59         DWORD ilMask;
60         if (bpp <= 4)
61             ilMask = ILC_COLOR4;
62         else if (bpp <= 8)
63             ilMask = ILC_COLOR8;
64         else if (bpp <= 16)
65             ilMask = ILC_COLOR16;
66         else if (bpp <= 24)
67             ilMask = ILC_COLOR24;
68         else if (bpp <= 32)
69             ilMask = ILC_COLOR32;
70         else
71             ilMask = ILC_COLOR;
72 
73         ilMask |= ILC_MASK;
74 
75         _himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ilMask, 2, 0);
76         ImageList_SetBkColor(_himl, GetSysColor(COLOR_WINDOW));
77     }
78 }
79 
~ShellBrowser()80 ShellBrowser::~ShellBrowser()
81 {
82 	(void)TreeView_SetImageList(_left_hwnd, _himl_old, TVSIL_NORMAL);
83 	ImageList_Destroy(_himl);
84 
85 	if (_pShellView)
86 		_pShellView->Release();
87 
88 	if (_pDropTarget) {
89 		_pDropTarget->Release();
90 		_pDropTarget = NULL;
91 	}
92 
93 	if (_right_hwnd) {
94 		DestroyWindow(_right_hwnd);
95 		_right_hwnd = 0;
96 	}
97 }
98 
99 
Init()100 void ShellBrowser::Init()
101 {
102 	CONTEXT("ShellBrowser::Init()");
103 
104 	const String& root_name = GetDesktopFolder().get_name(_create_info._root_shell_path, SHGDN_FORADDRESSBAR);
105 
106 	_root._drive_type = DRIVE_UNKNOWN;
107 	lstrcpy(_root._volname, root_name);
108 	_root._fs_flags = 0;
109 	lstrcpy(_root._fs, TEXT("Desktop"));
110 
111 	_root._entry = new ShellDirectory(GetDesktopFolder(), _create_info._root_shell_path, _hwnd);
112 
113 	_root._entry->read_directory(SCAN_DONT_ACCESS|SCAN_NO_FILESYSTEM);	// avoid to handle desktop root folder as file system directory
114 
115 	if (_left_hwnd) {
116 		InitializeTree();
117 		InitDragDrop();
118 	}
119 
120 	jump_to(_create_info._shell_path);
121 
122 	/* already filled by ShellDirectory constructor
123 	lstrcpy(_root._entry->_data.cFileName, TEXT("Desktop")); */
124 }
125 
jump_to(LPCITEMIDLIST pidl)126 void ShellBrowser::jump_to(LPCITEMIDLIST pidl)
127 {
128 	Entry* entry = NULL;
129 
130 	if (!_cur_dir)
131 		_cur_dir = static_cast<ShellDirectory*>(_root._entry);
132 
133 	//LOG(FmtString(TEXT("ShellBrowser::jump_to(): pidl=%s"), (LPCTSTR)FileSysShellPath(pidl)));
134 
135 	 // We could call read_tree() here to iterate through the hierarchy and open all folders
136 	 // from _create_info._root_shell_path (_cur_dir) to _create_info._shell_path (pidl).
137 	 // To make it easier we just use ILFindChild() instead.
138 	if (_cur_dir) {
139 		static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST, LPCITEMIDLIST)> ILFindChild(TEXT("SHELL32"), 24);
140 
141 		if (ILFindChild) {
142 			for(;;) {
143 				LPCITEMIDLIST child_pidl = (*ILFindChild)(_cur_dir->create_absolute_pidl(), pidl);
144 				if (!child_pidl || !child_pidl->mkid.cb)
145 					break;
146 
147 				_cur_dir->smart_scan(SORT_NAME, SCAN_DONT_ACCESS);
148 
149 				entry = _cur_dir->find_entry(child_pidl);
150 				if (!entry)
151 					break;
152 
153 				_cur_dir = static_cast<ShellDirectory*>(entry);
154 				_callback->entry_selected(entry);
155 			}
156 		} else {
157 			_cur_dir->smart_scan(SORT_NAME, SCAN_DONT_ACCESS);
158 
159 			entry = _cur_dir->find_entry(pidl);	// This is not correct in the common case, but works on the desktop level.
160 
161 			if (entry) {
162 				_cur_dir = static_cast<ShellDirectory*>(entry);
163 				_callback->entry_selected(entry);
164 			}
165 		}
166 	}
167 
168 	 // If not already called, now directly call UpdateFolderView() using pidl
169 	if (!entry)
170 		UpdateFolderView(ShellFolder(pidl));
171 }
172 
173 
InitializeTree()174 void ShellBrowser::InitializeTree()
175 {
176 	CONTEXT("ShellBrowserChild::InitializeTree()");
177 
178 	_himl_old = TreeView_SetImageList(_left_hwnd, _himl, TVSIL_NORMAL);
179 	TreeView_SetScrollTime(_left_hwnd, 100);
180 
181 	TV_INSERTSTRUCT tvInsert;
182 	TV_ITEM& tvItem = tvInsert.item;
183 
184 	tvInsert.hParent = 0;
185 	tvInsert.hInsertAfter = TVI_LAST;
186 
187 	tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
188 	tvItem.lParam = (LPARAM)_root._entry;
189 	tvItem.pszText = _root._volname; //LPSTR_TEXTCALLBACK;
190 	tvItem.iImage = tvItem.iSelectedImage = I_IMAGECALLBACK;
191 	tvItem.cChildren = 1;
192 
193 	HTREEITEM hItem = TreeView_InsertItem(_left_hwnd, &tvInsert);
194 	TreeView_SelectItem(_left_hwnd, hItem);
195 	TreeView_Expand(_left_hwnd, hItem, TVE_EXPAND);
196 }
197 
InitDragDrop()198 bool ShellBrowser::InitDragDrop()
199 {
200 	CONTEXT("ShellBrowser::InitDragDrop()");
201 
202 	_pDropTarget = new TreeDropTarget(_left_hwnd);
203 
204 	if (!_pDropTarget)
205 		return false;
206 
207 	_pDropTarget->AddRef();
208 
209 	if (FAILED(RegisterDragDrop(_left_hwnd, _pDropTarget))) {//calls addref
210 		_pDropTarget->Release(); // free TreeDropTarget
211 		_pDropTarget = NULL;
212 		return false;
213 	} else
214 		_pDropTarget->Release();
215 
216 	FORMATETC ftetc;
217 
218 	ftetc.dwAspect = DVASPECT_CONTENT;
219 	ftetc.lindex = -1;
220 	ftetc.tymed = TYMED_HGLOBAL;
221 	ftetc.cfFormat = CF_HDROP;
222 
223 	_pDropTarget->AddSuportedFormat(ftetc);
224 
225 	return true;
226 }
227 
228 
OnTreeGetDispInfo(int idCtrl,LPNMHDR pnmh)229 void ShellBrowser::OnTreeGetDispInfo(int idCtrl, LPNMHDR pnmh)
230 {
231 	CONTEXT("ShellBrowser::OnTreeGetDispInfo()");
232 
233 	LPNMTVDISPINFO lpdi = (LPNMTVDISPINFO)pnmh;
234 	ShellEntry* entry = (ShellEntry*)lpdi->item.lParam;
235 
236 	if (entry) {
237 		if (lpdi->item.mask & TVIF_TEXT)
238 			lpdi->item.pszText = entry->_display_name;
239 
240 		if (lpdi->item.mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
241 			if (lpdi->item.mask & TVIF_IMAGE)
242 				lpdi->item.iImage = get_image_idx(
243 						entry->safe_extract_icon((ICONCACHE_FLAGS)(ICF_HICON|ICF_OVERLAYS)));
244 
245 			if (lpdi->item.mask & TVIF_SELECTEDIMAGE)
246 				lpdi->item.iSelectedImage = get_image_idx(
247 						entry->safe_extract_icon((ICONCACHE_FLAGS)(ICF_HICON|ICF_OVERLAYS|ICF_OPEN)));
248 		}
249 	}
250 }
251 
get_image_idx(int icon_id)252 int ShellBrowser::get_image_idx(int icon_id)
253 {
254 	if (icon_id != ICID_NONE) {
255 		map<int,int>::const_iterator found = _image_map.find(icon_id);
256 
257 		if (found != _image_map.end())
258 			return found->second;
259 
260 		int idx = ImageList_AddIcon(_himl, g_Globals._icon_cache.get_icon(icon_id).get_hicon());
261 
262 		_image_map[icon_id] = idx;
263 
264 		return idx;
265 	} else
266 		return -1;
267 }
268 
invalidate_cache()269 void ShellBrowser::invalidate_cache()
270 {
271 	(void)TreeView_SetImageList(_left_hwnd, _himl_old, TVSIL_NORMAL);
272 	ImageList_Destroy(_himl);
273 
274 	_himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK|ILC_COLOR24, 2, 0);
275 	ImageList_SetBkColor(_himl, GetSysColor(COLOR_WINDOW));
276 
277 	_himl_old = TreeView_SetImageList(_left_hwnd, _himl, TVSIL_NORMAL);
278 
279 	for(map<int,int>::const_iterator it=_image_map.begin(); it!=_image_map.end(); ++it)
280 		g_Globals._icon_cache.free_icon(it->first);
281 
282 	_image_map.clear();
283 }
284 
285 
OnTreeItemExpanding(int idCtrl,LPNMTREEVIEW pnmtv)286 void ShellBrowser::OnTreeItemExpanding(int idCtrl, LPNMTREEVIEW pnmtv)
287 {
288 	CONTEXT("ShellBrowser::OnTreeItemExpanding()");
289 
290 	if (pnmtv->action == TVE_COLLAPSE)
291         TreeView_Expand(_left_hwnd, pnmtv->itemNew.hItem, TVE_COLLAPSE|TVE_COLLAPSERESET);
292     else if (pnmtv->action == TVE_EXPAND) {
293 		ShellDirectory* entry = (ShellDirectory*)TreeView_GetItemData(_left_hwnd, pnmtv->itemNew.hItem);
294 
295 		if (entry)
296 			if (!InsertSubitems(pnmtv->itemNew.hItem, entry, entry->_folder)) {
297 				entry->_shell_attribs &= ~SFGAO_HASSUBFOLDER;
298 
299 				 // remove subitem "+"
300 				TV_ITEM tvItem;
301 
302 				tvItem.mask = TVIF_CHILDREN;
303 				tvItem.hItem = pnmtv->itemNew.hItem;
304 				tvItem.cChildren = 0;
305 
306 				TreeView_SetItem(_left_hwnd, &tvItem);
307 			}
308 	}
309 }
310 
InsertSubitems(HTREEITEM hParentItem,Entry * entry,IShellFolder * pParentFolder)311 int ShellBrowser::InsertSubitems(HTREEITEM hParentItem, Entry* entry, IShellFolder* pParentFolder)
312 {
313 	CONTEXT("ShellBrowser::InsertSubitems()");
314 
315 	WaitCursor wait;
316 
317 	int cnt = 0;
318 
319 	SendMessage(_left_hwnd, WM_SETREDRAW, FALSE, 0);
320 
321 	try {
322 		entry->smart_scan(SORT_NAME, SCAN_DONT_ACCESS);
323 	} catch(COMException& e) {
324 		HandleException(e, g_Globals._hMainWnd);
325 	}
326 
327 	 // remove old children items
328 	HTREEITEM hchild, hnext;
329 
330 	hnext = TreeView_GetChild(_left_hwnd, hParentItem);
331 
332 	while((hchild=hnext) != 0) {
333 		hnext = TreeView_GetNextSibling(_left_hwnd, hchild);
334 		TreeView_DeleteItem(_left_hwnd, hchild);
335 	}
336 
337 	TV_ITEM tvItem;
338 	TV_INSERTSTRUCT tvInsert;
339 
340 	for(entry=entry->_down; entry; entry=entry->_next) {
341 #ifndef _LEFT_FILES
342 		if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
343 #endif
344 		{
345 			 // ignore hidden directories
346 			if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
347 				continue;
348 
349 			 // ignore directory entries "." and ".."
350 			if (entry->_data.cFileName[0]==TEXT('.') &&
351 				(entry->_data.cFileName[1]==TEXT('\0') ||
352 				(entry->_data.cFileName[1]==TEXT('.') && entry->_data.cFileName[2]==TEXT('\0'))))
353 				continue;
354 
355 			ZeroMemory(&tvItem, sizeof(tvItem));
356 
357 			tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
358 			tvItem.pszText = LPSTR_TEXTCALLBACK;
359 			tvItem.iImage = tvItem.iSelectedImage = I_IMAGECALLBACK;
360 			tvItem.lParam = (LPARAM)entry;
361 			tvItem.cChildren = entry->_shell_attribs & SFGAO_HASSUBFOLDER? 1: 0;
362 
363 			if (entry->_shell_attribs & SFGAO_SHARE) {
364 				tvItem.mask |= TVIF_STATE;
365 				tvItem.stateMask |= TVIS_OVERLAYMASK;
366 				tvItem.state |= INDEXTOOVERLAYMASK(1);
367 			}
368 
369 			tvInsert.item = tvItem;
370 			tvInsert.hInsertAfter = TVI_LAST;
371 			tvInsert.hParent = hParentItem;
372 
373 			(void)TreeView_InsertItem(_left_hwnd, &tvInsert);
374 
375 			++cnt;
376 		}
377 	}
378 
379 	SendMessage(_left_hwnd, WM_SETREDRAW, TRUE, 0);
380 
381 	return cnt;
382 }
383 
384 
OnTreeItemSelected(int idCtrl,LPNMTREEVIEW pnmtv)385 void ShellBrowser::OnTreeItemSelected(int idCtrl, LPNMTREEVIEW pnmtv)
386 {
387 	CONTEXT("ShellBrowser::OnTreeItemSelected()");
388 
389 	Entry* entry = (Entry*)pnmtv->itemNew.lParam;
390 
391 	_last_sel = pnmtv->itemNew.hItem;
392 
393 	if (entry)
394 		_callback->entry_selected(entry);
395 }
396 
397 
OnTreeItemRClick(int idCtrl,LPNMHDR pnmh)398 void ShellBrowser::OnTreeItemRClick(int idCtrl, LPNMHDR pnmh)
399 {
400 	CONTEXT("ShellBrowser::OnTreeItemRClick()");
401 
402 	TVHITTESTINFO tvhti;
403 
404 	GetCursorPos(&tvhti.pt);
405 	ScreenToClient(_left_hwnd, &tvhti.pt);
406 
407 	tvhti.flags = LVHT_NOWHERE;
408 	(void)TreeView_HitTest(_left_hwnd, &tvhti);
409 
410 	if (TVHT_ONITEM & tvhti.flags) {
411 		LPARAM itemData = TreeView_GetItemData(_left_hwnd, tvhti.hItem);
412 
413 		if (itemData) {
414 			Entry* entry = (Entry*)itemData;
415 			ClientToScreen(_left_hwnd, &tvhti.pt);
416 
417 			HRESULT hr = entry->do_context_menu(_hwnd, tvhti.pt, _cm_ifs);
418 
419 			if (SUCCEEDED(hr))
420 				refresh();
421 			else
422 				CHECKERROR(hr);
423 		}
424 	}
425 }
426 
427 
UpdateFolderView(IShellFolder * folder)428 void ShellBrowser::UpdateFolderView(IShellFolder* folder)
429 {
430 	CONTEXT("ShellBrowser::UpdateFolderView()");
431 
432 	FOLDERSETTINGS fs;
433 	IShellView* pLastShellView = _pShellView;
434 
435 	_folder = folder;
436 
437 	if (pLastShellView)
438 		pLastShellView->GetCurrentInfo(&fs);
439 	else {
440 		fs.ViewMode = _create_info._open_mode&OWM_DETAILS? FVM_DETAILS: FVM_ICON;
441 		fs.fFlags = FWF_NOCLIENTEDGE|FWF_BESTFITWINDOW;
442 	}
443 
444 	SFV_CREATE sfv_create;
445 
446 	sfv_create.cbSize = sizeof(SFV_CREATE);
447 	sfv_create.pshf = folder;
448 	sfv_create.psvOuter = NULL;
449 	sfv_create.psfvcb = this;
450 
451 	HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);
452 
453 	if (FAILED(hr)) {
454 		_pShellView = NULL;
455 		return;
456 	}
457 
458 	RECT rect = {CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT};
459 	hr = _pShellView->CreateViewWindow(pLastShellView, &fs, static_cast<IShellBrowser*>(this), &rect, &_right_hwnd/*&m_hWndListView*/);
460 
461 	if (pLastShellView) {
462 		pLastShellView->GetCurrentInfo(&fs);
463 		pLastShellView->UIActivate(SVUIA_DEACTIVATE);
464 		pLastShellView->DestroyViewWindow();
465 		pLastShellView->Release();
466 	}
467 
468 	_pShellView->UIActivate(SVUIA_ACTIVATE_NOFOCUS);
469 }
470 
471  /// shell view callback
MessageSFVCB(UINT uMsg,WPARAM wParam,LPARAM lParam)472 HRESULT STDMETHODCALLTYPE ShellBrowser::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
473 {
474 	if (uMsg == SFVM_INITMENUPOPUP) {
475 		///@todo never reached
476 		InsertMenu((HMENU)lParam, 0, MF_BYPOSITION, 12345, TEXT("TEST ENTRY"));
477 		return S_OK;
478 	}
479 
480 	return E_NOTIMPL;
481 }
482 
483 
OnDefaultCommand(LPIDA pida)484 HRESULT ShellBrowser::OnDefaultCommand(LPIDA pida)
485 {
486 	CONTEXT("ShellBrowser::OnDefaultCommand()");
487 
488 	if (pida->cidl >= 1) {
489 		if (_left_hwnd) {	// explorer mode
490 			if (_last_sel) {
491 				ShellDirectory* parent = (ShellDirectory*)TreeView_GetItemData(_left_hwnd, _last_sel);
492 
493 				if (parent) {
494 					try {
495 						parent->smart_scan(SORT_NAME, SCAN_DONT_ACCESS);
496 					} catch(COMException& e) {
497 						return e.Error();
498 					}
499 
500 					UINT firstOffset = pida->aoffset[1];
501 					LPITEMIDLIST pidl = (LPITEMIDLIST)((LPBYTE)pida+firstOffset);
502 
503 					Entry* entry = parent->find_entry(pidl);
504 
505 					if (entry && (entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
506 						if (entry->_etype == ET_SHELL)
507 							if (_last_sel && select_entry(_last_sel, entry))
508 								return S_OK;
509 
510 					///@todo look for hidden or new subfolders and refresh/add new entry instead of opening a new window
511 					return E_NOTIMPL;
512 				}
513 			}
514 		} else { // no tree control
515 			if (MainFrameBase::OpenShellFolders(pida, _hwndFrame))
516 				return S_OK;
517 
518 /* create new Frame Window
519 			if (MainFrame::OpenShellFolders(pida, 0))
520 				return S_OK;
521 */
522 		}
523 	}
524 
525 	return E_NOTIMPL;
526 }
527 
528 
select_entry(HTREEITEM hitem,Entry * entry,bool expand)529 HTREEITEM ShellBrowser::select_entry(HTREEITEM hitem, Entry* entry, bool expand)
530 {
531 	CONTEXT("ShellBrowser::select_entry()");
532 
533 	if (expand && !TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND))
534 		return 0;
535 
536 	for(hitem=TreeView_GetChild(_left_hwnd,hitem); hitem; hitem=TreeView_GetNextSibling(_left_hwnd,hitem)) {
537 		if ((Entry*)TreeView_GetItemData(_left_hwnd,hitem) == entry) {
538 			if (TreeView_SelectItem(_left_hwnd, hitem)) {
539 				if (expand)
540 					TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND);
541 
542 				return hitem;
543 			}
544 
545 			break;
546 		}
547 	}
548 
549 	return 0;
550 }
551 
552 
jump_to_pidl(LPCITEMIDLIST pidl)553 bool ShellBrowser::jump_to_pidl(LPCITEMIDLIST pidl)
554 {
555 	if (!_root._entry)
556 		return false;
557 
558 	 // iterate through the hierarchy and open all folders to reach pidl
559 	WaitCursor wait;
560 
561 	HTREEITEM hitem = TreeView_GetRoot(_left_hwnd);
562 	Entry* entry = _root._entry;
563 
564 	for(const void*p=pidl;;) {
565 		if (!p)
566 			return true;
567 
568 		if (!entry || !hitem)
569 			break;
570 
571 		entry->smart_scan(SORT_NAME, SCAN_DONT_ACCESS);
572 
573 		Entry* found = entry->find_entry(p);
574 		p = entry->get_next_path_component(p);
575 
576 		if (found)
577 			hitem = select_entry(hitem, found);
578 
579 		entry = found;
580 	}
581 
582 	return false;
583 }
584 
TranslateAccelerator(LPMSG lpmsg)585 bool ShellBrowser::TranslateAccelerator(LPMSG lpmsg)
586 {
587     HWND hwnd;
588 
589     /* TranslateAccelerator is called for all explorer windows that are open
590        so we have to decide if this is the correct recipient */
591     hwnd = lpmsg->hwnd;
592 
593     while(hwnd)
594     {
595         if(hwnd == _hwnd)
596             break;
597 
598         hwnd = GetParent(hwnd);
599     }
600 
601     if (hwnd)
602         return _pShellView->TranslateAccelerator(lpmsg) == S_OK;
603 
604     return false;
605 }
606 
select_folder(Entry * entry,bool expand)607 bool ShellBrowser::select_folder(Entry* entry, bool expand)
608 {
609 	CONTEXT("ShellBrowser::expand_folder()");
610 
611 	if (!_last_sel)
612 		return false;
613 
614 	if (!TreeView_Expand(_left_hwnd, _last_sel, TVE_EXPAND))
615 		return false;
616 
617 	for(HTREEITEM hitem=TreeView_GetChild(_left_hwnd,_last_sel); hitem; hitem=TreeView_GetNextSibling(_left_hwnd,hitem)) {
618 		if ((ShellDirectory*)TreeView_GetItemData(_left_hwnd,hitem) == entry) {
619 			if (TreeView_SelectItem(_left_hwnd, hitem)) {
620 				if (expand)
621 					if (!TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND))
622 						return false;
623 
624 				return true;
625 			}
626 
627 			break;
628 		}
629 	}
630 
631 	return false;
632 }
633 
634 
refresh()635 void ShellBrowser::refresh()
636 {
637 	///@todo
638 }
639 
640 
641 #ifndef _NO_MDI
642 
MDIShellBrowserChild(HWND hwnd,const ShellChildWndInfo & info)643 MDIShellBrowserChild::MDIShellBrowserChild(HWND hwnd, const ShellChildWndInfo& info)
644  :	super(hwnd, info),
645 	_create_info(info),
646 	_shellpath_info(info)	//@@ copies info -> no reference to _create_info !
647 {
648 /**todo Conversion of shell path into path string -> store into URL history
649 	const String& path = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORADDRESSBAR);
650 	const String& parsingpath = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORPARSING);
651 
652 	 // store path into history
653 	if (info._path && *info._path)
654 		_url_history.push(info._path);
655 */
656 }
657 
658 
create(const ShellChildWndInfo & info)659 MDIShellBrowserChild* MDIShellBrowserChild::create(const ShellChildWndInfo& info)
660 {
661 	ChildWindow* child = ChildWindow::create(info,
662 		                                     info._pos.rcNormalPosition,
663 		                                     WINDOW_CREATOR_INFO(MDIShellBrowserChild,ShellChildWndInfo),
664 											 CLASSNAME_CHILDWND,
665 											 NULL,
666 											 WS_CLIPCHILDREN | (info._pos.showCmd==SW_SHOWMAXIMIZED? WS_MAXIMIZE: 0));
667 
668 	return static_cast<MDIShellBrowserChild*>(child);
669 }
670 
671 
Init(LPCREATESTRUCT pcs)672 LRESULT MDIShellBrowserChild::Init(LPCREATESTRUCT pcs)
673 {
674 	CONTEXT("MDIShellBrowserChild::Init()");
675 
676 	if (super::Init(pcs))
677 		return 1;
678 
679 	update_shell_browser();
680 
681 	return 0;
682 }
683 
684 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)685 LRESULT MDIShellBrowserChild::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
686 {
687 	switch(nmsg) {
688 	  case PM_DISPATCH_COMMAND: {
689 		switch(LOWORD(wparam)) {
690 		  case ID_WINDOW_NEW: {CONTEXT("MDIShellBrowserChild PM_DISPATCH_COMMAND ID_WINDOW_NEW");
691 			MDIShellBrowserChild::create(_create_info);
692 			break;}
693 
694 		  case ID_REFRESH:
695 			///@todo refresh shell child
696 			_shellBrowser->invalidate_cache();
697 			break;
698 
699 		  case ID_VIEW_SDI:
700 			MainFrameBase::Create(ExplorerCmd(_url, false));
701 			break;
702 
703 		  default:
704 			return super::WndProc(nmsg, wparam, lparam);
705 		}
706 		return TRUE;}
707 
708 	  case WM_SYSCOLORCHANGE:
709 		/* Forward WM_SYSCOLORCHANGE to common controls */
710 		SendMessage(_left_hwnd, WM_SYSCOLORCHANGE, 0, 0);
711 		SendMessage(_right_hwnd, WM_SYSCOLORCHANGE, 0, 0);
712 		break;
713 
714 	  case PM_TRANSLATE_MSG:
715 		return _shellBrowser->TranslateAccelerator((MSG*)lparam);
716 
717 	  default:
718 		return super::WndProc(nmsg, wparam, lparam);
719 	}
720 
721 	return 0;
722 }
723 
update_shell_browser()724 void MDIShellBrowserChild::update_shell_browser()
725 {
726 	int split_pos = DEFAULT_SPLIT_POS;
727 
728 	if (_shellBrowser.get()) {
729 		split_pos = _split_pos;
730 		delete _shellBrowser.release();
731 	}
732 
733 	 // create explorer treeview
734 	if (_create_info._open_mode & OWM_EXPLORE) {
735 		if (!_left_hwnd) {
736 			ClientRect rect(_hwnd);
737 
738 			_left_hwnd = CreateWindowEx(0, WC_TREEVIEW, NULL,
739 							WS_CHILD|WS_TABSTOP|WS_VISIBLE|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS,//|TVS_NOTOOLTIPS
740 							0, rect.top, split_pos-SPLIT_WIDTH/2, rect.bottom-rect.top,
741 							_hwnd, (HMENU)IDC_FILETREE, g_Globals._hInstance, 0);
742 		}
743 	} else {
744 		if (_left_hwnd) {
745 			DestroyWindow(_left_hwnd);
746 			_left_hwnd = 0;
747 		}
748 	}
749 
750 	_shellBrowser = auto_ptr<ShellBrowser>(new ShellBrowser(_hwnd, _hwndFrame, _left_hwnd, _right_hwnd,
751 												_shellpath_info, this, _cm_ifs));
752 
753 	_shellBrowser->Init();
754 }
755 
756 
jump_to_int(LPCTSTR url)757 String MDIShellBrowserChild::jump_to_int(LPCTSTR url)
758 {
759 	String dir, fname;
760 
761 	if (!_tcsnicmp(url, TEXT("shell://"), 8)) {
762 		if (_shellBrowser->jump_to_pidl(ShellPath(url+8)))
763 			return url;
764 	}
765 
766 	if (SplitFileSysURL(url, dir, fname)) {
767 
768 		///@todo use fname
769 
770 		if (_shellBrowser->jump_to_pidl(ShellPath(dir)))
771 			return FmtString(TEXT("file://%s"), (LPCTSTR)dir);
772 	}
773 
774 	return String();
775 }
776 
777 
entry_selected(Entry * entry)778 void MDIShellBrowserChild::entry_selected(Entry* entry)
779 {
780 	if (_left_hwnd)
781 		_shellBrowser->select_folder(entry, false);
782 
783 	_shellBrowser->UpdateFolderView(entry->get_shell_folder());
784 
785 	 // set size of new created shell view windows
786 	ClientRect rt(_hwnd);
787 	resize_children(rt.right, rt.bottom);
788 
789 	 // set new URL
790 	TCHAR path[MAX_PATH];
791 
792 	if (entry->get_path(path, COUNTOF(path))) {
793 		String url;
794 
795 		if (path[0] == ':')
796 			url.printf(TEXT("shell://%s"), path);
797 		else
798 			url.printf(TEXT("file://%s"), path);
799 
800 		set_url(url);
801 	}
802 }
803 
804 #endif
805