Chromium Code Reviews| Index: chrome/browser/ui/toolbar/toolbar_actions_model.cc |
| diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc |
| similarity index 54% |
| rename from chrome/browser/extensions/extension_toolbar_model.cc |
| rename to chrome/browser/ui/toolbar/toolbar_actions_model.cc |
| index a50998db3f9c2af102082cddaf041375903a7f05..d1cca37a81ba26f6b62aebe5406c3ec6f825b25f 100644 |
| --- a/chrome/browser/extensions/extension_toolbar_model.cc |
| +++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc |
| @@ -2,7 +2,7 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "chrome/browser/extensions/extension_toolbar_model.h" |
| +#include "chrome/browser/ui/toolbar/toolbar_actions_model.h" |
| #include <algorithm> |
| #include <string> |
| @@ -17,13 +17,17 @@ |
| #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
| #include "chrome/browser/extensions/extension_action_manager.h" |
| #include "chrome/browser/extensions/extension_tab_util.h" |
| -#include "chrome/browser/extensions/extension_toolbar_model_factory.h" |
| #include "chrome/browser/extensions/extension_util.h" |
| #include "chrome/browser/extensions/tab_helper.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/ui/extensions/extension_action_view_controller.h" |
| #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| +#include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h" |
| +#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" |
| +#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" |
| +#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/web_contents.h" |
| @@ -37,101 +41,102 @@ |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/one_shot_event.h" |
| -namespace extensions { |
| - |
| -ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile, |
| - ExtensionPrefs* extension_prefs) |
| +ToolbarActionsModel::ToolbarActionsModel(Profile* profile, |
| + extensions::ExtensionPrefs* extension_prefs) |
| : profile_(profile), |
| extension_prefs_(extension_prefs), |
| prefs_(profile_->GetPrefs()), |
| - extension_action_api_(ExtensionActionAPI::Get(profile_)), |
| - extensions_initialized_(false), |
| - include_all_extensions_(FeatureSwitch::extension_action_redesign() |
| - ->IsEnabled()), |
| + extension_action_api_(extensions::ExtensionActionAPI::Get(profile_)), |
| + actions_initialized_(false), |
| + include_all_actions_( |
|
Devlin
2015/07/29 18:04:04
nit: this should probably stay "include_all_extens
apacible
2015/07/30 22:53:21
Done.
|
| + extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()), |
| + component_ids_(ComponentToolbarActionsFactory::GetComponentIds()), |
| highlight_type_(HIGHLIGHT_NONE), |
| extension_action_observer_(this), |
| extension_registry_observer_(this), |
| weak_ptr_factory_(this) { |
| - ExtensionSystem::Get(profile_)->ready().Post( |
| + extensions::ExtensionSystem::Get(profile_)->ready().Post( |
| FROM_HERE, |
| - base::Bind(&ExtensionToolbarModel::OnReady, |
| + base::Bind(&ToolbarActionsModel::OnReady, |
| weak_ptr_factory_.GetWeakPtr())); |
| - visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize); |
| + visible_icon_count_ = prefs_->GetInteger( |
| + extensions::pref_names::kToolbarSize); |
| // We only care about watching the prefs if not in incognito mode. |
| if (!profile_->IsOffTheRecord()) { |
| pref_change_registrar_.Init(prefs_); |
| pref_change_callback_ = |
| - base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange, |
| + base::Bind(&ToolbarActionsModel::OnActionToolbarPrefChange, |
| base::Unretained(this)); |
| - pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_); |
| + pref_change_registrar_.Add( |
| + extensions::pref_names::kToolbar, pref_change_callback_); |
| } |
| } |
| -ExtensionToolbarModel::~ExtensionToolbarModel() { |
| +ToolbarActionsModel::~ToolbarActionsModel() { |
| } |
| // static |
| -ExtensionToolbarModel* ExtensionToolbarModel::Get(Profile* profile) { |
| - return ExtensionToolbarModelFactory::GetForProfile(profile); |
| +ToolbarActionsModel* ToolbarActionsModel::Get(Profile* profile) { |
| + return ToolbarActionsModelFactory::GetForProfile(profile); |
| } |
| -void ExtensionToolbarModel::AddObserver(Observer* observer) { |
| +void ToolbarActionsModel::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| -void ExtensionToolbarModel::RemoveObserver(Observer* observer) { |
| +void ToolbarActionsModel::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| -void ExtensionToolbarModel::MoveExtensionIcon(const std::string& id, |
| - size_t index) { |
| - ExtensionList::iterator pos = toolbar_items_.begin(); |
| - while (pos != toolbar_items_.end() && (*pos)->id() != id) |
| +void ToolbarActionsModel::MoveActionIcon(const ActionId& id, size_t index) { |
| + ActionIdList::iterator pos = toolbar_items_.begin(); |
| + while (pos != toolbar_items_.end() && (*pos) != id) |
| ++pos; |
| if (pos == toolbar_items_.end()) { |
| NOTREACHED(); |
| return; |
| } |
| - scoped_refptr<const Extension> extension = *pos; |
| + |
| toolbar_items_.erase(pos); |
| - ExtensionIdList::iterator pos_id = std::find(last_known_positions_.begin(), |
| - last_known_positions_.end(), |
| - id); |
| + ActionIdList::iterator pos_id = |
| + std::find(last_known_positions_.begin(), |
| + last_known_positions_.end(), |
| + id); |
| if (pos_id != last_known_positions_.end()) |
| last_known_positions_.erase(pos_id); |
| if (index < toolbar_items_.size()) { |
| // If the index is not at the end, find the item currently at |index|, and |
| - // insert |extension| before it in both |toolbar_items_| and |
| + // insert the action with id |id| before it in both |toolbar_items_| and |
| // |last_known_positions_|. |
| - ExtensionList::iterator iter = toolbar_items_.begin() + index; |
| + ActionIdList::iterator iter = toolbar_items_.begin() + index; |
| last_known_positions_.insert(std::find(last_known_positions_.begin(), |
| last_known_positions_.end(), |
| - (*iter)->id()), |
| + (*iter)), |
| id); |
| - toolbar_items_.insert(iter, extension); |
| + toolbar_items_.insert(iter, id); |
| } else { |
| - // Otherwise, put |extension| at the end. |
| + // Otherwise, put the action at the end. |
| DCHECK_EQ(toolbar_items_.size(), index); |
| index = toolbar_items_.size(); |
| - toolbar_items_.push_back(extension); |
| + toolbar_items_.push_back(id); |
| last_known_positions_.push_back(id); |
| } |
| FOR_EACH_OBSERVER(Observer, observers_, |
| - OnToolbarExtensionMoved(extension.get(), index)); |
| - MaybeUpdateVisibilityPref(extension.get(), index); |
| + OnToolbarActionMoved(id, index)); |
| + MaybeUpdateVisibilityPref(id, index); |
| UpdatePrefs(); |
| } |
| -void ExtensionToolbarModel::SetVisibleIconCount(size_t count) { |
| +void ToolbarActionsModel::SetVisibleIconCount(size_t count) { |
| visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count; |
| // Only set the prefs if we're not in highlight mode and the profile is not |
| // incognito. Highlight mode is designed to be a transitory state, and should |
| - // not persist across browser restarts (though it may be re-entered), and we |
| + // not persist across browser restarts (though it may be re-entered), and we |
| // don't store anything in incognito. |
| if (!is_highlighting() && !profile_->IsOffTheRecord()) { |
| // Additionally, if we are using the new toolbar, any icons which are in the |
| @@ -140,42 +145,90 @@ void ExtensionToolbarModel::SetVisibleIconCount(size_t count) { |
| // in flux. So wait for things to cool down before setting the prefs. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| - base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs, |
| + base::Bind(&ToolbarActionsModel::MaybeUpdateVisibilityPrefs, |
| weak_ptr_factory_.GetWeakPtr())); |
| - prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_); |
| + prefs_->SetInteger(extensions::pref_names::kToolbarSize, |
| + visible_icon_count_); |
| } |
| FOR_EACH_OBSERVER(Observer, observers_, OnToolbarVisibleCountChanged()); |
| } |
| -void ExtensionToolbarModel::OnExtensionActionUpdated( |
| +void ToolbarActionsModel::OnExtensionActionUpdated( |
| ExtensionAction* extension_action, |
| content::WebContents* web_contents, |
| content::BrowserContext* browser_context) { |
| - const Extension* extension = |
| - ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID( |
| - extension_action->extension_id()); |
| + const extensions::Extension* extension = |
| + extensions::ExtensionRegistry::Get(profile_)-> |
| + enabled_extensions().GetByID(extension_action->extension_id()); |
| // Notify observers if the extension exists and is in the model. |
| - if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) != |
| - toolbar_items_.end()) { |
| + if (std::find(toolbar_items_.begin(), toolbar_items_.end(), |
| + extension->id()) != toolbar_items_.end()) { |
| FOR_EACH_OBSERVER(Observer, observers_, |
| - OnToolbarExtensionUpdated(extension)); |
| + OnToolbarActionUpdated(extension->id())); |
| } |
| } |
| -void ExtensionToolbarModel::OnExtensionActionVisibilityChanged( |
| - const std::string& extension_id, |
| - bool is_now_visible) { |
| - const Extension* extension = |
| - ExtensionRegistry::Get(profile_)->GetExtensionById( |
| - extension_id, ExtensionRegistry::EVERYTHING); |
| +ActionList ToolbarActionsModel::GetActions(Browser* browser, |
| + ToolbarActionsBar* bar) { |
|
Devlin
2015/07/29 18:04:04
Sad that this takes a ToolbarActionsBar... but it
apacible
2015/07/30 22:53:21
Acknowledged.
|
| + DCHECK(browser); |
| + ActionList action_list; |
| + |
| + // Get the component action list. |
| + ScopedVector<ToolbarActionViewController> component_actions = |
|
Devlin
2015/07/29 18:04:04
Technically, isn't this an ActionList?
apacible
2015/07/30 22:53:21
Right. Updated.
|
| + ComponentToolbarActionsFactory::GetInstance()-> |
| + GetComponentToolbarActions(browser); |
| + |
| + extensions::ExtensionActionManager* action_manager = |
| + extensions::ExtensionActionManager::Get(profile_); |
| + |
| + // Extension and component actions are suppressed if the extension |
| + // actions are being highlighted. The list of ids to show is kept track |
| + // of in |model_|. |
| + for (std::string action_id : toolbar_items()) { |
|
Devlin
2015/07/29 18:04:04
this results in a copy.
apacible
2015/07/30 22:53:21
Done.
|
| + // Check if current action_id is for an extension. |
|
Devlin
2015/07/29 18:04:04
nit: indentation.
apacible
2015/07/30 22:53:21
Done.
|
| + if (std::find(component_ids_.begin(), component_ids_.end(), |
| + action_id) == component_ids_.end()) { |
| + // Get the extension. |
| + const extensions::Extension* extension = |
| + extensions::ExtensionRegistry::Get( |
| + profile_)->enabled_extensions().GetByID( |
| + action_id); |
|
Devlin
2015/07/29 18:04:04
DCHECK extension, for kicks and grins?
apacible
2015/07/30 22:53:21
Done.
|
| + |
| + // Create and add an ExtensionActionViewController for the extension. |
| + action_list.push_back(new ExtensionActionViewController( |
| + extension, |
| + browser, |
| + action_manager->GetExtensionAction(*extension), |
| + bar)); |
| + } else { |
| + DCHECK(component_actions.empty() || |
|
Devlin
2015/07/29 18:04:04
not sure I understand the first clause. When woul
apacible
2015/07/30 22:53:21
We *shouldn't*. This was overly checking. Updated.
|
| + extensions::FeatureSwitch::extension_action_redesign()-> |
| + IsEnabled()); |
| + // Check if the current action_id is for a valid component action. |
| + for (size_t i = 0; i < component_actions.size(); i++) { |
| + if (component_actions[i]->GetId() == action_id) { |
| + action_list.push_back(component_actions[i]); |
| + continue; |
| + } |
| + } |
| + } |
| + } |
| + component_actions.weak_clear(); |
| + |
| + return action_list.Pass(); |
| +} |
| + |
| +void ToolbarActionsModel::OnExtensionActionVisibilityChanged( |
| + const ActionId& extension_id, |
| + bool is_now_visible) { |
| // Hiding works differently with the new and old toolbars. |
| - if (include_all_extensions_) { |
| - // It's possible that we haven't added this extension yet, if its |
| + if (include_all_actions_) { |
| + // It's possible that we haven't added this action yet, if its |
| // visibility was adjusted in the course of its initialization. |
| - if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) == |
| - toolbar_items_.end()) |
| + if (std::find(toolbar_items_.begin(), toolbar_items_.end(), |
| + extension_id) == toolbar_items_.end()) |
| return; |
| int new_size = 0; |
| @@ -183,20 +236,23 @@ void ExtensionToolbarModel::OnExtensionActionVisibilityChanged( |
| if (is_now_visible) { |
| // If this action used to be hidden, we can't possibly be showing all. |
| DCHECK_LT(visible_icon_count(), toolbar_items_.size()); |
| - // Grow the bar by one and move the extension to the end of the visibles. |
| + // Grow the bar by one and move the action to the end of the visibles. |
| new_size = visible_icon_count() + 1; |
| new_index = new_size - 1; |
| } else { |
| // If we're hiding one, we must be showing at least one. |
| DCHECK_GE(visible_icon_count(), 0u); |
| - // Shrink the bar by one and move the extension to the beginning of the |
| + // Shrink the bar by one and move the action to the beginning of the |
| // overflow menu. |
| new_size = visible_icon_count() - 1; |
| new_index = new_size; |
| } |
| SetVisibleIconCount(new_size); |
| - MoveExtensionIcon(extension->id(), new_index); |
| + MoveActionIcon(extension_id, new_index); |
| } else { // Don't include all extensions. |
| + const extensions::Extension* extension = |
| + extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( |
| + extension_id, extensions::ExtensionRegistry::EVERYTHING); |
| if (is_now_visible) |
| AddExtension(extension); |
| else |
| @@ -204,34 +260,34 @@ void ExtensionToolbarModel::OnExtensionActionVisibilityChanged( |
| } |
| } |
| -void ExtensionToolbarModel::OnExtensionLoaded( |
| +void ToolbarActionsModel::OnExtensionLoaded( |
| content::BrowserContext* browser_context, |
| - const Extension* extension) { |
| + const extensions::Extension* extension) { |
| // We don't want to add the same extension twice. It may have already been |
| // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user |
| // hides the browser action and then disables and enables the extension. |
| for (size_t i = 0; i < toolbar_items_.size(); i++) { |
| - if (toolbar_items_[i].get() == extension) |
| + if (toolbar_items_[i] == extension->id()) |
| return; |
| } |
| AddExtension(extension); |
| } |
| -void ExtensionToolbarModel::OnExtensionUnloaded( |
| +void ToolbarActionsModel::OnExtensionUnloaded( |
| content::BrowserContext* browser_context, |
| - const Extension* extension, |
| - UnloadedExtensionInfo::Reason reason) { |
| + const extensions::Extension* extension, |
| + extensions::UnloadedExtensionInfo::Reason reason) { |
| RemoveExtension(extension); |
| } |
| -void ExtensionToolbarModel::OnExtensionUninstalled( |
| +void ToolbarActionsModel::OnExtensionUninstalled( |
| content::BrowserContext* browser_context, |
| - const Extension* extension, |
| + const extensions::Extension* extension, |
| extensions::UninstallReason reason) { |
| // Remove the extension id from the ordered list, if it exists (the extension |
| // might not be represented in the list because it might not have an icon). |
| - ExtensionIdList::iterator pos = |
| + ActionIdList::iterator pos = |
| std::find(last_known_positions_.begin(), |
| last_known_positions_.end(), extension->id()); |
| @@ -241,9 +297,10 @@ void ExtensionToolbarModel::OnExtensionUninstalled( |
| } |
| } |
| -void ExtensionToolbarModel::OnReady() { |
| - ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| - InitializeExtensionList(); |
| +void ToolbarActionsModel::OnReady() { |
| + extensions::ExtensionRegistry* registry = |
| + extensions::ExtensionRegistry::Get(profile_); |
| + InitializeActionList(); |
| // Wait until the extension system is ready before observing any further |
| // changes so that the toolbar buttons can be shown in their stable ordering |
| // taken from prefs. |
| @@ -251,31 +308,32 @@ void ExtensionToolbarModel::OnReady() { |
| extension_action_observer_.Add(extension_action_api_); |
| if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile( |
| - profile_)) { |
| - ExtensionIdList ids; |
| - for (const auto& extension : toolbar_items_) |
| - ids.push_back(extension->id()); |
| - HighlightExtensions(ids, HIGHLIGHT_INFO); |
| + profile_)) { |
| + ActionIdList ids; |
| + for (const auto& extension_id : toolbar_items_) |
| + ids.push_back(extension_id); |
| + HighlightActions(ids, HIGHLIGHT_INFO); |
| } |
| - extensions_initialized_ = true; |
| + actions_initialized_ = true; |
| FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized()); |
| } |
| -size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood( |
| - const Extension* extension) { |
| +size_t ToolbarActionsModel::FindNewPositionFromLastKnownGood( |
| + const extensions::Extension* extension) { |
|
Devlin
2015/07/29 18:04:04
Shouldn't this take an id? Can't this be used for
apacible
2015/07/30 22:53:21
It's only used for AddExtension(Extension...), so
Devlin
2015/08/03 20:58:30
Yes, please.
apacible
2015/08/04 22:15:58
Done.
|
| // See if we have last known good position for this extension. |
| size_t new_index = 0; |
| // Loop through the ID list of known positions, to count the number of visible |
| // extension icons preceding |extension|. |
| - for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin(); |
| - iter_id < last_known_positions_.end(); ++iter_id) { |
| + for (ActionIdList::const_iterator iter_id = |
| + last_known_positions_.begin(); iter_id < last_known_positions_.end(); |
| + ++iter_id) { |
| if ((*iter_id) == extension->id()) |
| return new_index; // We've found the right position. |
| // Found an id, need to see if it is visible. |
| - for (ExtensionList::const_iterator iter_ext = toolbar_items_.begin(); |
| - iter_ext < toolbar_items_.end(); ++iter_ext) { |
| - if ((*iter_ext)->id() == (*iter_id)) { |
| + for (ActionIdList::const_iterator iter_ext = |
| + toolbar_items_.begin(); iter_ext < toolbar_items_.end(); ++iter_ext) { |
| + if ((*iter_ext) == (*iter_id)) { |
| // This extension is visible, update the index value. |
| ++new_index; |
| break; |
| @@ -287,15 +345,16 @@ size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood( |
| return toolbar_items_.size(); |
| } |
| -bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) { |
| +bool ToolbarActionsModel::ShouldAddExtension( |
| + const extensions::Extension* extension) { |
| // In incognito mode, don't add any extensions that aren't incognito-enabled. |
| if (profile_->IsOffTheRecord() && |
| - !util::IsIncognitoEnabled(extension->id(), profile_)) |
| + !extensions::util::IsIncognitoEnabled(extension->id(), profile_)) |
| return false; |
| - ExtensionActionManager* action_manager = |
| - ExtensionActionManager::Get(profile_); |
| - if (include_all_extensions_) { |
| + extensions::ExtensionActionManager* action_manager = |
| + extensions::ExtensionActionManager::Get(profile_); |
| + if (include_all_actions_) { |
| // In this case, we don't care about the browser action visibility, because |
| // we want to show each extension regardless. |
| // TODO(devlin): Extension actions which are not visible should be moved to |
| @@ -307,9 +366,9 @@ bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) { |
| extension_action_api_->GetBrowserActionVisibility(extension->id()); |
| } |
| -void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| +void ToolbarActionsModel::AddExtension(const extensions::Extension* extension) { |
| // We only use AddExtension() once the system is initialized. |
| - DCHECK(extensions_initialized_); |
| + DCHECK(actions_initialized_); |
| if (!ShouldAddExtension(extension)) |
| return; |
| @@ -323,8 +382,8 @@ void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| // extensions go at their previous position. |
| size_t new_index = 0; |
| if (is_new_extension) { |
| - new_index = Manifest::IsComponentLocation(extension->location()) ? |
| - 0 : visible_icon_count(); |
| + new_index = extensions::Manifest::IsComponentLocation( |
| + extension->location()) ? 0 : visible_icon_count(); |
| // For the last-known position, we use the index of the extension that is |
| // just before this extension, plus one. (Note that this isn't the same |
| // as new_index + 1, because last_known_positions_ can include disabled |
| @@ -333,7 +392,7 @@ void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| new_index == 0 ? 0 : |
| std::find(last_known_positions_.begin(), |
| last_known_positions_.end(), |
| - toolbar_items_[new_index - 1]->id()) - |
| + toolbar_items_[new_index - 1]) - |
| last_known_positions_.begin() + 1; |
| // In theory, the extension before this one should always |
| // be in last known positions, but if something funny happened with prefs, |
| @@ -348,14 +407,14 @@ void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| new_index = FindNewPositionFromLastKnownGood(extension); |
| } |
| - toolbar_items_.insert(toolbar_items_.begin() + new_index, extension); |
| + toolbar_items_.insert(toolbar_items_.begin() + new_index, extension->id()); |
| // If we're currently highlighting, then even though we add a browser action |
| // to the full list (|toolbar_items_|, there won't be another *visible* |
| // browser action, which was what the observers care about. |
| if (!is_highlighting()) { |
| FOR_EACH_OBSERVER(Observer, observers_, |
| - OnToolbarExtensionAdded(extension, new_index)); |
| + OnToolbarActionAdded(extension->id(), new_index)); |
| int visible_count_delta = 0; |
| if (is_new_extension && !all_icons_visible()) { |
| @@ -365,8 +424,8 @@ void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| } else if (profile_->IsOffTheRecord()) { |
| // If this is an incognito profile, we also have to check to make sure the |
| // overflow matches the main bar's status. |
| - ExtensionToolbarModel* main_model = |
| - ExtensionToolbarModel::Get(profile_->GetOriginalProfile()); |
| + ToolbarActionsModel* main_model = |
| + ToolbarActionsModel::Get(profile_->GetOriginalProfile()); |
| // Find what the index will be in the main bar. Because Observer calls are |
| // nondeterministic, we can't just assume the main bar will have the |
| // extension and look it up. |
| @@ -386,12 +445,14 @@ void ExtensionToolbarModel::AddExtension(const Extension* extension) { |
| SetVisibleIconCount(visible_icon_count() + visible_count_delta); |
| } |
| - MaybeUpdateVisibilityPref(extension, new_index); |
| + MaybeUpdateVisibilityPref(extension->id(), new_index); |
| } |
| -void ExtensionToolbarModel::RemoveExtension(const Extension* extension) { |
| - ExtensionList::iterator pos = |
| - std::find(toolbar_items_.begin(), toolbar_items_.end(), extension); |
| +void ToolbarActionsModel::RemoveExtension( |
| + const extensions::Extension* extension) { |
| + ActionIdList::iterator pos = |
| + std::find(toolbar_items_.begin(), toolbar_items_.end(), |
| + extension->id()); |
| if (pos == toolbar_items_.end()) |
| return; |
| @@ -406,31 +467,32 @@ void ExtensionToolbarModel::RemoveExtension(const Extension* extension) { |
| if (is_highlighting()) { |
| pos = std::find(highlighted_items_.begin(), |
| highlighted_items_.end(), |
| - extension); |
| + extension->id()); |
| if (pos != highlighted_items_.end()) { |
| highlighted_items_.erase(pos); |
| FOR_EACH_OBSERVER(Observer, observers_, |
| - OnToolbarExtensionRemoved(extension)); |
| + OnToolbarActionRemoved(extension->id())); |
| // If the highlighted list is now empty, we stop highlighting. |
| if (highlighted_items_.empty()) |
| StopHighlighting(); |
| } |
| } else { |
| FOR_EACH_OBSERVER(Observer, observers_, |
| - OnToolbarExtensionRemoved(extension)); |
| + OnToolbarActionRemoved(extension->id())); |
| } |
| UpdatePrefs(); |
| } |
| // Combine the currently enabled extensions that have browser actions (which |
| -// we get from the ExtensionRegistry) with the ordering we get from the |
| -// pref service. For robustness we use a somewhat inefficient process: |
| -// 1. Create a vector of extensions sorted by their pref values. This vector may |
| +// we get from the ExtensionRegistry) and component actions (which we get from |
| +// ComponentToolbarActionsFactory ) with the ordering we get from the pref |
| +// service. For robustness we use a somewhat inefficient process: |
| +// 1. Create a vector of actions sorted by their pref values. This vector may |
| // have holes. |
| -// 2. Create a vector of extensions that did not have a pref value. |
| +// 2. Create a vector of actions that did not have a pref value. |
| // 3. Remove holes from the sorted vector and append the unsorted vector. |
| -void ExtensionToolbarModel::InitializeExtensionList() { |
| +void ToolbarActionsModel::InitializeActionList() { |
| DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet. |
| last_known_positions_ = extension_prefs_->GetToolbarOrder(); |
| @@ -442,57 +504,90 @@ void ExtensionToolbarModel::InitializeExtensionList() { |
| MaybeUpdateVisibilityPrefs(); |
| } |
| -void ExtensionToolbarModel::Populate(ExtensionIdList* positions) { |
| +void ToolbarActionsModel::Populate(ActionIdList* positions) { |
| DCHECK(!profile_->IsOffTheRecord()); |
| - const ExtensionSet& extensions = |
| - ExtensionRegistry::Get(profile_)->enabled_extensions(); |
| + |
| // Items that have explicit positions. |
| - ExtensionList sorted(positions->size(), NULL); |
| + ActionIdList sorted(positions->size()); |
| // The items that don't have explicit positions. |
| - ExtensionList unsorted; |
| + ActionIdList unsorted; |
| - // Create the lists. |
| + // Populate the lists. |
| int hidden = 0; |
| - for (const scoped_refptr<const Extension>& extension : extensions) { |
| + |
| + // First, add the extension action ids to the lists. |
| + const extensions::ExtensionSet& extensions = |
| + extensions::ExtensionRegistry::Get(profile_)->enabled_extensions(); |
| + for (const scoped_refptr<const extensions::Extension>& extension : |
| + extensions) { |
| if (!ShouldAddExtension(extension.get())) { |
| if (!extension_action_api_->GetBrowserActionVisibility(extension->id())) |
| ++hidden; |
| continue; |
| } |
| - ExtensionIdList::const_iterator pos = |
| + ActionIdList::const_iterator pos = |
| std::find(positions->begin(), positions->end(), extension->id()); |
| if (pos != positions->end()) { |
| - sorted[pos - positions->begin()] = extension; |
| + sorted[pos - positions->begin()] = extension->id(); |
| } else { |
| // Unknown extension - push it to the back of unsorted, and add it to the |
| // list of ids at the end. |
| - unsorted.push_back(extension); |
| + unsorted.push_back(extension->id()); |
| positions->push_back(extension->id()); |
| } |
| } |
| + // Next, add the component action ids to the lists. |
| + for (ActionIdList::const_iterator it = component_ids_.begin(); |
| + it != component_ids_.end(); ++it) { |
| + ActionIdList::const_iterator pos = |
| + std::find(positions->begin(), positions->end(), (*it)); |
| + if (pos != positions->end()) { |
| + sorted[pos - positions->begin()] = (*it); |
| + } else { |
| + // New component - push it to the back of unsorted, and add it to the |
| + // list of ids at the end. This should only be the case when there is |
| + // a browser feature using a new component action. |
| + unsorted.push_back((*it)); |
| + positions->push_back((*it)); |
| + } |
| + } |
| + |
| // Merge the lists. |
| sorted.insert(sorted.end(), unsorted.begin(), unsorted.end()); |
| toolbar_items_.reserve(sorted.size()); |
| - for (const scoped_refptr<const Extension>& extension : sorted) { |
| - // It's possible for the extension order to contain items that aren't |
| - // actually loaded on this machine. For example, when extension sync is on, |
| - // we sync the extension order as-is but double-check with the user before |
| - // syncing NPAPI-containing extensions, so if one of those is not actually |
| - // synced, we'll get a NULL in the list. This sort of case can also happen |
| - // if some error prevents an extension from loading. |
| - if (extension.get()) { |
| - // We don't notify observers of the added extension yet. Rather, observers |
| - // should wait for the "OnToolbarModelInitialized" notification, and then |
| - // bulk-update. (This saves a lot of bouncing-back-and-forth here, and |
| - // allows observers to ensure that the extension system is always |
| - // initialized before using the extensions). |
| - toolbar_items_.push_back(extension); |
| + for (const ActionId& action_id : sorted) { |
| + // Check if this the current action_id is an extension or component |
| + // action i. |
| + if (std::find(component_ids_.begin(), component_ids_.end(), action_id) == |
| + component_ids_.end()) { |
| + // It's possible for the extension order to contain items that aren't |
| + // actually loaded on this machine. For example, when extension sync is |
| + // on, we sync the extension order as-is but double-check with the user |
| + // before syncing NPAPI-containing extensions, so if one of those is not |
| + // actually synced, we'll get a NULL in the list. This sort of case can |
| + // also happen if some error prevents an extension from loading. |
| + if (extensions::ExtensionRegistry::Get( |
| + profile_)->enabled_extensions().GetByID( |
| + action_id)) { |
| + // We don't notify observers of the added extension yet. Rather, |
| + // observers should wait for the "OnToolbarModelInitialized" |
| + // notification, and then bulk-update. (This saves a lot of |
| + // bouncing-back-and-forth here, and allows observers to ensure that |
| + // the extension system is always initialized before using the |
| + // extensions). |
| + toolbar_items_.push_back(action_id); |
| + } |
| + } else { |
| + // Always add component actions. |
| + toolbar_items_.push_back(action_id); |
| } |
| } |
| + // Histogram names are prefixed with "ExtensionToolbarModel" rather than |
| + // "ToolbarActionsModel" for historical reasons. |
| UMA_HISTOGRAM_COUNTS_100( |
| "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden); |
| UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount", |
| @@ -509,22 +604,33 @@ void ExtensionToolbarModel::Populate(ExtensionIdList* positions) { |
| } |
| } |
| -void ExtensionToolbarModel::IncognitoPopulate() { |
| +void ToolbarActionsModel::IncognitoPopulate() { |
| DCHECK(profile_->IsOffTheRecord()); |
| - const ExtensionToolbarModel* original_model = |
| - ExtensionToolbarModel::Get(profile_->GetOriginalProfile()); |
| + const ToolbarActionsModel* original_model = |
| + ToolbarActionsModel::Get(profile_->GetOriginalProfile()); |
| // Find the absolute value of the original model's count. |
| int original_visible = original_model->visible_icon_count(); |
| - // In incognito mode, we show only those extensions that are |
| - // incognito-enabled. Further, any actions that were overflowed in regular |
| - // mode are still overflowed. Order is the same as in regular mode. |
| + // In incognito mode, we show only those actions that are incognito-enabled |
| + // Further, any actions that were overflowed in regular mode are still |
| + // overflowed. Order is the same as in regular mode. |
| visible_icon_count_ = 0; |
| - for (ExtensionList::const_iterator iter = |
| + for (ActionIdList::const_iterator iter = |
| original_model->toolbar_items_.begin(); |
| iter != original_model->toolbar_items_.end(); ++iter) { |
| - if (ShouldAddExtension(iter->get())) { |
| + if (std::find(component_ids_.begin(), component_ids_.end(), |
| + *iter) == component_ids_.end()) { |
| + const extensions::Extension* extension = |
| + extensions::ExtensionRegistry::Get(profile_)-> |
| + enabled_extensions().GetByID((*iter)); |
| + if (ShouldAddExtension(extension)) { |
| + toolbar_items_.push_back(*iter); |
| + if (iter - original_model->toolbar_items_.begin() < original_visible) |
| + ++visible_icon_count_; |
| + } |
| + } else { |
| + // Always show component actions. |
| toolbar_items_.push_back(*iter); |
| if (iter - original_model->toolbar_items_.begin() < original_visible) |
| ++visible_icon_count_; |
| @@ -532,51 +638,55 @@ void ExtensionToolbarModel::IncognitoPopulate() { |
| } |
| } |
| -void ExtensionToolbarModel::UpdatePrefs() { |
| +void ToolbarActionsModel::UpdatePrefs() { |
| if (!extension_prefs_ || profile_->IsOffTheRecord()) |
| return; |
| // Don't observe change caused by self. |
| - pref_change_registrar_.Remove(pref_names::kToolbar); |
| + pref_change_registrar_.Remove(extensions::pref_names::kToolbar); |
| extension_prefs_->SetToolbarOrder(last_known_positions_); |
| - pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_); |
| + pref_change_registrar_.Add(extensions::pref_names::kToolbar, |
| + pref_change_callback_); |
| } |
| -void ExtensionToolbarModel::MaybeUpdateVisibilityPref( |
| - const Extension* extension, size_t index) { |
| +void ToolbarActionsModel::MaybeUpdateVisibilityPref( |
| + const ActionId id, size_t index) { |
| + // Component Actions are always shown; visibility should not change. |
| + if (std::find(component_ids_.begin(), component_ids_.end(), id) != |
| + component_ids_.end()) |
| + return; |
| + |
| // We only update the visibility pref for hidden/not hidden based on the |
| // overflow menu with the new toolbar design. |
| - if (include_all_extensions_ && !profile_->IsOffTheRecord()) { |
| + if (include_all_actions_ && !profile_->IsOffTheRecord()) { |
| bool visible = index < visible_icon_count(); |
| - if (visible != extension_action_api_->GetBrowserActionVisibility( |
| - extension->id())) { |
| + if (visible != extension_action_api_->GetBrowserActionVisibility(id)) { |
| // Don't observe changes caused by ourselves. |
| bool was_registered = false; |
| if (extension_action_observer_.IsObserving(extension_action_api_)) { |
| was_registered = true; |
| extension_action_observer_.RemoveAll(); |
| } |
| - extension_action_api_->SetBrowserActionVisibility(extension->id(), |
| - visible); |
| + extension_action_api_->SetBrowserActionVisibility(id, visible); |
| if (was_registered) |
| extension_action_observer_.Add(extension_action_api_); |
| } |
| } |
| } |
| -void ExtensionToolbarModel::MaybeUpdateVisibilityPrefs() { |
| +void ToolbarActionsModel::MaybeUpdateVisibilityPrefs() { |
| for (size_t i = 0u; i < toolbar_items_.size(); ++i) |
| - MaybeUpdateVisibilityPref(toolbar_items_[i].get(), i); |
| + MaybeUpdateVisibilityPref(toolbar_items_[i], i); |
| } |
| -void ExtensionToolbarModel::OnExtensionToolbarPrefChange() { |
| +void ToolbarActionsModel::OnActionToolbarPrefChange() { |
| // If extensions are not ready, defer to later Populate() call. |
| - if (!extensions_initialized_) |
| + if (!actions_initialized_) |
| return; |
| // Recalculate |last_known_positions_| to be |pref_positions| followed by |
| // ones that are only in |last_known_positions_|. |
| - ExtensionIdList pref_positions = extension_prefs_->GetToolbarOrder(); |
| + ActionIdList pref_positions = extension_prefs_->GetToolbarOrder(); |
| size_t pref_position_size = pref_positions.size(); |
| for (size_t i = 0; i < last_known_positions_.size(); ++i) { |
| if (std::find(pref_positions.begin(), pref_positions.end(), |
| @@ -589,18 +699,19 @@ void ExtensionToolbarModel::OnExtensionToolbarPrefChange() { |
| int desired_index = 0; |
| // Loop over the updated list of last known positions, moving any extensions |
| // that are in the wrong place. |
| - for (const std::string& id : last_known_positions_) { |
| + for (const ActionId& id : last_known_positions_) { |
| int current_index = GetIndexForId(id); |
| if (current_index == -1) |
| continue; |
| if (current_index != desired_index) { |
| - scoped_refptr<const Extension> extension = toolbar_items_[current_index]; |
| + ActionId extension_id = toolbar_items_[current_index]; |
| toolbar_items_.erase(toolbar_items_.begin() + current_index); |
| - toolbar_items_.insert(toolbar_items_.begin() + desired_index, extension); |
| + toolbar_items_.insert(toolbar_items_.begin() + desired_index, |
| + extension_id); |
| // Notify the observers to keep them up-to-date. |
| FOR_EACH_OBSERVER( |
| Observer, observers_, |
| - OnToolbarExtensionMoved(extension.get(), desired_index)); |
| + OnToolbarActionMoved(extension_id, desired_index)); |
| } |
| ++desired_index; |
| } |
| @@ -609,23 +720,22 @@ void ExtensionToolbarModel::OnExtensionToolbarPrefChange() { |
| // Need to update pref because we have extra icons. But can't call |
| // UpdatePrefs() directly within observation closure. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, base::Bind(&ExtensionToolbarModel::UpdatePrefs, |
| + FROM_HERE, base::Bind(&ToolbarActionsModel::UpdatePrefs, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| -int ExtensionToolbarModel::GetIndexForId(const std::string& id) const { |
| - for (size_t i = 0; i < toolbar_items().size(); ++i) { |
| - if (toolbar_items()[i]->id() == id) |
| +int ToolbarActionsModel::GetIndexForId(const ActionId& id) const { |
| + for (size_t i = 0; i < toolbar_items_.size(); ++i) { |
| + if (toolbar_items_[i] == id) |
| return i; |
| } |
| return -1; |
| } |
| -bool ExtensionToolbarModel::ShowExtensionActionPopup( |
| - const Extension* extension, |
| - Browser* browser, |
| - bool grant_active_tab) { |
| +bool ToolbarActionsModel::ShowToolbarActionPopup(const ActionId id, |
| + Browser* browser, |
| + bool grant_active_tab) { |
| base::ObserverListBase<Observer>::Iterator it(&observers_); |
| Observer* obs = NULL; |
| // Look for the Observer associated with the browser. |
| @@ -633,52 +743,48 @@ bool ExtensionToolbarModel::ShowExtensionActionPopup( |
| // (like we do for LocationBar), but sadly, we don't. |
| while ((obs = it.GetNext()) != NULL) { |
| if (obs->GetBrowser() == browser) |
| - return obs->ShowExtensionActionPopup(extension, grant_active_tab); |
| + return obs->ShowToolbarActionPopup(id, grant_active_tab); |
| } |
| return false; |
| } |
| -void ExtensionToolbarModel::EnsureVisibility( |
| - const ExtensionIdList& extension_ids) { |
| +void ToolbarActionsModel::EnsureVisibility(const ActionIdList& ids) { |
| if (all_icons_visible()) |
| return; // Already showing all. |
| // Otherwise, make sure we have enough room to show all the extensions |
| // requested. |
| - if (visible_icon_count() < extension_ids.size()) |
| - SetVisibleIconCount(extension_ids.size()); |
| + if (visible_icon_count() < ids.size()) |
| + SetVisibleIconCount(ids.size()); |
| if (all_icons_visible()) |
| return; // May have been set to max by SetVisibleIconCount. |
| // Guillotine's Delight: Move an orange noble to the front of the line. |
| - for (ExtensionIdList::const_iterator it = extension_ids.begin(); |
| - it != extension_ids.end(); ++it) { |
| - for (ExtensionList::const_iterator extension = toolbar_items_.begin(); |
| - extension != toolbar_items_.end(); ++extension) { |
| - if ((*extension)->id() == (*it)) { |
| - if (extension - toolbar_items_.begin() >= |
| - static_cast<int>(visible_icon_count())) |
| - MoveExtensionIcon((*extension)->id(), 0); |
| + for (ActionIdList::const_iterator it = ids.begin(); |
| + it != ids.end(); ++it) { |
| + for (ActionIdList::const_iterator id = toolbar_items_.begin(); |
| + id != toolbar_items_.end(); ++id) { |
| + if ((*id) == (*it)) { |
| + if (id - toolbar_items_.begin() >= |
| + static_cast<int>(visible_icon_count())) |
| + MoveActionIcon((*id), 0); |
| break; |
| } |
| } |
| } |
| } |
| -bool ExtensionToolbarModel::HighlightExtensions( |
| - const ExtensionIdList& extension_ids, |
| - HighlightType highlight_type) { |
| +bool ToolbarActionsModel::HighlightActions(const ActionIdList& ids, |
| + HighlightType highlight_type) { |
| highlighted_items_.clear(); |
| - for (ExtensionIdList::const_iterator id = extension_ids.begin(); |
| - id != extension_ids.end(); |
| - ++id) { |
| - for (ExtensionList::const_iterator extension = toolbar_items_.begin(); |
| - extension != toolbar_items_.end(); |
| - ++extension) { |
| - if (*id == (*extension)->id()) |
| - highlighted_items_.push_back(*extension); |
| + for (ActionIdList::const_iterator action_id = ids.begin(); |
| + action_id != ids.end(); ++action_id) { |
| + for (ActionIdList::const_iterator toolbar_item_id = toolbar_items_.begin(); |
| + toolbar_item_id != toolbar_items_.end(); ++toolbar_item_id) { |
| + if ((*action_id) == (*toolbar_item_id)) |
| + highlighted_items_.push_back(*toolbar_item_id); |
| } |
| } |
| @@ -694,8 +800,8 @@ bool ExtensionToolbarModel::HighlightExtensions( |
| // We set the visible icon count after the highlight mode change because |
| // the UI actions are created/destroyed during highlight, and doing that |
| // prior to changing the size allows us to still have smooth animations. |
| - if (visible_icon_count() < extension_ids.size()) |
| - SetVisibleIconCount(extension_ids.size()); |
| + if (visible_icon_count() < ids.size()) |
| + SetVisibleIconCount(ids.size()); |
| return true; |
| } |
| @@ -707,7 +813,7 @@ bool ExtensionToolbarModel::HighlightExtensions( |
| return false; |
| } |
| -void ExtensionToolbarModel::StopHighlighting() { |
| +void ToolbarActionsModel::StopHighlighting() { |
| if (is_highlighting()) { |
| // It's important that is_highlighting_ is changed immediately before the |
| // observers are notified since it changes the result of toolbar_items(). |
| @@ -722,21 +828,27 @@ void ExtensionToolbarModel::StopHighlighting() { |
| // We set the visible icon count after the highlight mode change because |
| // the UI actions are created/destroyed during highlight, and doing that |
| // prior to changing the size allows us to still have smooth animations. |
| - int saved_icon_count = prefs_->GetInteger(pref_names::kToolbarSize); |
| + int saved_icon_count = prefs_->GetInteger( |
| + extensions::pref_names::kToolbarSize); |
| if (saved_icon_count != visible_icon_count_) |
| SetVisibleIconCount(saved_icon_count); |
| } |
| } |
| -bool ExtensionToolbarModel::RedesignIsShowingNewIcons() const { |
| - for (const scoped_refptr<const Extension>& extension : toolbar_items_) { |
| - // Without the redesign, we only show extensions with browser actions. |
| - // Any extension without a browser action is an indication that we're |
| - // showing something new. |
| - if (!extension->manifest()->HasKey(manifest_keys::kBrowserAction)) |
| - return true; |
| +bool ToolbarActionsModel::RedesignIsShowingNewIcons() const { |
| + for (ActionId id : toolbar_items_) { |
| + if (std::find(component_ids_.begin(), component_ids_.end(), id) == |
| + component_ids_.end()) { |
| + const extensions::Extension* extension = |
| + extensions::ExtensionRegistry::Get(profile_)-> |
| + enabled_extensions().GetByID(id); |
| + // Without the redesign, we only show extensions with browser actions. |
| + // Any extension without a browser action is an indication that we're |
| + // showing something new. |
| + if (!extension->manifest()->HasKey( |
| + extensions::manifest_keys::kBrowserAction)) |
| + return true; |
| + } |
| } |
| return false; |
| } |
| - |
| -} // namespace extensions |