diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 18:05:56 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 18:05:56 +0000 |
commit | 8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3 (patch) | |
tree | 938304b8e1be417c1b9c73d7463dacbc1da79843 /chrome/browser/sidebar | |
parent | f2c4ee3627e6039fd42bd7c0c93e902b72653449 (diff) | |
download | chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.zip chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.tar.gz chromium_src-8b8e7c9bce4198a4ee2865d9dfce6e8baa173ad3.tar.bz2 |
Initial version of chrome.experimental.sidebar extension API.
BUG=51084
TEST=Run interactive_ui_tests and browser_tests.
New:
- sidebar Extension API (design doc: https://docs.google.com/a/google.com/Doc?docid=0AV4Qg3xyZ8RQZGZtbWIydDJfNWc0eHJtbmRm&hl=en);
- Sidebar panel in Chrome browser view;
Original review=http://codereview.chromium.org/2836040/show
Patch by alekseys@google.com
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56716 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sidebar')
-rw-r--r-- | chrome/browser/sidebar/sidebar_container.cc | 73 | ||||
-rw-r--r-- | chrome/browser/sidebar/sidebar_container.h | 141 | ||||
-rw-r--r-- | chrome/browser/sidebar/sidebar_manager.cc | 323 | ||||
-rw-r--r-- | chrome/browser/sidebar/sidebar_manager.h | 156 | ||||
-rw-r--r-- | chrome/browser/sidebar/sidebar_test.cc | 177 |
5 files changed, 870 insertions, 0 deletions
diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc new file mode 100644 index 0000000..4c73110 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_container.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sidebar/sidebar_container.h" + +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/common/bindings_policy.h" +#include "googleurl/src/gurl.h" +#include "third_party/skia/include/core/SkBitmap.h" + +SidebarContainer::SidebarContainer(TabContents* tab, + const std::string& content_id, + Delegate* delegate) + : tab_(tab), + content_id_(content_id), + delegate_(delegate), + icon_(new SkBitmap) { + // Create TabContents for sidebar. + sidebar_contents_.reset( + new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL)); + sidebar_contents_->render_view_host()->set_is_extension_process(true); + sidebar_contents_->render_view_host()->AllowBindings( + BindingsPolicy::EXTENSION); + sidebar_contents_->set_delegate(this); +} + +SidebarContainer::~SidebarContainer() { +} + +void SidebarContainer::SidebarClosing() { + delegate_->UpdateSidebar(this); +} + +int SidebarContainer::GetTabId() const { + return tab_->controller().session_id().id(); +} + +void SidebarContainer::Show() { + delegate_->UpdateSidebar(this); +} + +void SidebarContainer::Expand() { + delegate_->UpdateSidebar(this); + sidebar_contents_->view()->SetInitialFocus(); +} + +void SidebarContainer::Collapse() { + delegate_->UpdateSidebar(this); +} + +void SidebarContainer::Navigate(const GURL& url) { + DCHECK(sidebar_contents_.get()); + // TODO(alekseys): add a progress UI. + sidebar_contents_->controller().LoadURL( + url, GURL(), PageTransition::START_PAGE); +} + +void SidebarContainer::SetBadgeText(const string16& badge_text) { + badge_text_ = badge_text; +} + +void SidebarContainer::SetIcon(const SkBitmap& bitmap) { + *icon_ = bitmap; +} + +void SidebarContainer::SetTitle(const string16& title) { + title_ = title; +} diff --git a/chrome/browser/sidebar/sidebar_container.h b/chrome/browser/sidebar/sidebar_container.h new file mode 100644 index 0000000..152331d --- /dev/null +++ b/chrome/browser/sidebar/sidebar_container.h @@ -0,0 +1,141 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ +#define CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "chrome/browser/tab_contents/tab_contents_delegate.h" + +class BrowserWindow; +class Profile; +class RenderViewHost; +class SkBitmap; +class TabContents; + +/////////////////////////////////////////////////////////////////////////////// +// SidebarContainer +// +// Stores one particular sidebar state: sidebar's content, its content id, +// tab it is linked to, mini tab icon, title etc. +// +class SidebarContainer + : public TabContentsDelegate { + public: + // Interface to implement to listen for sidebar update notification. + class Delegate { + public: + Delegate() {} + virtual ~Delegate() {} + virtual void UpdateSidebar(SidebarContainer* host) = 0; + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + SidebarContainer(TabContents* tab, const std::string& content_id, + Delegate* delegate); + virtual ~SidebarContainer(); + + // Called right before destroying this sidebar. + // Does all the necessary cleanup. + void SidebarClosing(); + + // Returns id of the tab this sidebar is linked to. + int GetTabId() const; + + // Returns sidebar's content id. + const std::string& content_id() const { return content_id_; } + + // Returns TabContents sidebar is linked to. + TabContents* tab_contents() const { return tab_; } + + // Returns sidebar's TabContents. + TabContents* sidebar_contents() const { return sidebar_contents_.get(); } + + // Accessor for the badge text. + const string16& badge_text() const { return badge_text_; } + + // Accessor for the icon. + const SkBitmap& icon() const { return *icon_; } + + // Accessor for the title. + const string16& title() const { return title_; } + + // Functions supporting chrome.experimental.sidebar API. + + // Notifies hosting window that this sidebar was expanded. + void Show(); + + // Notifies hosting window that this sidebar was expanded. + void Expand(); + + // Notifies hosting window that this sidebar was collapsed. + void Collapse(); + + // Navigates sidebar contents to the |url|. + void Navigate(const GURL& url); + + // Changes sidebar's badge text. + void SetBadgeText(const string16& badge_text); + + // Changes sidebar's icon. + void SetIcon(const SkBitmap& bitmap); + + // Changes sidebar's title. + void SetTitle(const string16& title); + + private: + // Overridden from TabContentsDelegate. + virtual void OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) {} + virtual void NavigationStateChanged(const TabContents* source, + unsigned changed_flags) {} + virtual void AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) {} + virtual void ActivateContents(TabContents* contents) {} + virtual void LoadingStateChanged(TabContents* source) {} + virtual void CloseContents(TabContents* source) {} + virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} + virtual bool IsPopup(TabContents* source) { return false; } + virtual void URLStarredChanged(TabContents* source, bool starred) {} + virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} + virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {} + + // Contents of the tab this sidebar is linked to. + TabContents* tab_; + + // Sidebar's content id. There might be more than one sidebar liked to each + // particular tab and they are identified by their unique content id. + const std::string content_id_; + + // Sidebar update notification listener. + Delegate* delegate_; + + // Sidebar contents. + scoped_ptr<TabContents> sidebar_contents_; + + // Badge text displayed on the sidebar's mini tab. + string16 badge_text_; + + // Icon displayed on the sidebar's mini tab. + scoped_ptr<SkBitmap> icon_; + + // Sidebar's title, displayed as a tooltip for sidebar's mini tab. + string16 title_; + + DISALLOW_COPY_AND_ASSIGN(SidebarContainer); +}; + +#endif // CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_ + diff --git a/chrome/browser/sidebar/sidebar_manager.cc b/chrome/browser/sidebar/sidebar_manager.cc new file mode 100644 index 0000000..5ec9e12 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_manager.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sidebar/sidebar_manager.h" + +#include <vector> + +#include "base/command_line.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_sidebar_api.h" +#include "chrome/browser/pref_service.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "googleurl/src/gurl.h" + +// static +SidebarManager* SidebarManager::GetInstance() { + return g_browser_process->sidebar_manager(); +} + +// static +bool SidebarManager::IsSidebarAllowed() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExperimentalExtensionApis); +} + +SidebarManager::SidebarManager() { +} + +SidebarContainer* SidebarManager::GetActiveSidebarContainerFor( + TabContents* tab) { + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return NULL; + if (it->second.active_content_id.empty()) + return NULL; + ContentIdToSidebarHostMap::iterator host_it = + it->second.content_id_to_sidebar_host.find(it->second.active_content_id); + DCHECK(host_it != it->second.content_id_to_sidebar_host.end()); + return host_it->second; +} + +SidebarContainer* SidebarManager::GetSidebarContainerFor( + TabContents* tab, const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return NULL; + ContentIdToSidebarHostMap::iterator host_it = + it->second.content_id_to_sidebar_host.find(content_id); + if (host_it == it->second.content_id_to_sidebar_host.end()) + return NULL; + return host_it->second; +} + +TabContents* SidebarManager::GetSidebarTabContents( + TabContents* tab, const std::string& content_id) { + DCHECK(!content_id.empty()); + SidebarContainer* sidebar_host = GetSidebarContainerFor(tab, content_id); + if (!sidebar_host) + return NULL; + return sidebar_host->sidebar_contents(); +} + +void SidebarManager::NotifyStateChanges( + TabContents* was_active_sidebar_contents, + TabContents* active_sidebar_contents) { + if (was_active_sidebar_contents == active_sidebar_contents) + return; + + SidebarContainer* was_active_host = + was_active_sidebar_contents == NULL ? NULL : + FindSidebarContainerFor(was_active_sidebar_contents); + SidebarContainer* active_host = + active_sidebar_contents == NULL ? NULL : + FindSidebarContainerFor(active_sidebar_contents); + + if (was_active_host != NULL) { + ExtensionSidebarEventRouter::OnStateChanged( + was_active_sidebar_contents->profile(), + was_active_host->GetTabId(), was_active_host->content_id(), + extension_sidebar_constants::kShownState); + } + + if (active_host != NULL) { + ExtensionSidebarEventRouter::OnStateChanged( + active_sidebar_contents->profile(), + active_host->GetTabId(), active_host->content_id(), + extension_sidebar_constants::kActiveState); + } +} + +void SidebarManager::ShowSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) { + host = new SidebarContainer(tab, content_id, this); + RegisterSidebarContainerFor(tab, host); + } + + host->Show(); + + ExtensionSidebarEventRouter::OnStateChanged( + tab->profile(), host->GetTabId(), content_id, + extension_sidebar_constants::kShownState); +} + +void SidebarManager::ExpandSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + // If it's already active, bail out. + if (it->second.active_content_id == content_id) + return; + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + it->second.active_content_id = content_id; + + host->Expand(); +} + +void SidebarManager::CollapseSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + // If it's not the one active now, bail out. + if (it->second.active_content_id != content_id) + return; + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + it->second.active_content_id.clear(); + + host->Collapse(); +} + +void SidebarManager::HideSidebar(TabContents* tab, + const std::string& content_id) { + DCHECK(!content_id.empty()); + TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab); + if (it == tab_to_sidebar_host_.end()) + return; + if (it->second.active_content_id == content_id) + it->second.active_content_id.clear(); + + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + int tab_id = host->GetTabId(); + + UnregisterSidebarContainerFor(tab, content_id); + + ExtensionSidebarEventRouter::OnStateChanged( + tab->profile(), tab_id, content_id, + extension_sidebar_constants::kHiddenState); +} + +void SidebarManager::NavigateSidebar(TabContents* tab, + const std::string& content_id, + const GURL& url) { + DCHECK(!content_id.empty()); + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + + host->Navigate(url); +} + +void SidebarManager::SetSidebarBadgeText( + TabContents* tab, const std::string& content_id, + const string16& badge_text) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetBadgeText(badge_text); +} + +void SidebarManager::SetSidebarIcon( + TabContents* tab, const std::string& content_id, + const SkBitmap& bitmap) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetIcon(bitmap); +} + +void SidebarManager::SetSidebarTitle( + TabContents* tab, const std::string& content_id, + const string16& title) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + if (!host) + return; + host->SetTitle(title); +} + +SidebarManager::~SidebarManager() { + DCHECK(tab_to_sidebar_host_.empty()); + DCHECK(sidebar_host_to_tab_.empty()); +} + +void SidebarManager::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::TAB_CONTENTS_DESTROYED) { + HideAllSidebars(Source<TabContents>(source).ptr()); + } else { + NOTREACHED() << "Got a notification we didn't register for!"; + } +} + +void SidebarManager::UpdateSidebar(SidebarContainer* host) { + NotificationService::current()->Notify( + NotificationType::SIDEBAR_CHANGED, + Source<SidebarManager>(this), + Details<SidebarContainer>(host)); +} + +void SidebarManager::HideAllSidebars(TabContents* tab) { + TabToSidebarHostMap::iterator tab_it = tab_to_sidebar_host_.find(tab); + if (tab_it == tab_to_sidebar_host_.end()) + return; + const ContentIdToSidebarHostMap& hosts = + tab_it->second.content_id_to_sidebar_host; + + std::vector<std::string> content_ids; + for (ContentIdToSidebarHostMap::const_iterator it = hosts.begin(); + it != hosts.end(); ++it) { + content_ids.push_back(it->first); + } + + for (std::vector<std::string>::iterator it = content_ids.begin(); + it != content_ids.end(); ++it) { + HideSidebar(tab, *it); + } +} + +SidebarContainer* SidebarManager::FindSidebarContainerFor( + TabContents* sidebar_contents) { + for (SidebarHostToTabMap::iterator it = sidebar_host_to_tab_.begin(); + it != sidebar_host_to_tab_.end(); + ++it) { + if (sidebar_contents == it->first->sidebar_contents()) + return it->first; + } + return NULL; +} + +void SidebarManager::RegisterSidebarContainerFor( + TabContents* tab, SidebarContainer* sidebar_host) { + DCHECK(!GetSidebarContainerFor(tab, sidebar_host->content_id())); + + // If it's a first sidebar for this tab, register destroy notification. + if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) { + registrar_.Add(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab)); + } + + BindSidebarHost(tab, sidebar_host); +} + +void SidebarManager::UnregisterSidebarContainerFor( + TabContents* tab, const std::string& content_id) { + SidebarContainer* host = GetSidebarContainerFor(tab, content_id); + DCHECK(host); + if (!host) + return; + + UnbindSidebarHost(tab, host); + + // If there's no more sidebars linked to this tab, unsubscribe. + if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) { + registrar_.Remove(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab)); + } + + // Issue tab closing event post unbound. + host->SidebarClosing(); + // Destroy sidebar container. + delete host; +} + +void SidebarManager::BindSidebarHost(TabContents* tab, + SidebarContainer* sidebar_host) { + const std::string& content_id = sidebar_host->content_id(); + + DCHECK(GetSidebarContainerFor(tab, content_id) == NULL); + DCHECK(sidebar_host_to_tab_.find(sidebar_host) == + sidebar_host_to_tab_.end()); + + tab_to_sidebar_host_[tab].content_id_to_sidebar_host[content_id] = + sidebar_host; + sidebar_host_to_tab_[sidebar_host] = tab; +} + +void SidebarManager::UnbindSidebarHost(TabContents* tab, + SidebarContainer* sidebar_host) { + const std::string& content_id = sidebar_host->content_id(); + + DCHECK(GetSidebarContainerFor(tab, content_id) == sidebar_host); + DCHECK(sidebar_host_to_tab_.find(sidebar_host)->second == tab); + DCHECK(tab_to_sidebar_host_[tab].active_content_id != content_id); + + tab_to_sidebar_host_[tab].content_id_to_sidebar_host.erase(content_id); + if (tab_to_sidebar_host_[tab].content_id_to_sidebar_host.empty()) + tab_to_sidebar_host_.erase(tab); + sidebar_host_to_tab_.erase(sidebar_host); +} diff --git a/chrome/browser/sidebar/sidebar_manager.h b/chrome/browser/sidebar/sidebar_manager.h new file mode 100644 index 0000000..4f3231e --- /dev/null +++ b/chrome/browser/sidebar/sidebar_manager.h @@ -0,0 +1,156 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ +#define CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ + +#include <map> +#include <set> +#include <string> + +#include "base/ref_counted.h" +#include "base/string16.h" +#include "chrome/browser/sidebar/sidebar_container.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class GURL; +class PrefService; +class Profile; +class SidebarContainer; +class SkBitmap; +class TabContents; + +/////////////////////////////////////////////////////////////////////////////// +// SidebarManager +// +// This class is a singleton that manages SidebarContainer instances and +// maintains a connection between tabs and sidebars. +// +class SidebarManager : public NotificationObserver, + public base::RefCounted<SidebarManager>, + private SidebarContainer::Delegate { + public: + // Returns s singleton instance. + static SidebarManager* GetInstance(); + + // Returns true if sidebar is allowed to be displayed in the browser. + static bool IsSidebarAllowed(); + + SidebarManager(); + + // Returns SidebarContainer registered for |tab| and active or NULL if + // there is no alive and active SidebarContainer registered for |tab|. + SidebarContainer* GetActiveSidebarContainerFor(TabContents* tab); + + // Returns SidebarContainer registered for |tab| and |content_id| or NULL if + // there is no such SidebarContainer registered. + SidebarContainer* GetSidebarContainerFor(TabContents* tab, + const std::string& content_id); + + // Returns sidebar's TabContents registered for |tab| and |content_id|. + TabContents* GetSidebarTabContents(TabContents* tab, + const std::string& content_id); + + // Sends sidebar state change notification to extensions. + void NotifyStateChanges(TabContents* was_active_sidebar_contents, + TabContents* active_sidebar_contents); + + // Functions supporting chrome.experimental.sidebar API. + + // Shows sidebar identified by |tab| and |content_id| (only sidebar's + // mini tab is visible). + void ShowSidebar(TabContents* tab, const std::string& content_id); + + // Expands sidebar identified by |tab| and |content_id|. + void ExpandSidebar(TabContents* tab, const std::string& content_id); + + // Collapses sidebar identified by |tab| and |content_id| (has no effect + // if sidebar is not expanded). + void CollapseSidebar(TabContents* tab, const std::string& content_id); + + // Hides sidebar identified by |tab| and |content_id| (removes sidebar's + // mini tab). + void HideSidebar(TabContents* tab, const std::string& content_id); + + // Navigates sidebar identified by |tab| and |content_id| to |url|. + void NavigateSidebar(TabContents* tab, const std::string& content_id, + const GURL& url); + + // Changes sidebar's badge text (displayed on the mini tab). + void SetSidebarBadgeText(TabContents* tab, const std::string& content_id, + const string16& badge_text); + + // Changes sidebar's icon (displayed on the mini tab). + void SetSidebarIcon(TabContents* tab, const std::string& content_id, + const SkBitmap& bitmap); + + // Changes sidebar's title (mini tab's tooltip). + void SetSidebarTitle(TabContents* tab, const std::string& content_id, + const string16& title); + + private: + friend class base::RefCounted<SidebarManager>; + + virtual ~SidebarManager(); + + // Overridden from NotificationObserver. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Overridden from SidebarContainer::Delegate. + virtual void UpdateSidebar(SidebarContainer* host); + + // Hides all sidebars registered for |tab|. + void HideAllSidebars(TabContents* tab); + + // Returns SidebarContainer corresponding to |sidebar_contents|. + SidebarContainer* FindSidebarContainerFor(TabContents* sidebar_contents); + + // Registers new SidebarContainer for |tab|. There must be no + // other SidebarContainers registered for the RenderViewHost at the moment. + void RegisterSidebarContainerFor(TabContents* tab, + SidebarContainer* container); + + // Unregisters SidebarContainer identified by |tab| and |content_id|. + void UnregisterSidebarContainerFor(TabContents* tab, + const std::string& content_id); + + // Records the link between |tab| and |sidebar_host|. + void BindSidebarHost(TabContents* tab, SidebarContainer* sidebar_host); + + // Forgets the link between |tab| and |sidebar_host|. + void UnbindSidebarHost(TabContents* tab, SidebarContainer* sidebar_host); + + NotificationRegistrar registrar_; + + // This map stores sidebars linked to a particular tab. Sidebars are + // identified by their unique content id (string). + typedef std::map<std::string, SidebarContainer*> + ContentIdToSidebarHostMap; + // These two maps are for tracking dependencies between tabs and + // their SidebarContainers. + // + // SidebarManager start listening to SidebarContainers when they are put + // into these maps and removes them when they are closing. + typedef struct { + // Sidebars linked to this tab. + ContentIdToSidebarHostMap content_id_to_sidebar_host; + // Content id of the currently active (expanded and visible) sidebar. + std::string active_content_id; + } SidebarStateForTab; + typedef std::map<TabContents*, SidebarStateForTab> + TabToSidebarHostMap; + TabToSidebarHostMap tab_to_sidebar_host_; + + typedef std::map<SidebarContainer*, TabContents*> + SidebarHostToTabMap; + SidebarHostToTabMap sidebar_host_to_tab_; + + DISALLOW_COPY_AND_ASSIGN(SidebarManager); +}; + +#endif // CHROME_BROWSER_SIDEBAR_SIDEBAR_MANAGER_H_ + diff --git a/chrome/browser/sidebar/sidebar_test.cc b/chrome/browser/sidebar/sidebar_test.cc new file mode 100644 index 0000000..a518587 --- /dev/null +++ b/chrome/browser/sidebar/sidebar_test.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/sidebar/sidebar_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" +#include "net/test/test_server.h" + +namespace { + +const char kSampleContentId[] = "sample_content_id"; +const char kSimplePage[] = "files/sidebar/simple_page.html"; + +class SidebarTest : public InProcessBrowserTest { + public: + SidebarTest() { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + set_show_window(true); + } + + protected: + void ShowSidebarForCurrentTab() { + ShowSidebar(browser()->GetSelectedTabContents()); + } + + void ExpandSidebarForCurrentTab() { + ExpandSidebar(browser()->GetSelectedTabContents()); + } + + void CollapseSidebarForCurrentTab() { + CollapseSidebar(browser()->GetSelectedTabContents()); + } + + void HideSidebarForCurrentTab() { + HideSidebar(browser()->GetSelectedTabContents()); + } + + void NavigateSidebarForCurrentTabTo(const std::string& test_page) { + net::TestServer* server = test_server(); + ASSERT_TRUE(server); + GURL url = server->GetURL(test_page); + + TabContents* tab = browser()->GetSelectedTabContents(); + + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + + sidebar_manager->NavigateSidebar(tab, kSampleContentId, url); + + SidebarContainer* sidebar_container = + sidebar_manager->GetSidebarContainerFor(tab, kSampleContentId); + + TabContents* client_contents = sidebar_container->sidebar_contents(); + ui_test_utils::WaitForNavigation(&client_contents->controller()); + } + + void ShowSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->ShowSidebar(tab, kSampleContentId); + } + + void ExpandSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->ExpandSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + } + + void CollapseSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->CollapseSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + } + + void HideSidebar(TabContents* tab) { + SidebarManager* sidebar_manager = SidebarManager::GetInstance(); + sidebar_manager->HideSidebar(tab, kSampleContentId); + if (browser()->GetSelectedTabContents() == tab) + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + } + + TabContents* tab_contents(int i) { + return browser()->GetTabContentsAt(i); + } + + BrowserView* browser_view() const { + return static_cast<BrowserView*>(browser()->window()); + } +}; + +IN_PROC_BROWSER_TEST_F(SidebarTest, OpenClose) { + ShowSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + HideSidebarForCurrentTab(); + + ShowSidebarForCurrentTab(); + + ExpandSidebarForCurrentTab(); + CollapseSidebarForCurrentTab(); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SwitchingTabs) { + ShowSidebarForCurrentTab(); + ExpandSidebarForCurrentTab(); + + browser()->NewTab(); + + // Make sure sidebar is not visbile for the newly opened tab. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Switch back to the first tab. + browser()->SelectNumberedTab(0); + + // Make sure it is visible now. + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarOnInactiveTab) { + ShowSidebarForCurrentTab(); + ExpandSidebarForCurrentTab(); + + browser()->NewTab(); + + // Hide sidebar on inactive (first) tab. + HideSidebar(tab_contents(0)); + + // Switch back to the first tab. + browser()->SelectNumberedTab(0); + + // Make sure sidebar is not visbile anymore. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Show sidebar on inactive (second) tab. + ShowSidebar(tab_contents(1)); + ExpandSidebar(tab_contents(1)); + // Make sure sidebar is not visible yet. + EXPECT_EQ(0, browser_view()->GetSidebarWidth()); + + // Switch back to the second tab. + browser()->SelectNumberedTab(1); + // Make sure sidebar is visible now. + EXPECT_GT(browser_view()->GetSidebarWidth(), 0); + + HideSidebarForCurrentTab(); +} + +IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarNavigate) { + ShowSidebarForCurrentTab(); + + NavigateSidebarForCurrentTabTo(kSimplePage); + + HideSidebarForCurrentTab(); +} + +} // namespace + |