[PATCH 2/5] shell32: Add a travellog to the ExplorerBrowser control.

David Hedberg david.hedberg at gmail.com
Wed Aug 25 08:24:33 CDT 2010


---
 dlls/shell32/ebrowser.c       |  138 +++++++++++++++++++++++++++++++++++++++-
 dlls/shell32/tests/ebrowser.c |   24 +++++++-
 2 files changed, 156 insertions(+), 6 deletions(-)

diff --git a/dlls/shell32/ebrowser.c b/dlls/shell32/ebrowser.c
index 0d11d13..e753a79 100644
--- a/dlls/shell32/ebrowser.c
+++ b/dlls/shell32/ebrowser.c
@@ -43,6 +43,11 @@ typedef struct _event_client {
     DWORD cookie;
 } event_client;
 
+typedef struct _travellog_entry {
+    struct list entry;
+    LPITEMIDLIST pidl;
+} travellog_entry;
+
 typedef struct _ExplorerBrowserImpl {
     const IExplorerBrowserVtbl *lpVtbl;
     const IShellBrowserVtbl *lpsbVtbl;
@@ -57,6 +62,9 @@ typedef struct _ExplorerBrowserImpl {
 
     struct list event_clients;
     DWORD events_next_cookie;
+    struct list travellog;
+    travellog_entry *travellog_cursor;
+    int travellog_count;
 
     IShellView *psv;
     RECT sv_rc;
@@ -140,6 +148,99 @@ static void events_ViewCreated(ExplorerBrowserImpl *This, IShellView *psv)
 }
 
 /**************************************************************************
+ * Travellog functions.
+ */
+static void travellog_remove_entry(ExplorerBrowserImpl *This, travellog_entry *entry)
+{
+    TRACE("Removing %p\n", entry);
+
+    list_remove(&entry->entry);
+    HeapFree(GetProcessHeap(), 0, entry);
+    This->travellog_count--;
+}
+
+static void travellog_remove_all_entries(ExplorerBrowserImpl *This)
+{
+    travellog_entry *cursor, *cursor2;
+    TRACE("%p\n", This);
+
+    LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->travellog, travellog_entry, entry)
+        travellog_remove_entry(This, cursor);
+
+    This->travellog_cursor = NULL;
+}
+
+static void travellog_add_entry(ExplorerBrowserImpl *This, LPITEMIDLIST pidl)
+{
+    travellog_entry *new, *cursor, *cursor2;
+    TRACE("%p (old count %d)\n", pidl, This->travellog_count);
+
+    /* Replace the old tail, if any, with the new entry */
+    if(This->travellog_cursor)
+    {
+        LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, &This->travellog, travellog_entry, entry)
+        {
+            if(cursor == This->travellog_cursor)
+                break;
+            travellog_remove_entry(This, cursor);
+        }
+    }
+
+    /* Create and add the new entry */
+    new = HeapAlloc(GetProcessHeap(), 0, sizeof(travellog_entry));
+    new->pidl = ILClone(pidl);
+    list_add_tail(&This->travellog, &new->entry);
+    This->travellog_cursor = new;
+    This->travellog_count++;
+
+    /* Remove the first few entries if the size limit is reached. */
+    if(This->travellog_count > 200)
+    {
+        UINT i = 0;
+        LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->travellog, travellog_entry, entry)
+        {
+            if(i++ > 10)
+                break;
+            travellog_remove_entry(This, cursor);
+        }
+    }
+}
+
+static LPCITEMIDLIST travellog_go_back(ExplorerBrowserImpl *This)
+{
+    travellog_entry *prev;
+    TRACE("%p, %p\n", This, This->travellog_cursor);
+
+    if(!This->travellog_cursor)
+        return NULL;
+
+    prev = LIST_ENTRY(list_prev(&This->travellog, &This->travellog_cursor->entry),
+                      travellog_entry, entry);
+    if(!prev)
+        return NULL;
+
+    This->travellog_cursor = prev;
+    return prev->pidl;
+}
+
+static LPCITEMIDLIST travellog_go_forward(ExplorerBrowserImpl *This)
+{
+    travellog_entry *next;
+    TRACE("%p, %p\n", This, This->travellog_cursor);
+
+    if(!This->travellog_cursor)
+        return NULL;
+
+    next = LIST_ENTRY(list_next(&This->travellog, &This->travellog_cursor->entry),
+                      travellog_entry, entry);
+    if(!next)
+        return NULL;
+
+    This->travellog_cursor = next;
+    return next->pidl;
+}
+
+/**************************************************************************
  * Helper functions
  */
 static void update_layout(ExplorerBrowserImpl *This)
@@ -386,6 +487,7 @@ static HRESULT WINAPI IExplorerBrowser_fnDestroy(IExplorerBrowser *iface)
     }
 
     events_unadvise_all(This);
+    travellog_remove_all_entries(This);
 
     ILFree(This->current_pidl);
     This->current_pidl = NULL;
@@ -520,9 +622,6 @@ static HRESULT WINAPI IExplorerBrowser_fnGetOptions(IExplorerBrowser *iface,
     return S_OK;
 }
 
-static const UINT unsupported_browse_flags =
-    SBSP_NAVIGATEBACK | SBSP_NAVIGATEFORWARD | SBSP_NEWBROWSER |
-    EBF_SELECTFROMDATAOBJECT | EBF_NODROPTARGET;
 static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
                                                         PCUIDLIST_RELATIVE pidl,
                                                         UINT uFlags)
@@ -530,6 +629,8 @@ static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
     LPITEMIDLIST absolute_pidl = NULL;
     HRESULT hr;
+    static const UINT unsupported_browse_flags =
+        SBSP_NEWBROWSER | EBF_SELECTFROMDATAOBJECT | EBF_NODROPTARGET;
     TRACE("%p (%p, 0x%x)\n", This, pidl, uFlags);
 
     if(!This->hwnd_main)
@@ -547,7 +648,27 @@ static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
     if(uFlags & unsupported_browse_flags)
         FIXME("Argument 0x%x contains unsupported flags.\n", uFlags);
 
-    if(uFlags & SBSP_PARENT)
+    if(uFlags & SBSP_NAVIGATEBACK)
+    {
+        TRACE("SBSP_NAVIGATEBACK\n");
+        absolute_pidl = ILClone(travellog_go_back(This));
+        if(!absolute_pidl && !This->current_pidl)
+            return E_FAIL;
+        else if(!absolute_pidl)
+            return S_OK;
+
+    }
+    else if(uFlags & SBSP_NAVIGATEFORWARD)
+    {
+        TRACE("SBSP_NAVIGATEFORWARD\n");
+        absolute_pidl = ILClone(travellog_go_forward(This));
+        if(!absolute_pidl && !This->current_pidl)
+            return E_FAIL;
+        else if(!absolute_pidl)
+            return S_OK;
+
+    }
+    else if(uFlags & SBSP_PARENT)
     {
         if(This->current_pidl)
         {
@@ -618,6 +739,14 @@ static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
                 IShellItem_Release(psi);
                 return E_FAIL;
             }
+
+            /* Add to travellog */
+            if( !(This->eb_options & EBO_NOTRAVELLOG) &&
+                !(uFlags & (SBSP_NAVIGATEFORWARD|SBSP_NAVIGATEBACK)) )
+            {
+                travellog_add_entry(This, absolute_pidl);
+            }
+
             IShellItem_Release(psi);
         }
     }
@@ -928,6 +1057,7 @@ HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, voi
     eb->lpsbVtbl = &vt_IShellBrowser;
 
     list_init(&eb->event_clients);
+    list_init(&eb->travellog);
 
     ret = IExplorerBrowser_QueryInterface((IExplorerBrowser*)eb, riid, ppv);
     IExplorerBrowser_Release((IExplorerBrowser*)eb);
diff --git a/dlls/shell32/tests/ebrowser.c b/dlls/shell32/tests/ebrowser.c
index 442d8dc..809a7fc 100644
--- a/dlls/shell32/tests/ebrowser.c
+++ b/dlls/shell32/tests/ebrowser.c
@@ -811,14 +811,34 @@ static void test_navigation(void)
     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
 
     /* "The first browse is synchronous" */
     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
 
+    /* Navigate empty history */
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
+
+    /* Navigate history */
+    test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+
     /* Relative navigation */
-    test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
-    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
 
     hr = IExplorerBrowser_GetCurrentView(peb, &IID_IFolderView, (void**)&pfv);
     ok(hr == S_OK, "Got 0x%08x\n", hr);
-- 
1.7.2




More information about the wine-patches mailing list