extension_toolbar_model.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
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/extensions/extension_toolbar_model.h" 6 7#include "chrome/browser/extensions/extension_prefs.h" 8#include "chrome/browser/extensions/extensions_service.h" 9#include "chrome/browser/prefs/pref_service.h" 10#include "chrome/browser/profile.h" 11#include "chrome/common/extensions/extension.h" 12#include "chrome/common/notification_service.h" 13#include "chrome/common/pref_names.h" 14 15ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service) 16 : service_(service), 17 prefs_(service->profile()->GetPrefs()), 18 extensions_initialized_(false) { 19 DCHECK(service_); 20 21 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 22 Source<Profile>(service_->profile())); 23 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 24 Source<Profile>(service_->profile())); 25 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, 26 Source<Profile>(service_->profile())); 27 registrar_.Add(this, NotificationType::EXTENSIONS_READY, 28 Source<Profile>(service_->profile())); 29 30 visible_icon_count_ = prefs_->GetInteger(prefs::kExtensionToolbarSize); 31} 32 33ExtensionToolbarModel::~ExtensionToolbarModel() { 34} 35 36void ExtensionToolbarModel::DestroyingProfile() { 37 registrar_.RemoveAll(); 38} 39 40void ExtensionToolbarModel::AddObserver(Observer* observer) { 41 observers_.AddObserver(observer); 42} 43 44void ExtensionToolbarModel::RemoveObserver(Observer* observer) { 45 observers_.RemoveObserver(observer); 46} 47 48void ExtensionToolbarModel::MoveBrowserAction(Extension* extension, 49 int index) { 50 ExtensionList::iterator pos = std::find(begin(), end(), extension); 51 if (pos == end()) { 52 NOTREACHED(); 53 return; 54 } 55 toolitems_.erase(pos); 56 57 int i = 0; 58 bool inserted = false; 59 for (ExtensionList::iterator iter = begin(); iter != end(); ++iter, ++i) { 60 if (i == index) { 61 toolitems_.insert(iter, extension); 62 inserted = true; 63 break; 64 } 65 } 66 67 if (!inserted) { 68 DCHECK_EQ(index, static_cast<int>(toolitems_.size())); 69 index = toolitems_.size(); 70 71 toolitems_.push_back(extension); 72 } 73 74 FOR_EACH_OBSERVER(Observer, observers_, BrowserActionMoved(extension, index)); 75 76 UpdatePrefs(); 77} 78 79void ExtensionToolbarModel::SetVisibleIconCount(int count) { 80 visible_icon_count_ = count == static_cast<int>(size()) ? -1 : count; 81 prefs_->SetInteger(prefs::kExtensionToolbarSize, visible_icon_count_); 82} 83 84void ExtensionToolbarModel::Observe(NotificationType type, 85 const NotificationSource& source, 86 const NotificationDetails& details) { 87 if (type == NotificationType::EXTENSIONS_READY) { 88 InitializeExtensionList(); 89 return; 90 } 91 92 if (!service_->is_ready()) 93 return; 94 95 Extension* extension = Details<Extension>(details).ptr(); 96 if (type == NotificationType::EXTENSION_LOADED) { 97 AddExtension(extension); 98 } else if (type == NotificationType::EXTENSION_UNLOADED || 99 type == NotificationType::EXTENSION_UNLOADED_DISABLED) { 100 RemoveExtension(extension); 101 } else { 102 NOTREACHED() << "Received unexpected notification"; 103 } 104} 105 106void ExtensionToolbarModel::AddExtension(Extension* extension) { 107 // We only care about extensions with browser actions. 108 if (!extension->browser_action()) 109 return; 110 111 if (extension->id() == last_extension_removed_ && 112 last_extension_removed_index_ < toolitems_.size()) { 113 toolitems_.insert(begin() + last_extension_removed_index_, extension); 114 FOR_EACH_OBSERVER(Observer, observers_, 115 BrowserActionAdded(extension, last_extension_removed_index_)); 116 } else { 117 toolitems_.push_back(extension); 118 FOR_EACH_OBSERVER(Observer, observers_, 119 BrowserActionAdded(extension, toolitems_.size() - 1)); 120 } 121 122 last_extension_removed_ = ""; 123 last_extension_removed_index_ = -1; 124 125 UpdatePrefs(); 126} 127 128void ExtensionToolbarModel::RemoveExtension(Extension* extension) { 129 ExtensionList::iterator pos = std::find(begin(), end(), extension); 130 if (pos == end()) { 131 return; 132 } 133 134 last_extension_removed_ = extension->id(); 135 last_extension_removed_index_ = pos - begin(); 136 137 toolitems_.erase(pos); 138 FOR_EACH_OBSERVER(Observer, observers_, 139 BrowserActionRemoved(extension)); 140 141 UpdatePrefs(); 142} 143 144// Combine the currently enabled extensions that have browser actions (which 145// we get from the ExtensionsService) with the ordering we get from the 146// pref service. For robustness we use a somewhat inefficient process: 147// 1. Create a vector of extensions sorted by their pref values. This vector may 148// have holes. 149// 2. Create a vector of extensions that did not have a pref value. 150// 3. Remove holes from the sorted vector and append the unsorted vector. 151void ExtensionToolbarModel::InitializeExtensionList() { 152 DCHECK(service_->is_ready()); 153 154 std::vector<std::string> pref_order = service_->extension_prefs()-> 155 GetToolbarOrder(); 156 // Items that have a pref for their position. 157 ExtensionList sorted; 158 sorted.resize(pref_order.size(), NULL); 159 // The items that don't have a pref for their position. 160 ExtensionList unsorted; 161 162 // Create the lists. 163 for (size_t i = 0; i < service_->extensions()->size(); ++i) { 164 Extension* extension = service_->extensions()->at(i); 165 if (!extension->browser_action()) 166 continue; 167 168 std::vector<std::string>::iterator pos = 169 std::find(pref_order.begin(), pref_order.end(), extension->id()); 170 if (pos != pref_order.end()) { 171 int index = std::distance(pref_order.begin(), pos); 172 sorted[index] = extension; 173 } else { 174 unsorted.push_back(extension); 175 } 176 } 177 178 // Merge the lists. 179 toolitems_.reserve(sorted.size() + unsorted.size()); 180 for (ExtensionList::iterator iter = sorted.begin(); 181 iter != sorted.end(); ++iter) { 182 if (*iter != NULL) 183 toolitems_.push_back(*iter); 184 } 185 toolitems_.insert(toolitems_.end(), unsorted.begin(), unsorted.end()); 186 187 // Inform observers. 188 for (size_t i = 0; i < toolitems_.size(); i++) { 189 FOR_EACH_OBSERVER(Observer, observers_, 190 BrowserActionAdded(toolitems_[i], i)); 191 } 192 193 UpdatePrefs(); 194 195 extensions_initialized_ = true; 196 FOR_EACH_OBSERVER(Observer, observers_, ModelLoaded()); 197} 198 199void ExtensionToolbarModel::UpdatePrefs() { 200 if (!service_->extension_prefs()) 201 return; 202 203 std::vector<std::string> ids; 204 ids.reserve(toolitems_.size()); 205 for (ExtensionList::iterator iter = begin(); iter != end(); ++iter) 206 ids.push_back((*iter)->id()); 207 service_->extension_prefs()->SetToolbarOrder(ids); 208} 209 210Extension* ExtensionToolbarModel::GetExtensionByIndex(int index) const { 211 return toolitems_.at(index); 212} 213 214int ExtensionToolbarModel::IncognitoIndexToOriginal(int incognito_index) { 215 int original_index = 0, i = 0; 216 for (ExtensionList::iterator iter = begin(); iter != end(); 217 ++iter, ++original_index) { 218 if (service_->IsIncognitoEnabled(*iter)) { 219 if (incognito_index == i) 220 break; 221 ++i; 222 } 223 } 224 return original_index; 225} 226 227int ExtensionToolbarModel::OriginalIndexToIncognito(int original_index) { 228 int incognito_index = 0, i = 0; 229 for (ExtensionList::iterator iter = begin(); iter != end(); 230 ++iter, ++i) { 231 if (original_index == i) 232 break; 233 if (service_->IsIncognitoEnabled(*iter)) 234 ++incognito_index; 235 } 236 return incognito_index; 237} 238