Home | History | Annotate | Download | only in sidebar
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sidebar/sidebar_manager.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/browser/extensions/extension_sidebar_api.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/sidebar/sidebar_container.h"
     14 #include "chrome/common/chrome_switches.h"
     15 #include "content/browser/tab_contents/tab_contents.h"
     16 #include "content/common/notification_service.h"
     17 #include "googleurl/src/gurl.h"
     18 
     19 struct SidebarManager::SidebarStateForTab {
     20   // Sidebars linked to this tab.
     21   ContentIdToSidebarHostMap content_id_to_sidebar_host;
     22   // Content id of the currently active (expanded and visible) sidebar.
     23   std::string active_content_id;
     24 };
     25 
     26 // static
     27 SidebarManager* SidebarManager::GetInstance() {
     28   return g_browser_process->sidebar_manager();
     29 }
     30 
     31 // static
     32 bool SidebarManager::IsSidebarAllowed() {
     33   return CommandLine::ForCurrentProcess()->HasSwitch(
     34       switches::kEnableExperimentalExtensionApis);
     35 }
     36 
     37 SidebarManager::SidebarManager() {
     38 }
     39 
     40 SidebarContainer* SidebarManager::GetActiveSidebarContainerFor(
     41     TabContents* tab) {
     42   TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab);
     43   if (it == tab_to_sidebar_host_.end())
     44     return NULL;
     45   if (it->second.active_content_id.empty())
     46     return NULL;
     47   ContentIdToSidebarHostMap::iterator host_it =
     48       it->second.content_id_to_sidebar_host.find(it->second.active_content_id);
     49   DCHECK(host_it != it->second.content_id_to_sidebar_host.end());
     50   return host_it->second;
     51 }
     52 
     53 SidebarContainer* SidebarManager::GetSidebarContainerFor(
     54     TabContents* tab, const std::string& content_id) {
     55   DCHECK(!content_id.empty());
     56   TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab);
     57   if (it == tab_to_sidebar_host_.end())
     58     return NULL;
     59   ContentIdToSidebarHostMap::iterator host_it =
     60       it->second.content_id_to_sidebar_host.find(content_id);
     61   if (host_it == it->second.content_id_to_sidebar_host.end())
     62     return NULL;
     63   return host_it->second;
     64 }
     65 
     66 TabContents* SidebarManager::GetSidebarTabContents(
     67     TabContents* tab, const std::string& content_id) {
     68   DCHECK(!content_id.empty());
     69   SidebarContainer* sidebar_host = GetSidebarContainerFor(tab, content_id);
     70   if (!sidebar_host)
     71     return NULL;
     72   return sidebar_host->sidebar_contents();
     73 }
     74 
     75 void SidebarManager::NotifyStateChanges(
     76     TabContents* was_active_sidebar_contents,
     77     TabContents* active_sidebar_contents) {
     78   if (was_active_sidebar_contents == active_sidebar_contents)
     79     return;
     80 
     81   SidebarContainer* was_active_host =
     82       was_active_sidebar_contents == NULL ? NULL :
     83           FindSidebarContainerFor(was_active_sidebar_contents);
     84   SidebarContainer* active_host =
     85       active_sidebar_contents == NULL ? NULL :
     86           FindSidebarContainerFor(active_sidebar_contents);
     87 
     88   if (was_active_host != NULL) {
     89     ExtensionSidebarEventRouter::OnStateChanged(
     90         was_active_sidebar_contents->profile(),
     91         was_active_host->tab_contents(), was_active_host->content_id(),
     92         extension_sidebar_constants::kShownState);
     93   }
     94 
     95   if (active_host != NULL) {
     96     ExtensionSidebarEventRouter::OnStateChanged(
     97         active_sidebar_contents->profile(),
     98         active_host->tab_contents(), active_host->content_id(),
     99         extension_sidebar_constants::kActiveState);
    100   }
    101 }
    102 
    103 void SidebarManager::ShowSidebar(TabContents* tab,
    104                                  const std::string& content_id) {
    105   DCHECK(!content_id.empty());
    106   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    107   if (!host) {
    108     host = new SidebarContainer(tab, content_id, this);
    109     RegisterSidebarContainerFor(tab, host);
    110     // It might trigger UpdateSidebar notification, so load them after
    111     // the registration.
    112     host->LoadDefaults();
    113   }
    114 
    115   host->Show();
    116 
    117   ExtensionSidebarEventRouter::OnStateChanged(
    118       tab->profile(), tab, content_id,
    119       extension_sidebar_constants::kShownState);
    120 }
    121 
    122 void SidebarManager::ExpandSidebar(TabContents* tab,
    123                                    const std::string& content_id) {
    124   DCHECK(!content_id.empty());
    125   TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab);
    126   if (it == tab_to_sidebar_host_.end())
    127     return;
    128   // If it's already active, bail out.
    129   if (it->second.active_content_id == content_id)
    130     return;
    131 
    132   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    133   DCHECK(host);
    134   if (!host)
    135     return;
    136   it->second.active_content_id = content_id;
    137 
    138   host->Expand();
    139 }
    140 
    141 void SidebarManager::CollapseSidebar(TabContents* tab,
    142                                      const std::string& content_id) {
    143   DCHECK(!content_id.empty());
    144   TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab);
    145   if (it == tab_to_sidebar_host_.end())
    146     return;
    147   // If it's not the one active now, bail out.
    148   if (it->second.active_content_id != content_id)
    149     return;
    150 
    151   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    152   DCHECK(host);
    153   if (!host)
    154     return;
    155   it->second.active_content_id.clear();
    156 
    157   host->Collapse();
    158 }
    159 
    160 void SidebarManager::HideSidebar(TabContents* tab,
    161                                  const std::string& content_id) {
    162   DCHECK(!content_id.empty());
    163   TabToSidebarHostMap::iterator it = tab_to_sidebar_host_.find(tab);
    164   if (it == tab_to_sidebar_host_.end())
    165     return;
    166   if (it->second.active_content_id == content_id)
    167     it->second.active_content_id.clear();
    168 
    169   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    170   DCHECK(host);
    171 
    172   UnregisterSidebarContainerFor(tab, content_id);
    173 
    174   ExtensionSidebarEventRouter::OnStateChanged(
    175       tab->profile(), tab, content_id,
    176       extension_sidebar_constants::kHiddenState);
    177 }
    178 
    179 void SidebarManager::NavigateSidebar(TabContents* tab,
    180                                      const std::string& content_id,
    181                                      const GURL& url) {
    182   DCHECK(!content_id.empty());
    183   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    184   if (!host)
    185     return;
    186 
    187   host->Navigate(url);
    188 }
    189 
    190 void SidebarManager::SetSidebarBadgeText(
    191     TabContents* tab, const std::string& content_id,
    192     const string16& badge_text) {
    193   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    194   if (!host)
    195     return;
    196   host->SetBadgeText(badge_text);
    197 }
    198 
    199 void SidebarManager::SetSidebarIcon(
    200     TabContents* tab, const std::string& content_id,
    201     const SkBitmap& bitmap) {
    202   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    203   if (!host)
    204     return;
    205   host->SetIcon(bitmap);
    206 }
    207 
    208 void SidebarManager::SetSidebarTitle(
    209     TabContents* tab, const std::string& content_id,
    210     const string16& title) {
    211   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    212   if (!host)
    213     return;
    214   host->SetTitle(title);
    215 }
    216 
    217 SidebarManager::~SidebarManager() {
    218   DCHECK(tab_to_sidebar_host_.empty());
    219   DCHECK(sidebar_host_to_tab_.empty());
    220 }
    221 
    222 void SidebarManager::Observe(NotificationType type,
    223                              const NotificationSource& source,
    224                              const NotificationDetails& details) {
    225   if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
    226     HideAllSidebars(Source<TabContents>(source).ptr());
    227   } else {
    228     NOTREACHED() << "Got a notification we didn't register for!";
    229   }
    230 }
    231 
    232 void SidebarManager::UpdateSidebar(SidebarContainer* host) {
    233   NotificationService::current()->Notify(
    234       NotificationType::SIDEBAR_CHANGED,
    235       Source<SidebarManager>(this),
    236       Details<SidebarContainer>(host));
    237 }
    238 
    239 void SidebarManager::HideAllSidebars(TabContents* tab) {
    240   TabToSidebarHostMap::iterator tab_it = tab_to_sidebar_host_.find(tab);
    241   if (tab_it == tab_to_sidebar_host_.end())
    242     return;
    243   const ContentIdToSidebarHostMap& hosts =
    244       tab_it->second.content_id_to_sidebar_host;
    245 
    246   std::vector<std::string> content_ids;
    247   for (ContentIdToSidebarHostMap::const_iterator it = hosts.begin();
    248        it != hosts.end(); ++it) {
    249     content_ids.push_back(it->first);
    250   }
    251 
    252   for (std::vector<std::string>::iterator it = content_ids.begin();
    253        it != content_ids.end(); ++it) {
    254     HideSidebar(tab, *it);
    255   }
    256 }
    257 
    258 SidebarContainer* SidebarManager::FindSidebarContainerFor(
    259     TabContents* sidebar_contents) {
    260   for (SidebarHostToTabMap::iterator it = sidebar_host_to_tab_.begin();
    261        it != sidebar_host_to_tab_.end();
    262        ++it) {
    263     if (sidebar_contents == it->first->sidebar_contents())
    264       return it->first;
    265   }
    266   return NULL;
    267 }
    268 
    269 void SidebarManager::RegisterSidebarContainerFor(
    270     TabContents* tab, SidebarContainer* sidebar_host) {
    271   DCHECK(!GetSidebarContainerFor(tab, sidebar_host->content_id()));
    272 
    273   // If it's a first sidebar for this tab, register destroy notification.
    274   if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) {
    275     registrar_.Add(this,
    276                    NotificationType::TAB_CONTENTS_DESTROYED,
    277                    Source<TabContents>(tab));
    278   }
    279 
    280   BindSidebarHost(tab, sidebar_host);
    281 }
    282 
    283 void SidebarManager::UnregisterSidebarContainerFor(
    284       TabContents* tab, const std::string& content_id) {
    285   SidebarContainer* host = GetSidebarContainerFor(tab, content_id);
    286   DCHECK(host);
    287   if (!host)
    288     return;
    289 
    290   UnbindSidebarHost(tab, host);
    291 
    292   // If there's no more sidebars linked to this tab, unsubscribe.
    293   if (tab_to_sidebar_host_.find(tab) == tab_to_sidebar_host_.end()) {
    294     registrar_.Remove(this,
    295                       NotificationType::TAB_CONTENTS_DESTROYED,
    296                       Source<TabContents>(tab));
    297   }
    298 
    299   // Issue tab closing event post unbound.
    300   host->SidebarClosing();
    301   // Destroy sidebar container.
    302   delete host;
    303 }
    304 
    305 void SidebarManager::BindSidebarHost(TabContents* tab,
    306                                      SidebarContainer* sidebar_host) {
    307   const std::string& content_id = sidebar_host->content_id();
    308 
    309   DCHECK(GetSidebarContainerFor(tab, content_id) == NULL);
    310   DCHECK(sidebar_host_to_tab_.find(sidebar_host) ==
    311          sidebar_host_to_tab_.end());
    312 
    313   tab_to_sidebar_host_[tab].content_id_to_sidebar_host[content_id] =
    314       sidebar_host;
    315   sidebar_host_to_tab_[sidebar_host] = tab;
    316 }
    317 
    318 void SidebarManager::UnbindSidebarHost(TabContents* tab,
    319                                        SidebarContainer* sidebar_host) {
    320   const std::string& content_id = sidebar_host->content_id();
    321 
    322   DCHECK(GetSidebarContainerFor(tab, content_id) == sidebar_host);
    323   DCHECK(sidebar_host_to_tab_.find(sidebar_host)->second == tab);
    324   DCHECK(tab_to_sidebar_host_[tab].active_content_id != content_id);
    325 
    326   tab_to_sidebar_host_[tab].content_id_to_sidebar_host.erase(content_id);
    327   if (tab_to_sidebar_host_[tab].content_id_to_sidebar_host.empty())
    328     tab_to_sidebar_host_.erase(tab);
    329   sidebar_host_to_tab_.erase(sidebar_host);
    330 }
    331