• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetInstance()27 SidebarManager* SidebarManager::GetInstance() {
28   return g_browser_process->sidebar_manager();
29 }
30 
31 // static
IsSidebarAllowed()32 bool SidebarManager::IsSidebarAllowed() {
33   return CommandLine::ForCurrentProcess()->HasSwitch(
34       switches::kEnableExperimentalExtensionApis);
35 }
36 
SidebarManager()37 SidebarManager::SidebarManager() {
38 }
39 
GetActiveSidebarContainerFor(TabContents * tab)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 
GetSidebarContainerFor(TabContents * tab,const std::string & content_id)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 
GetSidebarTabContents(TabContents * tab,const std::string & content_id)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 
NotifyStateChanges(TabContents * was_active_sidebar_contents,TabContents * active_sidebar_contents)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 
ShowSidebar(TabContents * tab,const std::string & content_id)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 
ExpandSidebar(TabContents * tab,const std::string & content_id)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 
CollapseSidebar(TabContents * tab,const std::string & content_id)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 
HideSidebar(TabContents * tab,const std::string & content_id)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 
NavigateSidebar(TabContents * tab,const std::string & content_id,const GURL & url)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 
SetSidebarBadgeText(TabContents * tab,const std::string & content_id,const string16 & badge_text)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 
SetSidebarIcon(TabContents * tab,const std::string & content_id,const SkBitmap & bitmap)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 
SetSidebarTitle(TabContents * tab,const std::string & content_id,const string16 & title)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 
~SidebarManager()217 SidebarManager::~SidebarManager() {
218   DCHECK(tab_to_sidebar_host_.empty());
219   DCHECK(sidebar_host_to_tab_.empty());
220 }
221 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
UpdateSidebar(SidebarContainer * host)232 void SidebarManager::UpdateSidebar(SidebarContainer* host) {
233   NotificationService::current()->Notify(
234       NotificationType::SIDEBAR_CHANGED,
235       Source<SidebarManager>(this),
236       Details<SidebarContainer>(host));
237 }
238 
HideAllSidebars(TabContents * tab)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 
FindSidebarContainerFor(TabContents * sidebar_contents)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 
RegisterSidebarContainerFor(TabContents * tab,SidebarContainer * sidebar_host)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 
UnregisterSidebarContainerFor(TabContents * tab,const std::string & content_id)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 
BindSidebarHost(TabContents * tab,SidebarContainer * sidebar_host)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 
UnbindSidebarHost(TabContents * tab,SidebarContainer * sidebar_host)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