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