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