// Copyright (c) 2011 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/profiles/profile.h" #include "chrome/browser/sidebar/sidebar_container.h" #include "chrome/common/chrome_switches.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/common/notification_service.h" #include "googleurl/src/gurl.h" struct SidebarManager::SidebarStateForTab { // 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; }; // 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->tab_contents(), was_active_host->content_id(), extension_sidebar_constants::kShownState); } if (active_host != NULL) { ExtensionSidebarEventRouter::OnStateChanged( active_sidebar_contents->profile(), active_host->tab_contents(), 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); // It might trigger UpdateSidebar notification, so load them after // the registration. host->LoadDefaults(); } host->Show(); ExtensionSidebarEventRouter::OnStateChanged( tab->profile(), tab, 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); UnregisterSidebarContainerFor(tab, content_id); ExtensionSidebarEventRouter::OnStateChanged( tab->profile(), tab, 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); }