MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / extensions / extension_toolbar_model.cc
blobc8e110d38d3fe44e95c7c2c3aacf7f3a3ea36b44
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/extension_toolbar_model.h"
7 #include <algorithm>
8 #include <string>
10 #include "base/message_loop/message_loop.h"
11 #include "base/metrics/histogram.h"
12 #include "base/metrics/histogram_base.h"
13 #include "base/prefs/pref_service.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
16 #include "chrome/browser/extensions/extension_action_manager.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/extensions/extension_toolbar_model_factory.h"
19 #include "chrome/browser/extensions/extension_util.h"
20 #include "chrome/browser/extensions/tab_helper.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_source.h"
27 #include "content/public/browser/web_contents.h"
28 #include "extensions/browser/extension_prefs.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/browser/pref_names.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/extension_set.h"
34 #include "extensions/common/feature_switch.h"
35 #include "extensions/common/one_shot_event.h"
37 namespace extensions {
39 ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile,
40 ExtensionPrefs* extension_prefs)
41 : profile_(profile),
42 extension_prefs_(extension_prefs),
43 prefs_(profile_->GetPrefs()),
44 extensions_initialized_(false),
45 include_all_extensions_(
46 FeatureSwitch::extension_action_redesign()->IsEnabled()),
47 is_highlighting_(false),
48 extension_action_observer_(this),
49 extension_registry_observer_(this),
50 weak_ptr_factory_(this) {
51 ExtensionSystem::Get(profile_)->ready().Post(
52 FROM_HERE,
53 base::Bind(&ExtensionToolbarModel::OnReady,
54 weak_ptr_factory_.GetWeakPtr()));
55 visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize);
57 // We only care about watching the prefs if not in incognito mode.
58 if (!profile_->IsOffTheRecord()) {
59 pref_change_registrar_.Init(prefs_);
60 pref_change_callback_ =
61 base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange,
62 base::Unretained(this));
63 pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
67 ExtensionToolbarModel::~ExtensionToolbarModel() {
70 // static
71 ExtensionToolbarModel* ExtensionToolbarModel::Get(Profile* profile) {
72 return ExtensionToolbarModelFactory::GetForProfile(profile);
75 void ExtensionToolbarModel::AddObserver(Observer* observer) {
76 observers_.AddObserver(observer);
79 void ExtensionToolbarModel::RemoveObserver(Observer* observer) {
80 observers_.RemoveObserver(observer);
83 void ExtensionToolbarModel::MoveExtensionIcon(const std::string& id,
84 size_t index) {
85 ExtensionList::iterator pos = toolbar_items_.begin();
86 while (pos != toolbar_items_.end() && (*pos)->id() != id)
87 ++pos;
88 if (pos == toolbar_items_.end()) {
89 NOTREACHED();
90 return;
92 scoped_refptr<const Extension> extension = *pos;
93 toolbar_items_.erase(pos);
95 ExtensionIdList::iterator pos_id = std::find(last_known_positions_.begin(),
96 last_known_positions_.end(),
97 id);
98 if (pos_id != last_known_positions_.end())
99 last_known_positions_.erase(pos_id);
101 if (index < toolbar_items_.size()) {
102 // If the index is not at the end, find the item currently at |index|, and
103 // insert |extension| before it in both |toolbar_items_| and
104 // |last_known_positions_|.
105 ExtensionList::iterator iter = toolbar_items_.begin() + index;
106 last_known_positions_.insert(std::find(last_known_positions_.begin(),
107 last_known_positions_.end(),
108 (*iter)->id()),
109 id);
110 toolbar_items_.insert(iter, extension);
111 } else {
112 // Otherwise, put |extension| at the end.
113 DCHECK_EQ(toolbar_items_.size(), index);
114 index = toolbar_items_.size();
115 toolbar_items_.push_back(extension);
116 last_known_positions_.push_back(id);
119 FOR_EACH_OBSERVER(
120 Observer, observers_, ToolbarExtensionMoved(extension.get(), index));
121 MaybeUpdateVisibilityPref(extension.get(), index);
122 UpdatePrefs();
125 void ExtensionToolbarModel::SetVisibleIconCount(int count) {
126 visible_icon_count_ =
127 count == static_cast<int>(toolbar_items_.size()) ? -1 : count;
129 // Only set the prefs if we're not in highlight mode and the profile is not
130 // incognito. Highlight mode is designed to be a transitory state, and should
131 // not persist across browser restarts (though it may be re-entered), and we
132 // don't store anything in incognito.
133 if (!is_highlighting_ && !profile_->IsOffTheRecord()) {
134 // Additionally, if we are using the new toolbar, any icons which are in the
135 // overflow menu are considered "hidden". But it so happens that the times
136 // we are likely to call SetVisibleIconCount() are also those when we are
137 // in flux. So wait for things to cool down before setting the prefs.
138 base::MessageLoop::current()->PostTask(
139 FROM_HERE,
140 base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs,
141 weak_ptr_factory_.GetWeakPtr()));
142 prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_);
145 FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
148 void ExtensionToolbarModel::OnExtensionActionUpdated(
149 ExtensionAction* extension_action,
150 content::WebContents* web_contents,
151 content::BrowserContext* browser_context) {
152 const Extension* extension =
153 ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
154 extension_action->extension_id());
155 // Notify observers if the extension exists and is in the model.
156 if (extension &&
157 std::find(toolbar_items_.begin(),
158 toolbar_items_.end(),
159 extension) != toolbar_items_.end()) {
160 FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionUpdated(extension));
164 void ExtensionToolbarModel::OnExtensionLoaded(
165 content::BrowserContext* browser_context,
166 const Extension* extension) {
167 // We don't want to add the same extension twice. It may have already been
168 // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
169 // hides the browser action and then disables and enables the extension.
170 for (size_t i = 0; i < toolbar_items_.size(); i++) {
171 if (toolbar_items_[i].get() == extension)
172 return;
175 AddExtension(extension);
178 void ExtensionToolbarModel::OnExtensionUnloaded(
179 content::BrowserContext* browser_context,
180 const Extension* extension,
181 UnloadedExtensionInfo::Reason reason) {
182 RemoveExtension(extension);
185 void ExtensionToolbarModel::OnExtensionUninstalled(
186 content::BrowserContext* browser_context,
187 const Extension* extension,
188 extensions::UninstallReason reason) {
189 // Remove the extension id from the ordered list, if it exists (the extension
190 // might not be represented in the list because it might not have an icon).
191 ExtensionIdList::iterator pos =
192 std::find(last_known_positions_.begin(),
193 last_known_positions_.end(), extension->id());
195 if (pos != last_known_positions_.end()) {
196 last_known_positions_.erase(pos);
197 UpdatePrefs();
201 void ExtensionToolbarModel::Observe(
202 int type,
203 const content::NotificationSource& source,
204 const content::NotificationDetails& details) {
205 DCHECK_EQ(NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, type);
206 const Extension* extension =
207 ExtensionRegistry::Get(profile_)->GetExtensionById(
208 *content::Details<const std::string>(details).ptr(),
209 ExtensionRegistry::EVERYTHING);
211 bool visible = ExtensionActionAPI::GetBrowserActionVisibility(
212 extension_prefs_, extension->id());
213 // Hiding works differently with the new and old toolbars.
214 if (include_all_extensions_) {
215 int new_size = 0;
216 int new_index = 0;
217 if (visible) {
218 // If this action used to be hidden, we can't possibly be showing all.
219 DCHECK_NE(-1, visible_icon_count_);
220 // Grow the bar by one and move the extension to the end of the visibles.
221 new_size = visible_icon_count_ + 1;
222 new_index = new_size - 1;
223 } else {
224 // If we're hiding one, we must be showing at least one.
225 DCHECK_NE(visible_icon_count_, 0);
226 // Shrink the bar by one and move the extension to the beginning of the
227 // overflow menu.
228 new_size = visible_icon_count_ == -1 ?
229 toolbar_items_.size() - 1 : visible_icon_count_ - 1;
230 new_index = new_size;
232 SetVisibleIconCount(new_size);
233 MoveExtensionIcon(extension->id(), new_index);
234 } else { // Don't include all extensions.
235 if (visible)
236 AddExtension(extension);
237 else
238 RemoveExtension(extension);
242 void ExtensionToolbarModel::OnReady() {
243 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
244 InitializeExtensionList();
245 // Wait until the extension system is ready before observing any further
246 // changes so that the toolbar buttons can be shown in their stable ordering
247 // taken from prefs.
248 extension_registry_observer_.Add(registry);
249 extension_action_observer_.Add(ExtensionActionAPI::Get(profile_));
250 registrar_.Add(
251 this,
252 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
253 content::Source<ExtensionPrefs>(extension_prefs_));
256 size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood(
257 const Extension* extension) {
258 // See if we have last known good position for this extension.
259 size_t new_index = 0;
260 // Loop through the ID list of known positions, to count the number of visible
261 // extension icons preceding |extension|.
262 for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin();
263 iter_id < last_known_positions_.end(); ++iter_id) {
264 if ((*iter_id) == extension->id())
265 return new_index; // We've found the right position.
266 // Found an id, need to see if it is visible.
267 for (ExtensionList::const_iterator iter_ext = toolbar_items_.begin();
268 iter_ext < toolbar_items_.end(); ++iter_ext) {
269 if ((*iter_ext)->id() == (*iter_id)) {
270 // This extension is visible, update the index value.
271 ++new_index;
272 break;
277 // Position not found.
278 return toolbar_items_.size();
281 bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) {
282 // In incognito mode, don't add any extensions that aren't incognito-enabled.
283 if (profile_->IsOffTheRecord() &&
284 !util::IsIncognitoEnabled(extension->id(), profile_))
285 return false;
287 ExtensionActionManager* action_manager =
288 ExtensionActionManager::Get(profile_);
289 if (include_all_extensions_) {
290 // In this case, we don't care about the browser action visibility, because
291 // we want to show each extension regardless.
292 // TODO(devlin): Extension actions which are not visible should be moved to
293 // the overflow menu by default.
294 return action_manager->GetExtensionAction(*extension) != NULL;
297 return action_manager->GetBrowserAction(*extension) &&
298 ExtensionActionAPI::GetBrowserActionVisibility(
299 extension_prefs_, extension->id());
302 void ExtensionToolbarModel::AddExtension(const Extension* extension) {
303 if (!ShouldAddExtension(extension))
304 return;
306 // See if we have a last known good position for this extension.
307 bool is_new_extension =
308 std::find(last_known_positions_.begin(),
309 last_known_positions_.end(),
310 extension->id()) == last_known_positions_.end();
311 size_t new_index = is_new_extension ? toolbar_items_.size() :
312 FindNewPositionFromLastKnownGood(extension);
313 toolbar_items_.insert(toolbar_items_.begin() + new_index,
314 make_scoped_refptr(extension));
315 if (is_new_extension) {
316 last_known_positions_.push_back(extension->id());
317 UpdatePrefs();
320 MaybeUpdateVisibilityPref(extension, new_index);
322 // If we're currently highlighting, then even though we add a browser action
323 // to the full list (|toolbar_items_|, there won't be another *visible*
324 // browser action, which was what the observers care about.
325 if (!is_highlighting_) {
326 FOR_EACH_OBSERVER(
327 Observer, observers_, ToolbarExtensionAdded(extension, new_index));
331 void ExtensionToolbarModel::RemoveExtension(const Extension* extension) {
332 ExtensionList::iterator pos =
333 std::find(toolbar_items_.begin(), toolbar_items_.end(), extension);
334 if (pos == toolbar_items_.end())
335 return;
337 toolbar_items_.erase(pos);
339 // If we're in highlight mode, we also have to remove the extension from
340 // the highlighted list.
341 if (is_highlighting_) {
342 pos = std::find(highlighted_items_.begin(),
343 highlighted_items_.end(),
344 extension);
345 if (pos != highlighted_items_.end()) {
346 highlighted_items_.erase(pos);
347 FOR_EACH_OBSERVER(
348 Observer, observers_, ToolbarExtensionRemoved(extension));
349 // If the highlighted list is now empty, we stop highlighting.
350 if (highlighted_items_.empty())
351 StopHighlighting();
353 } else {
354 FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionRemoved(extension));
357 UpdatePrefs();
360 void ExtensionToolbarModel::ClearItems() {
361 size_t items_count = toolbar_items_.size();
362 for (size_t i = 0; i < items_count; ++i) {
363 const Extension* extension = toolbar_items_.back().get();
364 toolbar_items_.pop_back();
365 FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionRemoved(extension));
367 DCHECK(toolbar_items_.empty());
370 // Combine the currently enabled extensions that have browser actions (which
371 // we get from the ExtensionRegistry) with the ordering we get from the
372 // pref service. For robustness we use a somewhat inefficient process:
373 // 1. Create a vector of extensions sorted by their pref values. This vector may
374 // have holes.
375 // 2. Create a vector of extensions that did not have a pref value.
376 // 3. Remove holes from the sorted vector and append the unsorted vector.
377 void ExtensionToolbarModel::InitializeExtensionList() {
378 last_known_positions_ = extension_prefs_->GetToolbarOrder();
379 if (profile_->IsOffTheRecord())
380 IncognitoPopulate();
381 else
382 Populate(last_known_positions_);
384 extensions_initialized_ = true;
385 MaybeUpdateVisibilityPrefs();
386 FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
389 void ExtensionToolbarModel::Populate(const ExtensionIdList& positions) {
390 DCHECK(!profile_->IsOffTheRecord());
391 const ExtensionSet& extensions =
392 ExtensionRegistry::Get(profile_)->enabled_extensions();
393 // Items that have explicit positions.
394 ExtensionList sorted(positions.size(), NULL);
395 // The items that don't have explicit positions.
396 ExtensionList unsorted;
398 // Create the lists.
399 int hidden = 0;
400 for (const scoped_refptr<const Extension>& extension : extensions) {
401 if (!ShouldAddExtension(extension.get())) {
402 if (!ExtensionActionAPI::GetBrowserActionVisibility(extension_prefs_,
403 extension->id()))
404 ++hidden;
405 continue;
408 ExtensionIdList::const_iterator pos =
409 std::find(positions.begin(), positions.end(), extension->id());
410 if (pos != positions.end())
411 sorted[pos - positions.begin()] = extension;
412 else
413 unsorted.push_back(extension);
416 // Clear the current items, if any.
417 ClearItems();
419 // Merge the lists.
420 toolbar_items_.reserve(sorted.size() + unsorted.size());
422 for (const scoped_refptr<const Extension>& extension : sorted) {
423 // It's possible for the extension order to contain items that aren't
424 // actually loaded on this machine. For example, when extension sync is on,
425 // we sync the extension order as-is but double-check with the user before
426 // syncing NPAPI-containing extensions, so if one of those is not actually
427 // synced, we'll get a NULL in the list. This sort of case can also happen
428 // if some error prevents an extension from loading.
429 if (extension.get() != NULL) {
430 toolbar_items_.push_back(extension);
431 FOR_EACH_OBSERVER(
432 Observer,
433 observers_,
434 ToolbarExtensionAdded(extension.get(), toolbar_items_.size() - 1));
437 for (const scoped_refptr<const Extension>& extension : unsorted) {
438 if (extension.get() != NULL) {
439 toolbar_items_.push_back(extension);
440 FOR_EACH_OBSERVER(
441 Observer,
442 observers_,
443 ToolbarExtensionAdded(extension.get(), toolbar_items_.size() - 1));
447 UMA_HISTOGRAM_COUNTS_100(
448 "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden);
449 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount",
450 toolbar_items_.size());
452 if (!toolbar_items_.empty()) {
453 // Visible count can be -1, meaning: 'show all'. Since UMA converts negative
454 // values to 0, this would be counted as 'show none' unless we convert it to
455 // max.
456 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsVisible",
457 visible_icon_count_ == -1 ?
458 base::HistogramBase::kSampleType_MAX :
459 visible_icon_count_);
463 void ExtensionToolbarModel::IncognitoPopulate() {
464 DCHECK(profile_->IsOffTheRecord());
465 // Clear the current items, if any.
466 ClearItems();
468 const ExtensionToolbarModel* original_model =
469 ExtensionToolbarModel::Get(profile_->GetOriginalProfile());
471 // Find the absolute value of the original model's count.
472 int original_visible = original_model->GetVisibleIconCount();
473 if (original_visible == -1)
474 original_visible = original_model->toolbar_items_.size();
476 // In incognito mode, we show only those extensions that are
477 // incognito-enabled. Further, any actions that were overflowed in regular
478 // mode are still overflowed. Order is the same as in regular mode.
479 visible_icon_count_ = 0;
480 for (ExtensionList::const_iterator iter =
481 original_model->toolbar_items_.begin();
482 iter != original_model->toolbar_items_.end(); ++iter) {
483 if (ShouldAddExtension(iter->get())) {
484 toolbar_items_.push_back(*iter);
485 if (iter - original_model->toolbar_items_.begin() < original_visible)
486 ++visible_icon_count_;
487 FOR_EACH_OBSERVER(
488 Observer,
489 observers_,
490 ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
495 void ExtensionToolbarModel::UpdatePrefs() {
496 if (!extension_prefs_ || profile_->IsOffTheRecord())
497 return;
499 // Don't observe change caused by self.
500 pref_change_registrar_.Remove(pref_names::kToolbar);
501 extension_prefs_->SetToolbarOrder(last_known_positions_);
502 pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
505 void ExtensionToolbarModel::MaybeUpdateVisibilityPref(
506 const Extension* extension, int index) {
507 // We only update the visibility pref for hidden/not hidden based on the
508 // overflow menu with the new toolbar design.
509 if (include_all_extensions_ && !profile_->IsOffTheRecord()) {
510 bool visible = index < visible_icon_count_ || visible_icon_count_ == -1;
511 if (visible != ExtensionActionAPI::GetBrowserActionVisibility(
512 extension_prefs_, extension->id())) {
513 // Don't observe changes caused by ourselves.
514 bool was_registered = false;
515 if (registrar_.IsRegistered(
516 this,
517 NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
518 content::Source<ExtensionPrefs>(extension_prefs_))) {
519 was_registered = true;
520 registrar_.Remove(
521 this,
522 NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
523 content::Source<ExtensionPrefs>(extension_prefs_));
525 ExtensionActionAPI::SetBrowserActionVisibility(
526 extension_prefs_, extension->id(), visible);
527 if (was_registered) {
528 registrar_.Add(this,
529 NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
530 content::Source<ExtensionPrefs>(extension_prefs_));
536 void ExtensionToolbarModel::MaybeUpdateVisibilityPrefs() {
537 for (size_t i = 0u; i < toolbar_items_.size(); ++i)
538 MaybeUpdateVisibilityPref(toolbar_items_[i].get(), i);
541 void ExtensionToolbarModel::OnExtensionToolbarPrefChange() {
542 // If extensions are not ready, defer to later Populate() call.
543 if (!extensions_initialized_)
544 return;
546 // Recalculate |last_known_positions_| to be |pref_positions| followed by
547 // ones that are only in |last_known_positions_|.
548 ExtensionIdList pref_positions = extension_prefs_->GetToolbarOrder();
549 size_t pref_position_size = pref_positions.size();
550 for (size_t i = 0; i < last_known_positions_.size(); ++i) {
551 if (std::find(pref_positions.begin(), pref_positions.end(),
552 last_known_positions_[i]) == pref_positions.end()) {
553 pref_positions.push_back(last_known_positions_[i]);
556 last_known_positions_.swap(pref_positions);
558 // Re-populate.
559 Populate(last_known_positions_);
561 if (last_known_positions_.size() > pref_position_size) {
562 // Need to update pref because we have extra icons. But can't call
563 // UpdatePrefs() directly within observation closure.
564 base::MessageLoop::current()->PostTask(
565 FROM_HERE,
566 base::Bind(&ExtensionToolbarModel::UpdatePrefs,
567 weak_ptr_factory_.GetWeakPtr()));
571 bool ExtensionToolbarModel::ShowExtensionActionPopup(
572 const Extension* extension,
573 Browser* browser,
574 bool grant_active_tab) {
575 ObserverListBase<Observer>::Iterator it(observers_);
576 Observer* obs = NULL;
577 // Look for the Observer associated with the browser.
578 // This would be cleaner if we had an abstract class for the Toolbar UI
579 // (like we do for LocationBar), but sadly, we don't.
580 while ((obs = it.GetNext()) != NULL) {
581 if (obs->GetBrowser() == browser)
582 return obs->ShowExtensionActionPopup(extension, grant_active_tab);
584 return false;
587 void ExtensionToolbarModel::EnsureVisibility(
588 const ExtensionIdList& extension_ids) {
589 if (visible_icon_count_ == -1)
590 return; // Already showing all.
592 // Otherwise, make sure we have enough room to show all the extensions
593 // requested.
594 if (visible_icon_count_ < static_cast<int>(extension_ids.size()))
595 SetVisibleIconCount(extension_ids.size());
597 if (visible_icon_count_ == -1)
598 return; // May have been set to max by SetVisibleIconCount.
600 // Guillotine's Delight: Move an orange noble to the front of the line.
601 for (ExtensionIdList::const_iterator it = extension_ids.begin();
602 it != extension_ids.end(); ++it) {
603 for (ExtensionList::const_iterator extension = toolbar_items_.begin();
604 extension != toolbar_items_.end(); ++extension) {
605 if ((*extension)->id() == (*it)) {
606 if (extension - toolbar_items_.begin() >= visible_icon_count_)
607 MoveExtensionIcon((*extension)->id(), 0);
608 break;
614 bool ExtensionToolbarModel::HighlightExtensions(
615 const ExtensionIdList& extension_ids) {
616 highlighted_items_.clear();
618 for (ExtensionIdList::const_iterator id = extension_ids.begin();
619 id != extension_ids.end();
620 ++id) {
621 for (ExtensionList::const_iterator extension = toolbar_items_.begin();
622 extension != toolbar_items_.end();
623 ++extension) {
624 if (*id == (*extension)->id())
625 highlighted_items_.push_back(*extension);
629 // If we have any items in |highlighted_items_|, then we entered highlighting
630 // mode.
631 if (highlighted_items_.size()) {
632 old_visible_icon_count_ = visible_icon_count_;
633 is_highlighting_ = true;
634 if (visible_icon_count_ != -1 &&
635 visible_icon_count_ < static_cast<int>(extension_ids.size())) {
636 SetVisibleIconCount(extension_ids.size());
639 FOR_EACH_OBSERVER(Observer, observers_, ToolbarHighlightModeChanged(true));
640 return true;
643 // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if
644 // we were otherwise in it).
645 if (is_highlighting_)
646 StopHighlighting();
647 return false;
650 void ExtensionToolbarModel::StopHighlighting() {
651 if (is_highlighting_) {
652 highlighted_items_.clear();
653 is_highlighting_ = false;
654 if (old_visible_icon_count_ != visible_icon_count_)
655 SetVisibleIconCount(old_visible_icon_count_);
656 FOR_EACH_OBSERVER(Observer, observers_, ToolbarHighlightModeChanged(false));
660 } // namespace extensions