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