| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 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/extensions/extension_shelf_model.h" | |
| 6 | |
| 7 #include "base/stl_util-inl.h" | |
| 8 #include "chrome/browser/browser.h" | |
| 9 #include "chrome/browser/profile.h" | |
| 10 #include "chrome/browser/extensions/extension_host.h" | |
| 11 #include "chrome/browser/extensions/extension_process_manager.h" | |
| 12 #include "chrome/browser/extensions/extension_toolstrip_api.h" | |
| 13 #include "chrome/browser/extensions/extensions_service.h" | |
| 14 #include "chrome/browser/renderer_host/render_view_host.h" | |
| 15 #include "chrome/common/extensions/extension.h" | |
| 16 #include "chrome/common/notification_service.h" | |
| 17 | |
| 18 ExtensionShelfModel::ExtensionShelfModel(Browser* browser) | |
| 19 : browser_(browser), ready_(false) { | |
| 20 // Watch extensions loaded and unloaded notifications. | |
| 21 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
| 22 NotificationService::AllSources()); | |
| 23 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
| 24 NotificationService::AllSources()); | |
| 25 registrar_.Add(this, NotificationType::EXTENSIONS_READY, | |
| 26 NotificationService::AllSources()); | |
| 27 | |
| 28 // Add any already-loaded extensions now, since we missed the notification for | |
| 29 // those. | |
| 30 ExtensionsService* service = browser_->profile()->GetExtensionsService(); | |
| 31 if (service) { // This can be null in unit tests. | |
| 32 prefs_ = browser_->profile()->GetExtensionsService()->extension_prefs(); | |
| 33 registrar_.Add(this, NotificationType::EXTENSION_SHELF_MODEL_CHANGED, | |
| 34 Source<ExtensionPrefs>(prefs_)); | |
| 35 ready_ = service->is_ready(); | |
| 36 if (ready_) { | |
| 37 AddExtensions(service->extensions()); | |
| 38 SortToolstrips(); | |
| 39 } | |
| 40 } | |
| 41 } | |
| 42 | |
| 43 ExtensionShelfModel::~ExtensionShelfModel() { | |
| 44 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 45 ShelfModelDeleting()); | |
| 46 | |
| 47 observers_.Clear(); | |
| 48 | |
| 49 for (iterator t = toolstrips_.begin(); t != toolstrips_.end(); ++t) | |
| 50 delete t->host; | |
| 51 toolstrips_.clear(); | |
| 52 } | |
| 53 | |
| 54 void ExtensionShelfModel::AddObserver(ExtensionShelfModelObserver* observer) { | |
| 55 observers_.AddObserver(observer); | |
| 56 } | |
| 57 | |
| 58 void ExtensionShelfModel::RemoveObserver( | |
| 59 ExtensionShelfModelObserver* observer) { | |
| 60 observers_.RemoveObserver(observer); | |
| 61 } | |
| 62 | |
| 63 void ExtensionShelfModel::AppendToolstrip(const ToolstripItem& toolstrip) { | |
| 64 InsertToolstripAt(count(), toolstrip); | |
| 65 } | |
| 66 | |
| 67 void ExtensionShelfModel::InsertToolstripAt(int index, | |
| 68 const ToolstripItem& toolstrip) { | |
| 69 toolstrips_.insert(toolstrips_.begin() + index, toolstrip); | |
| 70 if (ready_) { | |
| 71 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 72 ToolstripInsertedAt(toolstrip.host, index)); | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 void ExtensionShelfModel::RemoveToolstripAt(int index) { | |
| 77 ExtensionHost* host = ToolstripAt(index).host; | |
| 78 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 79 ToolstripRemovingAt(host, index)); | |
| 80 toolstrips_.erase(toolstrips_.begin() + index); | |
| 81 delete host; | |
| 82 } | |
| 83 | |
| 84 void ExtensionShelfModel::MoveToolstripAt(int index, int to_index) { | |
| 85 DCHECK(index >= 0); | |
| 86 DCHECK(to_index >= 0); | |
| 87 if (index == to_index) | |
| 88 return; | |
| 89 | |
| 90 ToolstripItem toolstrip = toolstrips_[index]; | |
| 91 toolstrips_.erase(toolstrips_.begin() + index); | |
| 92 toolstrips_.insert(toolstrips_.begin() + to_index, toolstrip); | |
| 93 | |
| 94 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 95 ToolstripMoved(toolstrip.host, index, to_index)); | |
| 96 | |
| 97 UpdatePrefs(); | |
| 98 } | |
| 99 | |
| 100 int ExtensionShelfModel::IndexOfHost(ExtensionHost* host) { | |
| 101 for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) { | |
| 102 if (i->host == host) | |
| 103 return i - toolstrips_.begin(); | |
| 104 } | |
| 105 return -1; | |
| 106 } | |
| 107 | |
| 108 ExtensionShelfModel::iterator ExtensionShelfModel::ToolstripForHost( | |
| 109 ExtensionHost* host) { | |
| 110 for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) { | |
| 111 if (i->host == host) | |
| 112 return i; | |
| 113 } | |
| 114 return toolstrips_.end(); | |
| 115 } | |
| 116 | |
| 117 const ExtensionShelfModel::ToolstripItem& ExtensionShelfModel::ToolstripAt( | |
| 118 int index) { | |
| 119 DCHECK(index >= 0); | |
| 120 return toolstrips_[index]; | |
| 121 } | |
| 122 | |
| 123 void ExtensionShelfModel::SetToolstripDataAt(int index, void* data) { | |
| 124 DCHECK(index >= 0); | |
| 125 toolstrips_[index].data = data; | |
| 126 } | |
| 127 | |
| 128 void ExtensionShelfModel::ExpandToolstrip(iterator toolstrip, | |
| 129 const GURL& url, int height) { | |
| 130 if (toolstrip == end()) | |
| 131 return; | |
| 132 toolstrip->height = height; | |
| 133 toolstrip->url = url; | |
| 134 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 135 ToolstripChanged(toolstrip)); | |
| 136 int routing_id = toolstrip->host->render_view_host()->routing_id(); | |
| 137 ToolstripEventRouter::OnToolstripExpanded(browser_->profile(), | |
| 138 routing_id, | |
| 139 url, height); | |
| 140 toolstrip->host->SetRenderViewType(ViewType::EXTENSION_MOLE); | |
| 141 } | |
| 142 | |
| 143 void ExtensionShelfModel::CollapseToolstrip(iterator toolstrip, | |
| 144 const GURL& url) { | |
| 145 if (toolstrip == end()) | |
| 146 return; | |
| 147 toolstrip->height = 0; | |
| 148 toolstrip->url = url; | |
| 149 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 150 ToolstripChanged(toolstrip)); | |
| 151 int routing_id = toolstrip->host->render_view_host()->routing_id(); | |
| 152 ToolstripEventRouter::OnToolstripCollapsed(browser_->profile(), | |
| 153 routing_id, | |
| 154 url); | |
| 155 toolstrip->host->SetRenderViewType(ViewType::EXTENSION_TOOLSTRIP); | |
| 156 } | |
| 157 | |
| 158 void ExtensionShelfModel::Observe(NotificationType type, | |
| 159 const NotificationSource& source, | |
| 160 const NotificationDetails& details) { | |
| 161 switch (type.value) { | |
| 162 case NotificationType::EXTENSION_LOADED: | |
| 163 if (ready_) | |
| 164 AddExtension(Details<Extension>(details).ptr()); | |
| 165 break; | |
| 166 case NotificationType::EXTENSION_UNLOADED: | |
| 167 RemoveExtension(Details<Extension>(details).ptr()); | |
| 168 break; | |
| 169 case NotificationType::EXTENSIONS_READY: | |
| 170 if (browser_->profile()->GetExtensionsService()) { | |
| 171 AddExtensions( | |
| 172 browser_->profile()->GetExtensionsService()->extensions()); | |
| 173 SortToolstrips(); | |
| 174 } | |
| 175 ready_ = true; | |
| 176 break; | |
| 177 case NotificationType::EXTENSION_SHELF_MODEL_CHANGED: | |
| 178 // Ignore changes that this model originated. | |
| 179 if (Details<ExtensionShelfModel>(details).ptr() != this) | |
| 180 SortToolstrips(); | |
| 181 break; | |
| 182 default: | |
| 183 DCHECK(false) << "Unhandled notification of type: " << type.value; | |
| 184 break; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 void ExtensionShelfModel::AddExtension(Extension* extension) { | |
| 189 ExtensionProcessManager* manager = | |
| 190 browser_->profile()->GetExtensionProcessManager(); | |
| 191 DCHECK(manager); | |
| 192 if (!manager) | |
| 193 return; | |
| 194 | |
| 195 for (std::vector<Extension::ToolstripInfo>::const_iterator toolstrip = | |
| 196 extension->toolstrips().begin(); | |
| 197 toolstrip != extension->toolstrips().end(); ++toolstrip) { | |
| 198 GURL url = toolstrip->toolstrip; | |
| 199 ToolstripItem item; | |
| 200 item.host = manager->CreateToolstrip(extension, url, browser_); | |
| 201 item.info = *toolstrip; | |
| 202 item.data = NULL; | |
| 203 item.height = 0; | |
| 204 AppendToolstrip(item); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 void ExtensionShelfModel::AddExtensions(const ExtensionList* extensions) { | |
| 209 if (extensions->size()) { | |
| 210 ExtensionList::const_iterator extension = extensions->begin(); | |
| 211 for (; extension != extensions->end(); ++extension) | |
| 212 AddExtension(*extension); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 void ExtensionShelfModel::RemoveExtension(Extension* extension) { | |
| 217 bool changed = false; | |
| 218 for (int i = count() - 1; i >= 0; --i) { | |
| 219 ExtensionHost* t = ToolstripAt(i).host; | |
| 220 if (t->extension()->id() == extension->id()) { | |
| 221 changed = true; | |
| 222 RemoveToolstripAt(i); | |
| 223 | |
| 224 // There can be more than one toolstrip per extension, so we have to keep | |
| 225 // looping even after finding a match. | |
| 226 } | |
| 227 } | |
| 228 if (changed) | |
| 229 UpdatePrefs(); | |
| 230 } | |
| 231 | |
| 232 void ExtensionShelfModel::UpdatePrefs() { | |
| 233 if (!prefs_) | |
| 234 return; | |
| 235 | |
| 236 // It's easiest to just rebuild the list each time. | |
| 237 ExtensionPrefs::URLList urls; | |
| 238 for (int i = 0; i < count(); ++i) | |
| 239 urls.push_back(ToolstripAt(i).host->GetURL()); | |
| 240 prefs_->SetShelfToolstripOrder(urls); | |
| 241 | |
| 242 NotificationService::current()->Notify( | |
| 243 NotificationType::EXTENSION_SHELF_MODEL_CHANGED, | |
| 244 Source<ExtensionPrefs>(prefs_), | |
| 245 Details<ExtensionShelfModel>(this)); | |
| 246 } | |
| 247 | |
| 248 void ExtensionShelfModel::SortToolstrips() { | |
| 249 ExtensionPrefs::URLList urls = prefs_->GetShelfToolstripOrder(); | |
| 250 ToolstripList copy = | |
| 251 ToolstripList(toolstrips_.begin(), toolstrips_.end()); | |
| 252 toolstrips_.clear(); | |
| 253 | |
| 254 // Go through the urls and find the matching toolstrip, re-adding it to the | |
| 255 // new list in the proper order. | |
| 256 for (size_t i = 0; i < urls.size(); ++i) { | |
| 257 GURL& url = urls[i]; | |
| 258 for (iterator toolstrip = copy.begin(); | |
| 259 toolstrip != copy.end(); ++toolstrip) { | |
| 260 if (url == toolstrip->host->GetURL()) { | |
| 261 // Note that it's technically possible for the same URL to appear in | |
| 262 // multiple toolstrips, so we don't do any testing for uniqueness. | |
| 263 toolstrips_.push_back(*toolstrip); | |
| 264 | |
| 265 // Remove the toolstrip from the list so we don't have to iterate over | |
| 266 // it next time. | |
| 267 copy.erase(toolstrip); | |
| 268 break; | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 // Any toolstrips remaining in |copy| were somehow missing from the prefs, | |
| 274 // so just append them to the end. | |
| 275 for (iterator toolstrip = copy.begin(); | |
| 276 toolstrip != copy.end(); ++toolstrip) { | |
| 277 toolstrips_.push_back(*toolstrip); | |
| 278 } | |
| 279 | |
| 280 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
| 281 ShelfModelReloaded()); | |
| 282 } | |
| OLD | NEW |