reinitialize image list in ShellBrowser::invalidate_cache()
[reactos.git] / reactos / subsys / system / explorer / shell / shellbrowser.cpp
index 55094c3..eb15c37 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003, 2004 Martin Fuchs
+ * Copyright 2003, 2004, 2005 Martin Fuchs
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,7 +18,7 @@
 
 
  //
- // Explorer clone, lean version
+ // Explorer clone
  //
  // shellbrowser.cpp
  //
  //
 
 
-#include "precomp.h"
+#include <precomp.h>
 
-#include "../explorer_intres.h"
+#include "../resource.h"
 
 
-static LPARAM TreeView_GetItemData(HWND hwndTreeView, HTREEITEM hItem)
-{
-       TVITEM tvItem;
-
-       tvItem.mask = TVIF_PARAM;
-       tvItem.hItem = hItem;
-
-       if (!TreeView_GetItem(hwndTreeView, &tvItem))
-               return 0;
-
-       return tvItem.lParam;
-}
+ // work around GCC's wide string constant bug
+#ifdef __GNUC__
+const LPCTSTR C_DRIVE = C_DRIVE_STR;
+#endif
 
 
-ShellBrowserChild::ShellBrowserChild(HWND hwnd, HWND left_hwnd, WindowHandle& right_hwnd, ShellPathInfo& create_info)
- :     _hwnd(hwnd),
+ShellBrowser::ShellBrowser(HWND hwnd, HWND left_hwnd, WindowHandle& right_hwnd, ShellPathInfo& create_info,
+                                                       BrowserCallback* cb, CtxMenuInterfaces& cm_ifs)
+#ifndef __MINGW32__    // IShellFolderViewCB missing in MinGW (as of 25.09.2005)
+ :     super(IID_IShellFolderViewCB),
+#else
+ :     
+#endif
+       _hwnd(hwnd),
        _left_hwnd(left_hwnd),
        _right_hwnd(right_hwnd),
-       _create_info(create_info)
+       _create_info(create_info),
+       _callback(cb),
+       _cm_ifs(cm_ifs)
 {
        _pShellView = NULL;
        _pDropTarget = NULL;
-       _himlSmall = 0;
        _last_sel = 0;
 
-        // SDI integration
-       _split_pos = DEFAULT_SPLIT_POS;
-       _last_split = DEFAULT_SPLIT_POS;
-
        _cur_dir = NULL;
 
-       Init(hwnd);
+       _himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK|ILC_COLOR24, 2, 0);
+       ImageList_SetBkColor(_himl, GetSysColor(COLOR_WINDOW));
 }
 
-ShellBrowserChild::~ShellBrowserChild()
+ShellBrowser::~ShellBrowser()
 {
+       (void)TreeView_SetImageList(_left_hwnd, _himl_old, TVSIL_NORMAL);
+       ImageList_Destroy(_himl);
+
        if (_pShellView)
                _pShellView->Release();
 
@@ -82,25 +81,13 @@ ShellBrowserChild::~ShellBrowserChild()
 }
 
 
-LRESULT ShellBrowserChild::Init(HWND hWndFrame)
+LRESULT ShellBrowser::Init(HWND hWndFrame)
 {
-       CONTEXT("ShellBrowserChild::Init()");
+       CONTEXT("ShellBrowser::Init()");
 
        _hWndFrame = hWndFrame;
 
-       ClientRect rect(_hwnd);
-
-       SHFILEINFO sfi;
-
-       _himlSmall = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX|SHGFI_SMALLICON);
-//     _himlLarge = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX|SHGFI_LARGEICON);
-
-       if (_left_hwnd) {
-               InitializeTree();
-               InitDragDrop();
-       }
-
-       const String& root_name = GetDesktopFolder().get_name(_create_info._root_shell_path, SHGDN_FORPARSING);
+       const String& root_name = GetDesktopFolder().get_name(_create_info._root_shell_path, SHGDN_FORADDRESSBAR);
 
        _root._drive_type = DRIVE_UNKNOWN;
        lstrcpy(_root._volname, root_name);
@@ -120,37 +107,77 @@ LRESULT ShellBrowserChild::Init(HWND hWndFrame)
        return 0;
 }
 
+void ShellBrowser::jump_to(LPCITEMIDLIST pidl)
+{
+       Entry* entry = NULL;
+
+        //@@
+       if (!_cur_dir)
+               _cur_dir = static_cast<ShellDirectory*>(_root._entry);
+
+       //LOG(FmtString(TEXT("ShellBrowser::jump_to(): pidl=%s"), (LPCTSTR)FileSysShellPath(pidl)));
+
+       if (_cur_dir) {
+               static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST, LPCITEMIDLIST)> ILFindChild(TEXT("SHELL32"), 24);
+
+/*@todo
+       we should call read_tree() here to iterate through the hierarchy and open all folders from _create_info._root_shell_path (_cur_dir) to _create_info._shell_path (pidl)
+       _root._entry->read_tree(_create_info._root_shell_path.get_folder(), info._shell_path, SORT_NAME);
+       -> see FileChildWindow::FileChildWindow()_create_info._shell_path
+*/
+
+               LPCITEMIDLIST child_pidl;
 
-void ShellBrowserChild::InitializeTree()
+               if (ILFindChild)
+                       child_pidl = (*ILFindChild)(_cur_dir->create_absolute_pidl(), pidl);
+               else
+                       child_pidl = pidl;      // This is not correct in the common case, but works on the desktop level.
+
+               if (child_pidl) {
+                       _cur_dir->smart_scan();
+
+                       entry = _cur_dir->find_entry(child_pidl);
+
+                       if (entry) {
+                               _cur_dir = static_cast<ShellDirectory*>(entry);
+                               _callback->entry_selected(entry);
+                       }
+               }
+       }
+
+               //@@ work around as long as we don't iterate correctly through the ShellEntry tree
+       if (!entry)
+               UpdateFolderView(ShellFolder(pidl));
+}
+
+
+void ShellBrowser::InitializeTree()
 {
        CONTEXT("ShellBrowserChild::InitializeTree()");
 
-       TreeView_SetImageList(_left_hwnd, _himlSmall, TVSIL_NORMAL);
+       _himl_old = TreeView_SetImageList(_left_hwnd, _himl, TVSIL_NORMAL);
        TreeView_SetScrollTime(_left_hwnd, 100);
 
-       TV_ITEM tvItem;
+       TV_INSERTSTRUCT tvInsert;
+       TV_ITEM& tvItem = tvInsert.item;
+
+       tvInsert.hParent = 0;
+       tvInsert.hInsertAfter = TVI_LAST;
 
        tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;
        tvItem.lParam = (LPARAM)_root._entry;
-       tvItem.pszText = LPSTR_TEXTCALLBACK;
+       tvItem.pszText = _root._volname; //LPSTR_TEXTCALLBACK;
        tvItem.iImage = tvItem.iSelectedImage = I_IMAGECALLBACK;
        tvItem.cChildren = 1;
 
-       TV_INSERTSTRUCT tvInsert;
-
-       tvInsert.hParent = 0;
-       tvInsert.hInsertAfter = TVI_LAST;
-       tvInsert.item = tvItem;
-
        HTREEITEM hItem = TreeView_InsertItem(_left_hwnd, &tvInsert);
        TreeView_SelectItem(_left_hwnd, hItem);
        TreeView_Expand(_left_hwnd, hItem, TVE_EXPAND);
 }
 
-
-bool ShellBrowserChild::InitDragDrop()
+bool ShellBrowser::InitDragDrop()
 {
-       CONTEXT("ShellBrowserChild::InitDragDrop()");
+       CONTEXT("ShellBrowser::InitDragDrop()");
 
        _pDropTarget = new TreeDropTarget(_left_hwnd);
 
@@ -163,8 +190,7 @@ bool ShellBrowserChild::InitDragDrop()
                _pDropTarget->Release(); // free TreeDropTarget
                _pDropTarget = NULL;
                return false;
-       }
-       else
+       } else
                _pDropTarget->Release();
 
        FORMATETC ftetc;
@@ -180,9 +206,9 @@ bool ShellBrowserChild::InitDragDrop()
 }
 
 
-void ShellBrowserChild::OnTreeItemRClick(int idCtrl, LPNMHDR pnmh)
+void ShellBrowser::OnTreeItemRClick(int idCtrl, LPNMHDR pnmh)
 {
-       CONTEXT("ShellBrowserChild::OnTreeItemRClick()");
+       CONTEXT("ShellBrowser::OnTreeItemRClick()");
 
        TVHITTESTINFO tvhti;
 
@@ -190,78 +216,77 @@ void ShellBrowserChild::OnTreeItemRClick(int idCtrl, LPNMHDR pnmh)
        ScreenToClient(_left_hwnd, &tvhti.pt);
 
        tvhti.flags = LVHT_NOWHERE;
-       TreeView_HitTest(_left_hwnd, &tvhti);
+       (void)TreeView_HitTest(_left_hwnd, &tvhti);
 
        if (TVHT_ONITEM & tvhti.flags) {
-               ClientToScreen(_left_hwnd, &tvhti.pt);
-               Tree_DoItemMenu(_left_hwnd, tvhti.hItem , &tvhti.pt);
+               LPARAM itemData = TreeView_GetItemData(_left_hwnd, tvhti.hItem);
+
+               if (itemData) {
+                       Entry* entry = (Entry*)itemData;
+                       ClientToScreen(_left_hwnd, &tvhti.pt);
+
+                       CHECKERROR(entry->do_context_menu(_hwnd, tvhti.pt, _cm_ifs));
+               }
        }
 }
 
-void ShellBrowserChild::Tree_DoItemMenu(HWND hwndTreeView, HTREEITEM hItem, LPPOINT pptScreen)
+void ShellBrowser::OnTreeGetDispInfo(int idCtrl, LPNMHDR pnmh)
 {
-       CONTEXT("ShellBrowserChild::Tree_DoItemMenu()");
-
-       LPARAM itemData = TreeView_GetItemData(hwndTreeView, hItem);
+       CONTEXT("ShellBrowser::OnTreeGetDispInfo()");
 
-       if (itemData) {
-               Entry* entry = (Entry*)itemData;
+       LPNMTVDISPINFO lpdi = (LPNMTVDISPINFO)pnmh;
+       ShellEntry* entry = (ShellEntry*)lpdi->item.lParam;
 
-               if (entry->_etype == ET_SHELL) {
-                       ShellDirectory* dir = static_cast<ShellDirectory*>(entry->_up);
-                       ShellFolder folder = dir? dir->_folder: GetDesktopFolder();
-                       LPCITEMIDLIST pidl = static_cast<ShellEntry*>(entry)->_pidl;
+       if (entry) {
+               if (lpdi->item.mask & TVIF_TEXT)
+                       lpdi->item.pszText = entry->_display_name;
 
-                       CHECKERROR(ShellFolderContextMenu(folder, ::GetParent(hwndTreeView), 1, &pidl, pptScreen->x, pptScreen->y));
-               } else {
-                       ShellPath shell_path = entry->create_absolute_pidl();
-                       LPCITEMIDLIST pidl = shell_path;
+               if (lpdi->item.mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
+                       if (lpdi->item.mask & TVIF_IMAGE)
+                               lpdi->item.iImage = get_image_idx(
+                                               entry->safe_extract_icon((ICONCACHE_FLAGS)(ICF_HICON|ICF_OVERLAYS)));
 
-                       ///@todo use parent folder instead of desktop
-                       CHECKERROR(ShellFolderContextMenu(GetDesktopFolder(), _hwnd, 1, &pidl, pptScreen->x, pptScreen->y));
+                       if (lpdi->item.mask & TVIF_SELECTEDIMAGE)
+                               lpdi->item.iSelectedImage = get_image_idx(
+                                               entry->safe_extract_icon((ICONCACHE_FLAGS)(ICF_HICON|ICF_OVERLAYS|ICF_OPEN)));
                }
        }
 }
 
-void ShellBrowserChild::OnTreeGetDispInfo(int idCtrl, LPNMHDR pnmh)
+int ShellBrowser::get_image_idx(int icon_id)
 {
-       CONTEXT("ShellBrowserChild::OnTreeGetDispInfo()");
+       if (icon_id != ICID_NONE) {
+               map<int,int>::const_iterator found = _image_map.find(icon_id);
 
-       LPNMTVDISPINFO lpdi = (LPNMTVDISPINFO)pnmh;
-       ShellEntry* entry = (ShellEntry*)lpdi->item.lParam;
+               if (found != _image_map.end())
+                       return found->second;
 
-       if (lpdi->item.mask & TVIF_TEXT)
-               lpdi->item.pszText = entry->_display_name;
+               int idx = ImageList_AddIcon(_himl, g_Globals._icon_cache.get_icon(icon_id).get_hicon());
 
-       if (lpdi->item.mask & (/*TVIF_TEXT|*/TVIF_IMAGE|TVIF_SELECTEDIMAGE)) {
-               ShellPath pidl_abs = entry->create_absolute_pidl();     // Caching of absolute PIDLs could enhance performance.
-               LPCITEMIDLIST pidl = pidl_abs;
+               _image_map[icon_id] = idx;
 
-               SHFILEINFO sfi;
-/*
-               if (lpdi->item.mask & TVIF_TEXT)
-                       if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_DISPLAYNAME))
-                               lstrcpy(lpdi->item.pszText, sfi.szDisplayName); ///@todo look at cchTextMax if there is enough space available
-                       else
-                               lpdi->item.pszText = entry->_data.cFileName;
-*/
-               if (lpdi->item.mask & TVIF_IMAGE)
-                       if ((HIMAGELIST)SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_LINKOVERLAY) == _himlSmall)
-                               lpdi->item.iImage = sfi.iIcon;
-                       else
-                               lpdi->item.iImage = -1;
+               return idx;
+       } else
+               return -1;
+}
 
-               if (lpdi->item.mask & TVIF_SELECTEDIMAGE)
-                       if ((HIMAGELIST)SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_OPENICON) == _himlSmall)
-                               lpdi->item.iSelectedImage = sfi.iIcon;
-                       else
-                               lpdi->item.iSelectedImage = -1;
-       }
+void ShellBrowser::invalidate_cache()
+{
+       (void)TreeView_SetImageList(_left_hwnd, _himl_old, TVSIL_NORMAL);
+       ImageList_Destroy(_himl);
+
+       _himl_old = TreeView_SetImageList(_left_hwnd, _himl, TVSIL_NORMAL);
+       _himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK|ILC_COLOR24, 2, 0);
+
+       for(map<int,int>::const_iterator it=_image_map.begin(); it!=_image_map.end(); ++it)
+               g_Globals._icon_cache.free_icon(it->first);
+
+       _image_map.clear();
 }
 
-void ShellBrowserChild::OnTreeItemExpanding(int idCtrl, LPNMTREEVIEW pnmtv)
+void ShellBrowser::OnTreeItemExpanding(int idCtrl, LPNMTREEVIEW pnmtv)
 {
-       CONTEXT("ShellBrowserChild::OnTreeItemExpanding()");
+       CONTEXT("ShellBrowser::OnTreeItemExpanding()");
 
        if (pnmtv->action == TVE_COLLAPSE)
         TreeView_Expand(_left_hwnd, pnmtv->itemNew.hItem, TVE_COLLAPSE|TVE_COLLAPSERESET);
@@ -284,9 +309,9 @@ void ShellBrowserChild::OnTreeItemExpanding(int idCtrl, LPNMTREEVIEW pnmtv)
        }
 }
 
-int ShellBrowserChild::InsertSubitems(HTREEITEM hParentItem, Entry* entry, IShellFolder* pParentFolder)
+int ShellBrowser::InsertSubitems(HTREEITEM hParentItem, Entry* entry, IShellFolder* pParentFolder)
 {
-       CONTEXT("ShellBrowserChild::InsertSubitems()");
+       CONTEXT("ShellBrowser::InsertSubitems()");
 
        WaitCursor wait;
 
@@ -326,7 +351,7 @@ int ShellBrowserChild::InsertSubitems(HTREEITEM hParentItem, Entry* entry, IShel
                        tvInsert.hInsertAfter = TVI_LAST;
                        tvInsert.hParent = hParentItem;
 
-                       TreeView_InsertItem(_left_hwnd, &tvInsert);
+                       (void)TreeView_InsertItem(_left_hwnd, &tvInsert);
                }
 
                ++cnt;
@@ -337,19 +362,21 @@ int ShellBrowserChild::InsertSubitems(HTREEITEM hParentItem, Entry* entry, IShel
        return cnt;
 }
 
-void ShellBrowserChild::OnTreeItemSelected(int idCtrl, LPNMTREEVIEW pnmtv)
+void ShellBrowser::OnTreeItemSelected(int idCtrl, LPNMTREEVIEW pnmtv)
 {
-       CONTEXT("ShellBrowserChild::OnTreeItemSelected()");
+       CONTEXT("ShellBrowser::OnTreeItemSelected()");
+
+       ShellEntry* entry = (ShellEntry*)pnmtv->itemNew.lParam;
 
        _last_sel = pnmtv->itemNew.hItem;
-       Entry* entry = (Entry*)pnmtv->itemNew.lParam;
 
-       jump_to(entry);
+       if (entry)
+               _callback->entry_selected(entry);
 }
 
-void ShellBrowserChild::UpdateFolderView(IShellFolder* folder)
+void ShellBrowser::UpdateFolderView(IShellFolder* folder)
 {
-       CONTEXT("ShellBrowserChild::UpdateFolderView()");
+       CONTEXT("ShellBrowser::UpdateFolderView()");
 
        FOLDERSETTINGS fs;
        IShellView* pLastShellView = _pShellView;
@@ -360,10 +387,21 @@ void ShellBrowserChild::UpdateFolderView(IShellFolder* folder)
                pLastShellView->GetCurrentInfo(&fs);
        else {
                fs.ViewMode = _create_info._open_mode&OWM_DETAILS? FVM_DETAILS: FVM_ICON;
-               fs.fFlags = FWF_BESTFITWINDOW;
+               fs.fFlags = FWF_NOCLIENTEDGE|FWF_BESTFITWINDOW;
        }
 
+#ifndef __MINGW32__    // IShellFolderViewCB missing in MinGW (as of 25.09.2005)
+       SFV_CREATE sfv_create;
+
+       sfv_create.cbSize = sizeof(SFV_CREATE);
+       sfv_create.pshf = folder;
+       sfv_create.psvOuter = NULL;
+       sfv_create.psfvcb = this;
+
+       HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);
+#else
        HRESULT hr = folder->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
+#endif
 
        if (FAILED(hr)) {
                _pShellView = NULL;
@@ -378,185 +416,37 @@ void ShellBrowserChild::UpdateFolderView(IShellFolder* folder)
                pLastShellView->UIActivate(SVUIA_DEACTIVATE);
                pLastShellView->DestroyViewWindow();
                pLastShellView->Release();
-
-               resize_children();
        }
 
        _pShellView->UIActivate(SVUIA_ACTIVATE_NOFOCUS);
 }
 
 
-void ShellBrowserChild::resize_children()
-{
-       RECT rect = _clnt_rect;
-
-       HDWP hdwp = BeginDeferWindowPos(2);
-
-       int cx = rect.left;
-
-       if (_left_hwnd) {
-               cx = _split_pos + SPLIT_WIDTH/2;
-
-               hdwp = DeferWindowPos(hdwp, _left_hwnd, 0, rect.left, rect.top, _split_pos-SPLIT_WIDTH/2-rect.left, rect.bottom-rect.top, SWP_NOZORDER|SWP_NOACTIVATE);
-       } else {
-               _split_pos = 0;
-               cx = 0;
-       }
-
-       if (_right_hwnd)
-               hdwp = DeferWindowPos(hdwp, _right_hwnd, 0, rect.left+cx+1, rect.top, rect.right-cx, rect.bottom-rect.top, SWP_NOZORDER|SWP_NOACTIVATE);
-
-       EndDeferWindowPos(hdwp);
-}
-
-
-LRESULT ShellBrowserChild::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
-{
-       switch(nmsg) {
-         case WM_GETISHELLBROWSER:     // for Registry Explorer Plugin
-               return (LRESULT)static_cast<IShellBrowser*>(this);
-
-
-               // SDI integration:
-
-         case WM_PAINT: {
-               PaintCanvas canvas(_hwnd);
-               ClientRect rt(_hwnd);
-               rt.left = _split_pos-SPLIT_WIDTH/2;
-               rt.right = _split_pos+SPLIT_WIDTH/2+1;
-
-               if (_right_hwnd) {
-                       WindowRect right_rect(_right_hwnd);
-                       ScreenToClient(_hwnd, &right_rect);
-                       rt.top = right_rect.top;
-                       rt.bottom = right_rect.bottom;
-               }
-
-               HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(COLOR_SPLITBAR));
-               Rectangle(canvas, rt.left, rt.top-1, rt.right, rt.bottom+1);
-               SelectObject(canvas, lastBrush);
-               break;}
-
-         case WM_SETCURSOR:
-               if (LOWORD(lparam) == HTCLIENT) {
-                       POINT pt;
-                       GetCursorPos(&pt);
-                       ScreenToClient(_hwnd, &pt);
-
-                       if (pt.x>=_split_pos-SPLIT_WIDTH/2 && pt.x<_split_pos+SPLIT_WIDTH/2+1) {
-                               SetCursor(LoadCursor(0, IDC_SIZEWE));
-                               return TRUE;
-                       }
-               }
-               goto def;
-
-         case WM_LBUTTONDOWN: {
-               int x = GET_X_LPARAM(lparam);
-
-               ClientRect rt(_hwnd);
-
-               if (x>=_split_pos-SPLIT_WIDTH/2 && x<_split_pos+SPLIT_WIDTH/2+1) {
-                       _last_split = _split_pos;
-                       SetCapture(_hwnd);
-               }
-
-               break;}
-
-         case WM_LBUTTONUP:
-               if (GetCapture() == _hwnd)
-                       ReleaseCapture();
-               break;
-
-         case WM_KEYDOWN:
-               if (wparam == VK_ESCAPE)
-                       if (GetCapture() == _hwnd) {
-                               _split_pos = _last_split;
-                               resize_children();
-                               _last_split = -1;
-                               ReleaseCapture();
-                               SetCursor(LoadCursor(0, IDC_ARROW));
-                       }
-               break;
-
-         case WM_MOUSEMOVE:
-               if (GetCapture() == _hwnd) {
-                       int x = LOWORD(lparam);
-
-                       ClientRect rt(_hwnd);
-
-                       if (x>=0 && x<rt.right) {
-                               _split_pos = x;
-                               resize_children();
-                               rt.left = x-SPLIT_WIDTH/2;
-                               rt.right = x+SPLIT_WIDTH/2+1;
-                               InvalidateRect(_hwnd, &rt, FALSE);
-                               UpdateWindow(_left_hwnd);
-                               UpdateWindow(_hwnd);
-                               UpdateWindow(_right_hwnd);
-                       }
-               }
-               break;
-
-
-         default: def:
-               return DefWindowProc(_hwnd, nmsg, wparam, lparam);
-       }
+#ifndef __MINGW32__    // IShellFolderViewCB missing in MinGW (as of 25.09.2005)
 
-       return 0;
-}
-
-int ShellBrowserChild::Command(int id, int code)
+ /// shell view callback
+HRESULT STDMETHODCALLTYPE ShellBrowser::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-       switch(id) {
-         case ID_BROWSE_BACK:
-               break;//@todo
-
-         case ID_BROWSE_FORWARD:
-               break;//@todo
-
-         case ID_BROWSE_UP:
-               if (_left_hwnd) {
-                       //@@ not necessary in this simply case: jump_to(_cur_dir->_up);
-
-                        //@@ -> move into jump_to()
-                       HTREEITEM hitem = TreeView_GetParent(_left_hwnd, _last_sel);
-
-                       if (hitem)
-                               TreeView_SelectItem(_left_hwnd, hitem); // sends TVN_SELCHANGED notification
-               } else {
-                       if (_cur_dir->_up)
-                               jump_to(_cur_dir->_up);
-               }
-               break;
-
-         default:
-               return 1;
+       if (uMsg == SFVM_INITMENUPOPUP) {
+               //@todo never reached
+               InsertMenu((HMENU)lParam, 0, MF_BYPOSITION, 12345, TEXT("TEST ENTRY"));
+               return S_OK;
        }
 
-       return 0;
+       return E_NOTIMPL;
 }
 
-int ShellBrowserChild::Notify(int id, NMHDR* pnmh)
-{
-       switch(pnmh->code) {
-         case TVN_GETDISPINFO:         OnTreeGetDispInfo(id, pnmh);                                    break;
-         case TVN_ITEMEXPANDING:       OnTreeItemExpanding(id, (LPNMTREEVIEW)pnmh);    break;
-         case TVN_SELCHANGED:          OnTreeItemSelected(id, (LPNMTREEVIEW)pnmh);             break;
-         case NM_RCLICK:                       OnTreeItemRClick(id, pnmh);                                             break;
-       }
-
-       return 0;
-}
+#endif
 
 
-HRESULT ShellBrowserChild::OnDefaultCommand(LPIDA pida)
+HRESULT ShellBrowser::OnDefaultCommand(LPIDA pida)
 {
-       CONTEXT("ShellBrowserChild::OnDefaultCommand()");
+       CONTEXT("ShellBrowser::OnDefaultCommand()");
 
        if (pida->cidl >= 1) {
                if (_left_hwnd) {       // explorer mode
-                       //@@if (_last_sel) {
-                               ShellDirectory* parent = _cur_dir;//@@(ShellDirectory*)TreeView_GetItemData(_left_hwnd, _last_sel);
+                       if (_last_sel) {
+                               ShellDirectory* parent = (ShellDirectory*)TreeView_GetItemData(_left_hwnd, _last_sel);
 
                                if (parent) {
                                        try {
@@ -572,12 +462,12 @@ HRESULT ShellBrowserChild::OnDefaultCommand(LPIDA pida)
 
                                        if (entry && (entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
                                                if (entry->_etype == ET_SHELL)
-                                                       if (expand_folder(static_cast<ShellDirectory*>(entry)))
+                                                       if (_last_sel && select_entry(_last_sel, entry))
                                                                return S_OK;
                                }
-                       //@@}
+                       }
                } else { // no tree control
-                       if (MainFrame::OpenShellFolders(pida, _hWndFrame))
+                       if (MainFrameBase::OpenShellFolders(pida, _hWndFrame))
                                return S_OK;
 
 /* create new Frame Window
@@ -591,96 +481,230 @@ HRESULT ShellBrowserChild::OnDefaultCommand(LPIDA pida)
 }
 
 
-bool ShellBrowserChild::expand_folder(ShellDirectory* entry)
+HTREEITEM ShellBrowser::select_entry(HTREEITEM hitem, Entry* entry, bool expand)
 {
-       CONTEXT("ShellBrowserChild::expand_folder()");
+       CONTEXT("ShellBrowser::select_entry()");
 
-       //HTREEITEM hitem_sel = TreeView_GetSelection(_left_hwnd);
-       if (!_last_sel)
-               return false;
+       if (expand && !TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND))
+               return 0;
 
-       if (!TreeView_Expand(_left_hwnd, _last_sel, TVE_EXPAND))
-               return false;
+       for(hitem=TreeView_GetChild(_left_hwnd,hitem); hitem; hitem=TreeView_GetNextSibling(_left_hwnd,hitem)) {
+               if ((Entry*)TreeView_GetItemData(_left_hwnd,hitem) == entry) {
+                       if (TreeView_SelectItem(_left_hwnd, hitem)) {
+                               if (expand)
+                                       TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND);
 
-       for(HTREEITEM hitem=TreeView_GetChild(_left_hwnd,_last_sel); hitem; hitem=TreeView_GetNextSibling(_left_hwnd,hitem)) {
-               if ((ShellDirectory*)TreeView_GetItemData(_left_hwnd,hitem) == entry) {
-                       if (TreeView_SelectItem(_left_hwnd, hitem) &&
-                               TreeView_Expand(_left_hwnd, hitem, TVE_EXPAND))
-                               return true;
+                               return hitem;
+                       }
 
                        break;
                }
        }
 
+       return 0;
+}
+
+
+bool ShellBrowser::jump_to_pidl(LPCITEMIDLIST pidl)
+{
+       if (!_root._entry)
+               return false;
+
+        // iterate through the hierarchy and open all folders to reach pidl
+       WaitCursor wait;
+
+       HTREEITEM hitem = TreeView_GetRoot(_left_hwnd);
+       Entry* entry = _root._entry;
+
+       for(const void*p=pidl;;) {
+               if (!p)
+                       return true;
+
+               if (!entry || !hitem)
+                       break;
+
+               entry->smart_scan(SORT_NAME);
+
+               Entry* found = entry->find_entry(p);
+               p = entry->get_next_path_component(p);
+
+               if (found)
+                       hitem = select_entry(hitem, found);
+
+               entry = found;
+       }
+
        return false;
 }
 
 
-void ShellBrowserChild::jump_to(LPCTSTR path)
+#ifndef _NO_MDI
+
+MDIShellBrowserChild::MDIShellBrowserChild(HWND hwnd, const ShellChildWndInfo& info)
+ :     super(hwnd, info),
+       _create_info(info),
+       _shellpath_info(info)   //@@ copies info -> no referenz to _create_info !
 {
-       ///@todo implement "file://", ... parsing
-       jump_to(ShellPath(path));
+/**todo Conversion of shell path into path string -> store into URL history
+       const String& path = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORADDRESSBAR);
+       const String& parsingpath = GetDesktopFolder().get_name(info._shell_path, SHGDN_FORPARSING);
+
+        // store path into history
+       if (info._path && *info._path)
+               _url_history.push(info._path);
+*/
 }
 
 
-void ShellBrowserChild::jump_to(LPCITEMIDLIST pidl)
+MDIShellBrowserChild* MDIShellBrowserChild::create(const ShellChildWndInfo& info)
 {
-       Entry* entry = NULL;
+       ChildWindow* child = ChildWindow::create(info, info._pos.rcNormalPosition,
+               WINDOW_CREATOR_INFO(MDIShellBrowserChild,ShellChildWndInfo), CLASSNAME_CHILDWND, NULL, info._pos.showCmd==SW_SHOWMAXIMIZED? WS_MAXIMIZE: 0);
 
-        //@@
-       if (!_cur_dir)
-               _cur_dir = static_cast<ShellDirectory*>(_root._entry);
+       return static_cast<MDIShellBrowserChild*>(child);
+}
 
-/*@todo
-       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
-       _root._entry->read_tree(shell_info._root_shell_path.get_folder(), info._shell_path, SORT_NAME);
-       -> see FileChildWindow::FileChildWindow()
-*/
 
-       if (_cur_dir) {
-               static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST, LPCITEMIDLIST)> ILFindChild(TEXT("SHELL32"), 24);
+LRESULT MDIShellBrowserChild::Init(LPCREATESTRUCT pcs)
+{
+       CONTEXT("MDIShellBrowserChild::Init()");
 
-               LPCITEMIDLIST child_pidl;
+       if (super::Init(pcs))
+               return 1;
 
-               if (ILFindChild)
-                       child_pidl = (*ILFindChild)(_cur_dir->create_absolute_pidl(), pidl);
+       update_shell_browser();
+
+       if (_shellBrowser.get())
+               if (_left_hwnd)
+                       _shellBrowser->Init();
                else
-                       child_pidl = pidl;      // This is not correct in the common case, but works on the desktop level.
+                       _shellBrowser->UpdateFolderView(_create_info._shell_path.get_folder());
 
-               if (child_pidl) {
-                       _cur_dir->smart_scan();
+       return 0;
+}
 
-                       entry = _cur_dir->find_entry(child_pidl);
 
-                       if (entry)
-                               jump_to(entry);
+LRESULT MDIShellBrowserChild::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
+{
+       switch(nmsg) {
+         case PM_DISPATCH_COMMAND: {
+               switch(LOWORD(wparam)) {
+                 case ID_WINDOW_NEW: {CONTEXT("MDIShellBrowserChild PM_DISPATCH_COMMAND ID_WINDOW_NEW");
+                       MDIShellBrowserChild::create(_create_info);
+                       break;}
+
+                 case ID_REFRESH:
+                       //@todo refresh shell child
+                       _shellBrowser->invalidate_cache();
+                       break;
+
+                 case ID_VIEW_SDI:
+                       MainFrameBase::Create(ExplorerCmd(_url, false));
+                       break;
+
+                 default:
+                       return super::WndProc(nmsg, wparam, lparam);
                }
+               return TRUE;}
+       
+         default:
+               return super::WndProc(nmsg, wparam, lparam);
        }
 
-               //@@ work around as long as we don't iterate correctly through the ShellEntry tree
-       if (!entry) {
-               UpdateFolderView(ShellFolder(pidl));
+       return 0;
+}
+
+void MDIShellBrowserChild::update_shell_browser()
+{
+       int split_pos = DEFAULT_SPLIT_POS;
+
+       if (_shellBrowser.get()) {
+               split_pos = _split_pos;
+               delete _shellBrowser.release();
+       }
+
+       ///@todo use OWM_ROOTED flag
+
+        // create explorer treeview
+       if (_create_info._open_mode & OWM_EXPLORE) {
+               if (!_left_hwnd) {
+                       ClientRect rect(_hwnd);
+
+                       _left_hwnd = CreateWindowEx(0, WC_TREEVIEW, NULL,
+                                                       WS_CHILD|WS_TABSTOP|WS_VISIBLE|WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS,//|TVS_NOTOOLTIPS
+                                                       0, rect.top, split_pos-SPLIT_WIDTH/2, rect.bottom-rect.top,
+                                                       _hwnd, (HMENU)IDC_FILETREE, g_Globals._hInstance, 0);
+               }
+       } else {
+               if (_left_hwnd) {
+                       DestroyWindow(_left_hwnd);
+                       _left_hwnd = 0;
+               }
        }
+
+       _shellBrowser = auto_ptr<ShellBrowser>(new ShellBrowser(_hwnd, _left_hwnd, _right_hwnd,
+                                                                                               _shellpath_info, this, _cm_ifs));
+
+       _shellBrowser->Init(_hwndFrame);
 }
 
-void ShellBrowserChild::jump_to(Entry* entry)
+
+String MDIShellBrowserChild::jump_to_int(LPCTSTR url)
+{
+       String dir, fname;
+
+       if (!_tcsnicmp(url, TEXT("shell://"), 8)) {
+               if (_shellBrowser->jump_to_pidl(ShellPath(url+8)))
+                       return url;
+       }
+
+       if (SplitFileSysURL(url, dir, fname)) {
+
+               ///@todo use fname
+
+               if (_shellBrowser->jump_to_pidl(ShellPath(dir)))
+                       return FmtString(TEXT("file://%s"), (LPCTSTR)dir);
+       }
+       
+       return String();
+}
+
+
+void MDIShellBrowserChild::entry_selected(Entry* entry)
 {
        if (entry->_etype == ET_SHELL) {
+               ShellEntry* shell_entry = static_cast<ShellEntry*>(entry);
                IShellFolder* folder;
-               ShellDirectory* se = static_cast<ShellDirectory*>(entry);
 
-               if (se->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                       folder = static_cast<ShellDirectory*>(se)->_folder;
+               if (shell_entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                       folder = static_cast<ShellDirectory*>(shell_entry)->_folder;
                else
-                       folder = se->get_parent_folder();
+                       folder = shell_entry->get_parent_folder();
 
                if (!folder) {
                        assert(folder);
                        return;
                }
 
-               UpdateFolderView(folder);
+               TCHAR path[MAX_PATH];
+
+               if (shell_entry->get_path(path, COUNTOF(path))) {
+                       String url;
+
+                       if (path[0] == ':')
+                               url.printf(TEXT("shell://%s"), path);
+                       else
+                               url.printf(TEXT("file://%s"), path);
+
+                       set_url(url);
+               }
+
+               _shellBrowser->UpdateFolderView(folder);
 
-               _cur_dir = se;
+                // set size of new created shell view windows
+               ClientRect rt(_hwnd);
+               resize_children(rt.right, rt.bottom);
        }
 }
+
+#endif