Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: chrome/browser/ui/toolbar/toolbar_actions_model.cc

Issue 1241063003: Support Component Actions in the toolbar. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes per mfoltz@'s comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension_toolbar_model.h" 5 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/metrics/histogram_base.h" 12 #include "base/metrics/histogram_base.h"
13 #include "base/prefs/pref_service.h" 13 #include "base/prefs/pref_service.h"
14 #include "base/single_thread_task_runner.h" 14 #include "base/single_thread_task_runner.h"
15 #include "base/thread_task_runner_handle.h" 15 #include "base/thread_task_runner_handle.h"
16 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
18 #include "chrome/browser/extensions/extension_action_manager.h" 17 #include "chrome/browser/extensions/extension_action_manager.h"
19 #include "chrome/browser/extensions/extension_tab_util.h" 18 #include "chrome/browser/extensions/extension_tab_util.h"
20 #include "chrome/browser/extensions/extension_toolbar_model_factory.h"
21 #include "chrome/browser/extensions/extension_util.h" 19 #include "chrome/browser/extensions/extension_util.h"
22 #include "chrome/browser/extensions/tab_helper.h" 20 #include "chrome/browser/extensions/tab_helper.h"
23 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
25 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_d elegate.h" 24 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_d elegate.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h" 25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
27 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
28 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
29 #include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
27 #include "content/public/browser/notification_details.h" 30 #include "content/public/browser/notification_details.h"
28 #include "content/public/browser/notification_source.h" 31 #include "content/public/browser/notification_source.h"
29 #include "content/public/browser/web_contents.h" 32 #include "content/public/browser/web_contents.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_registry.h" 33 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h" 34 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/pref_names.h" 35 #include "extensions/browser/pref_names.h"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/extension_set.h" 36 #include "extensions/common/extension_set.h"
36 #include "extensions/common/feature_switch.h" 37 #include "extensions/common/feature_switch.h"
37 #include "extensions/common/manifest_constants.h" 38 #include "extensions/common/manifest_constants.h"
38 #include "extensions/common/one_shot_event.h" 39 #include "extensions/common/one_shot_event.h"
39 40
40 namespace extensions { 41 ToolbarActionsModel::ToolbarActionsModel(Profile* profile,
41 42 extensions::ExtensionPrefs* extension_prefs)
42 ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile,
43 ExtensionPrefs* extension_prefs)
44 : profile_(profile), 43 : profile_(profile),
45 extension_prefs_(extension_prefs), 44 prefs_service_(extension_prefs),
46 prefs_(profile_->GetPrefs()), 45 prefs_(profile_->GetPrefs()),
47 extension_action_api_(ExtensionActionAPI::Get(profile_)), 46 extension_action_api_(extensions::ExtensionActionAPI::Get(profile_)),
48 extensions_initialized_(false), 47 extension_registry_(extensions::ExtensionRegistry::Get(profile_)),
49 include_all_extensions_(FeatureSwitch::extension_action_redesign() 48 actions_initialized_(false),
50 ->IsEnabled()), 49 include_all_extensions_(
Devlin 2015/08/06 22:04:56 Let's just rename this to, like, use_redesign_.
apacible 2015/08/10 22:38:10 Done.
50 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()),
51 highlight_type_(HIGHLIGHT_NONE), 51 highlight_type_(HIGHLIGHT_NONE),
52 extension_action_observer_(this), 52 extension_action_observer_(this),
53 extension_registry_observer_(this), 53 extension_registry_observer_(this),
54 weak_ptr_factory_(this) { 54 weak_ptr_factory_(this) {
55 ExtensionSystem::Get(profile_)->ready().Post( 55 extensions::ExtensionSystem::Get(profile_)->ready().Post(
56 FROM_HERE, 56 FROM_HERE,
57 base::Bind(&ExtensionToolbarModel::OnReady, 57 base::Bind(&ToolbarActionsModel::OnReady,
58 weak_ptr_factory_.GetWeakPtr())); 58 weak_ptr_factory_.GetWeakPtr()));
59 visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize); 59 visible_icon_count_ = prefs_->GetInteger(
60 extensions::pref_names::kToolbarSize);
60 61
61 // We only care about watching the prefs if not in incognito mode. 62 // We only care about watching the prefs if not in incognito mode.
62 if (!profile_->IsOffTheRecord()) { 63 if (!profile_->IsOffTheRecord()) {
63 pref_change_registrar_.Init(prefs_); 64 pref_change_registrar_.Init(prefs_);
64 pref_change_callback_ = 65 pref_change_callback_ =
65 base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange, 66 base::Bind(&ToolbarActionsModel::OnActionToolbarPrefChange,
66 base::Unretained(this)); 67 base::Unretained(this));
67 pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_); 68 pref_change_registrar_.Add(
69 extensions::pref_names::kToolbar, pref_change_callback_);
68 } 70 }
69 } 71 }
70 72
71 ExtensionToolbarModel::~ExtensionToolbarModel() { 73 ToolbarActionsModel::~ToolbarActionsModel() {
72 } 74 }
73 75
74 // static 76 // static
75 ExtensionToolbarModel* ExtensionToolbarModel::Get(Profile* profile) { 77 ToolbarActionsModel* ToolbarActionsModel::Get(Profile* profile) {
76 return ExtensionToolbarModelFactory::GetForProfile(profile); 78 return ToolbarActionsModelFactory::GetForProfile(profile);
77 } 79 }
78 80
79 void ExtensionToolbarModel::AddObserver(Observer* observer) { 81 void ToolbarActionsModel::AddObserver(Observer* observer) {
80 observers_.AddObserver(observer); 82 observers_.AddObserver(observer);
81 } 83 }
82 84
83 void ExtensionToolbarModel::RemoveObserver(Observer* observer) { 85 void ToolbarActionsModel::RemoveObserver(Observer* observer) {
84 observers_.RemoveObserver(observer); 86 observers_.RemoveObserver(observer);
85 } 87 }
86 88
87 void ExtensionToolbarModel::MoveExtensionIcon(const std::string& id, 89 void ToolbarActionsModel::MoveActionIcon(const std::string& id, size_t index) {
88 size_t index) { 90 ActionIdList::iterator pos = toolbar_items_.begin();
89 ExtensionList::iterator pos = toolbar_items_.begin(); 91 while (pos != toolbar_items_.end() && (*pos) != id)
90 while (pos != toolbar_items_.end() && (*pos)->id() != id)
91 ++pos; 92 ++pos;
92 if (pos == toolbar_items_.end()) { 93 if (pos == toolbar_items_.end()) {
93 NOTREACHED(); 94 NOTREACHED();
94 return; 95 return;
95 } 96 }
96 scoped_refptr<const Extension> extension = *pos; 97
97 toolbar_items_.erase(pos); 98 toolbar_items_.erase(pos);
98 99
99 ExtensionIdList::iterator pos_id = std::find(last_known_positions_.begin(), 100 ActionIdList::iterator pos_id =
100 last_known_positions_.end(), 101 std::find(last_known_positions_.begin(),
101 id); 102 last_known_positions_.end(),
103 id);
102 if (pos_id != last_known_positions_.end()) 104 if (pos_id != last_known_positions_.end())
103 last_known_positions_.erase(pos_id); 105 last_known_positions_.erase(pos_id);
104 106
105 if (index < toolbar_items_.size()) { 107 if (index < toolbar_items_.size()) {
106 // If the index is not at the end, find the item currently at |index|, and 108 // If the index is not at the end, find the item currently at |index|, and
107 // insert |extension| before it in both |toolbar_items_| and 109 // insert the action with id |id| before it in both |toolbar_items_| and
Devlin 2015/08/06 22:04:56 nitty nit: just |id|, not id |id|.
apacible 2015/08/10 22:38:10 Done.
108 // |last_known_positions_|. 110 // |last_known_positions_|.
109 ExtensionList::iterator iter = toolbar_items_.begin() + index; 111 ActionIdList::iterator iter = toolbar_items_.begin() + index;
110 last_known_positions_.insert(std::find(last_known_positions_.begin(), 112 last_known_positions_.insert(std::find(last_known_positions_.begin(),
111 last_known_positions_.end(), 113 last_known_positions_.end(),
112 (*iter)->id()), 114 *iter),
113 id); 115 id);
114 toolbar_items_.insert(iter, extension); 116 toolbar_items_.insert(iter, id);
115 } else { 117 } else {
116 // Otherwise, put |extension| at the end. 118 // Otherwise, put the action at the end.
117 DCHECK_EQ(toolbar_items_.size(), index); 119 DCHECK_EQ(toolbar_items_.size(), index);
118 index = toolbar_items_.size(); 120 index = toolbar_items_.size();
119 toolbar_items_.push_back(extension); 121 toolbar_items_.push_back(id);
120 last_known_positions_.push_back(id); 122 last_known_positions_.push_back(id);
121 } 123 }
122 124
123 FOR_EACH_OBSERVER(Observer, observers_, 125 FOR_EACH_OBSERVER(Observer, observers_,
124 OnToolbarExtensionMoved(extension.get(), index)); 126 OnToolbarActionMoved(id, index));
125 MaybeUpdateVisibilityPref(extension.get(), index); 127 MaybeUpdateVisibilityPref(id, index);
126 UpdatePrefs(); 128 UpdatePrefs();
127 } 129 }
128 130
129 void ExtensionToolbarModel::SetVisibleIconCount(size_t count) { 131 void ToolbarActionsModel::SetVisibleIconCount(size_t count) {
130 visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count; 132 visible_icon_count_ = (count >= toolbar_items_.size()) ? -1 : count;
131 133
132 // Only set the prefs if we're not in highlight mode and the profile is not 134 // Only set the prefs if we're not in highlight mode and the profile is not
133 // incognito. Highlight mode is designed to be a transitory state, and should 135 // incognito. Highlight mode is designed to be a transitory state, and should
134 // not persist across browser restarts (though it may be re-entered), and we 136 // not persist across browser restarts (though it may be re-entered), and we
135 // don't store anything in incognito. 137 // don't store anything in incognito.
136 if (!is_highlighting() && !profile_->IsOffTheRecord()) { 138 if (!is_highlighting() && !profile_->IsOffTheRecord()) {
137 // Additionally, if we are using the new toolbar, any icons which are in the 139 // Additionally, if we are using the new toolbar, any icons which are in the
138 // overflow menu are considered "hidden". But it so happens that the times 140 // overflow menu are considered "hidden". But it so happens that the times
139 // we are likely to call SetVisibleIconCount() are also those when we are 141 // we are likely to call SetVisibleIconCount() are also those when we are
140 // in flux. So wait for things to cool down before setting the prefs. 142 // in flux. So wait for things to cool down before setting the prefs.
141 base::ThreadTaskRunnerHandle::Get()->PostTask( 143 base::ThreadTaskRunnerHandle::Get()->PostTask(
142 FROM_HERE, 144 FROM_HERE,
143 base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs, 145 base::Bind(&ToolbarActionsModel::MaybeUpdateVisibilityPrefs,
144 weak_ptr_factory_.GetWeakPtr())); 146 weak_ptr_factory_.GetWeakPtr()));
145 prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_); 147 prefs_->SetInteger(extensions::pref_names::kToolbarSize,
148 visible_icon_count_);
146 } 149 }
147 150
148 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarVisibleCountChanged()); 151 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarVisibleCountChanged());
149 } 152 }
150 153
151 void ExtensionToolbarModel::OnExtensionActionUpdated( 154 void ToolbarActionsModel::OnExtensionActionUpdated(
152 ExtensionAction* extension_action, 155 ExtensionAction* extension_action,
153 content::WebContents* web_contents, 156 content::WebContents* web_contents,
154 content::BrowserContext* browser_context) { 157 content::BrowserContext* browser_context) {
155 const Extension* extension =
156 ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
157 extension_action->extension_id());
158 // Notify observers if the extension exists and is in the model. 158 // Notify observers if the extension exists and is in the model.
159 if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) != 159 if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
160 toolbar_items_.end()) { 160 extension_action->extension_id()) != toolbar_items_.end()) {
161 FOR_EACH_OBSERVER(Observer, observers_, 161 FOR_EACH_OBSERVER(Observer, observers_,
162 OnToolbarExtensionUpdated(extension)); 162 OnToolbarActionUpdated(
163 extension_action->extension_id()));
163 } 164 }
164 } 165 }
165 166
166 void ExtensionToolbarModel::OnExtensionActionVisibilityChanged( 167 ActionList ToolbarActionsModel::GetActions(Browser* browser,
168 ToolbarActionsBar* bar) {
169 DCHECK(browser);
170 DCHECK(bar);
171 ActionList action_list;
172
173 // Get the component action list.
174 ActionList component_actions =
175 ComponentToolbarActionsFactory::GetInstance()->
176 GetComponentToolbarActions(browser);
177
178 extensions::ExtensionActionManager* action_manager =
179 extensions::ExtensionActionManager::Get(profile_);
180
181 ActionIdList items = toolbar_items();
182 // Some actions are suppressed when others are highlighted. The list of ids
183 // is kept track of in |model_|.
Devlin 2015/08/06 22:04:56 This is the model. ;)
apacible 2015/08/10 22:38:10 Done.
184 for (size_t i = 0; i < items.size(); i++) {
Devlin 2015/08/06 22:04:56 range-based for loop.
apacible 2015/08/10 22:38:10 Done.
185 // Check if current action_id is for an extension.
186 if (IsKnownActionWithType(items[i], ACTION_EXTENSION)) {
187 // Get the extension.
188 const extensions::Extension* extension = GetExtensionById(items[i]);
189 DCHECK(extension);
190
191 // Create and add an ExtensionActionViewController for the extension.
192 action_list.push_back(new ExtensionActionViewController(
193 extension,
194 browser,
195 action_manager->GetExtensionAction(*extension),
196 bar));
197 } else if (IsKnownActionWithType(items[i], ACTION_COMPONENT)) {
198 DCHECK(extensions::FeatureSwitch::extension_action_redesign()->
Devlin 2015/08/06 22:04:56 This is cached as a variable.
apacible 2015/08/10 22:38:09 Done.
199 IsEnabled());
200 // Find the corresponding action to action_id.
201 for (size_t j = 0; j < component_actions.size(); j++) {
Devlin 2015/08/06 22:04:56 range-based
apacible 2015/08/10 22:38:09 Done.
202 if (component_actions[j]->GetId() == items[i]) {
203 action_list.push_back(component_actions[j]);
204 continue;
Devlin 2015/08/06 22:04:55 this looks like it should be a break.
apacible 2015/08/10 22:38:10 Done.
205 }
206 }
207 }
208 }
209
210 component_actions.weak_clear();
Devlin 2015/08/06 22:04:56 have a comment about why this is safe (i.e., doesn
apacible 2015/08/10 22:38:10 Added above in the loop that adds the component ac
211
212 return action_list.Pass();
213 }
214
215 void ToolbarActionsModel::OnExtensionActionVisibilityChanged(
167 const std::string& extension_id, 216 const std::string& extension_id,
168 bool is_now_visible) { 217 bool is_now_visible) {
169 const Extension* extension =
170 ExtensionRegistry::Get(profile_)->GetExtensionById(
171 extension_id, ExtensionRegistry::EVERYTHING);
172
173 // Hiding works differently with the new and old toolbars. 218 // Hiding works differently with the new and old toolbars.
174 if (include_all_extensions_) { 219 if (include_all_extensions_) {
175 // It's possible that we haven't added this extension yet, if its 220 // It's possible that we haven't added this action yet, if its
176 // visibility was adjusted in the course of its initialization. 221 // visibility was adjusted in the course of its initialization.
177 if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) == 222 if (std::find(toolbar_items_.begin(), toolbar_items_.end(),
178 toolbar_items_.end()) 223 extension_id) == toolbar_items_.end())
179 return; 224 return;
180 225
181 int new_size = 0; 226 int new_size = 0;
182 int new_index = 0; 227 int new_index = 0;
183 if (is_now_visible) { 228 if (is_now_visible) {
184 // If this action used to be hidden, we can't possibly be showing all. 229 // If this action used to be hidden, we can't possibly be showing all.
185 DCHECK_LT(visible_icon_count(), toolbar_items_.size()); 230 DCHECK_LT(visible_icon_count(), toolbar_items_.size());
186 // Grow the bar by one and move the extension to the end of the visibles. 231 // Grow the bar by one and move the action to the end of the visibles.
187 new_size = visible_icon_count() + 1; 232 new_size = visible_icon_count() + 1;
188 new_index = new_size - 1; 233 new_index = new_size - 1;
189 } else { 234 } else {
190 // If we're hiding one, we must be showing at least one. 235 // If we're hiding one, we must be showing at least one.
191 DCHECK_GE(visible_icon_count(), 0u); 236 DCHECK_GE(visible_icon_count(), 0u);
192 // Shrink the bar by one and move the extension to the beginning of the 237 // Shrink the bar by one and move the action to the beginning of the
193 // overflow menu. 238 // overflow menu.
194 new_size = visible_icon_count() - 1; 239 new_size = visible_icon_count() - 1;
195 new_index = new_size; 240 new_index = new_size;
196 } 241 }
197 SetVisibleIconCount(new_size); 242 SetVisibleIconCount(new_size);
198 MoveExtensionIcon(extension->id(), new_index); 243 MoveActionIcon(extension_id, new_index);
199 } else { // Don't include all extensions. 244 } else { // Don't include all extensions.
245 const extensions::Extension* extension =
246 extension_registry_->GetExtensionById(
Devlin 2015/08/06 22:04:56 We have a method for this now, right? (It shouldn
apacible 2015/08/10 22:38:09 Done.
247 extension_id, extensions::ExtensionRegistry::EVERYTHING);
200 if (is_now_visible) 248 if (is_now_visible)
201 AddExtension(extension); 249 AddExtension(extension);
202 else 250 else
203 RemoveExtension(extension); 251 RemoveExtension(extension);
204 } 252 }
205 } 253 }
206 254
207 void ExtensionToolbarModel::OnExtensionLoaded( 255 void ToolbarActionsModel::OnExtensionLoaded(
208 content::BrowserContext* browser_context, 256 content::BrowserContext* browser_context,
209 const Extension* extension) { 257 const extensions::Extension* extension) {
210 // We don't want to add the same extension twice. It may have already been 258 // We don't want to add the same extension twice. It may have already been
211 // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user 259 // added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
212 // hides the browser action and then disables and enables the extension. 260 // hides the browser action and then disables and enables the extension.
213 for (size_t i = 0; i < toolbar_items_.size(); i++) { 261 for (size_t i = 0; i < toolbar_items_.size(); i++) {
Devlin 2015/08/06 22:04:56 this can be std::find now.
apacible 2015/08/10 22:38:10 Done.
214 if (toolbar_items_[i].get() == extension) 262 if (toolbar_items_[i] == extension->id())
215 return; 263 return;
216 } 264 }
217 265
218 AddExtension(extension); 266 AddExtension(extension);
219 } 267 }
220 268
221 void ExtensionToolbarModel::OnExtensionUnloaded( 269 void ToolbarActionsModel::OnExtensionUnloaded(
222 content::BrowserContext* browser_context, 270 content::BrowserContext* browser_context,
223 const Extension* extension, 271 const extensions::Extension* extension,
224 UnloadedExtensionInfo::Reason reason) { 272 extensions::UnloadedExtensionInfo::Reason reason) {
225 RemoveExtension(extension); 273 RemoveExtension(extension);
226 } 274 }
227 275
228 void ExtensionToolbarModel::OnExtensionUninstalled( 276 void ToolbarActionsModel::OnExtensionUninstalled(
229 content::BrowserContext* browser_context, 277 content::BrowserContext* browser_context,
230 const Extension* extension, 278 const extensions::Extension* extension,
231 extensions::UninstallReason reason) { 279 extensions::UninstallReason reason) {
232 // Remove the extension id from the ordered list, if it exists (the extension 280 // Remove the extension id from the ordered list, if it exists (the extension
233 // might not be represented in the list because it might not have an icon). 281 // might not be represented in the list because it might not have an icon).
234 ExtensionIdList::iterator pos = 282 ActionIdList::iterator pos =
235 std::find(last_known_positions_.begin(), 283 std::find(last_known_positions_.begin(),
236 last_known_positions_.end(), extension->id()); 284 last_known_positions_.end(), extension->id());
237 285
238 if (pos != last_known_positions_.end()) { 286 if (pos != last_known_positions_.end()) {
239 last_known_positions_.erase(pos); 287 last_known_positions_.erase(pos);
240 UpdatePrefs(); 288 UpdatePrefs();
241 } 289 }
242 } 290 }
243 291
244 void ExtensionToolbarModel::OnReady() { 292 void ToolbarActionsModel::OnReady() {
245 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); 293 InitializeActionList();
246 InitializeExtensionList();
247 // Wait until the extension system is ready before observing any further 294 // Wait until the extension system is ready before observing any further
248 // changes so that the toolbar buttons can be shown in their stable ordering 295 // changes so that the toolbar buttons can be shown in their stable ordering
249 // taken from prefs. 296 // taken from prefs.
250 extension_registry_observer_.Add(registry); 297 extension_registry_observer_.Add(extension_registry_);
251 extension_action_observer_.Add(extension_action_api_); 298 extension_action_observer_.Add(extension_action_api_);
252 299
253 if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile( 300 if (ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
254 profile_)) { 301 profile_)) {
255 ExtensionIdList ids; 302 ActionIdList ids;
256 for (const auto& extension : toolbar_items_) 303 for (const std::string& id : toolbar_items_)
257 ids.push_back(extension->id()); 304 ids.push_back(id);
258 HighlightExtensions(ids, HIGHLIGHT_INFO); 305 HighlightActions(ids, HIGHLIGHT_INFO);
259 } 306 }
260 307
261 extensions_initialized_ = true; 308 actions_initialized_ = true;
262 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized()); 309 FOR_EACH_OBSERVER(Observer, observers_, OnToolbarModelInitialized());
263 } 310 }
264 311
265 size_t ExtensionToolbarModel::FindNewPositionFromLastKnownGood( 312 size_t ToolbarActionsModel::FindNewPositionFromLastKnownGood(
266 const Extension* extension) { 313 const std::string& id) {
267 // See if we have last known good position for this extension. 314 // See if we have last known good position for this extension.
268 size_t new_index = 0; 315 size_t new_index = 0;
269 // Loop through the ID list of known positions, to count the number of visible 316 // Loop through the ID list of known positions, to count the number of visible
270 // extension icons preceding |extension|. 317 // extension icons preceding |extension|.
271 for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin(); 318 for (ActionIdList::const_iterator iter_id =
Devlin 2015/08/06 22:04:56 range-based.
apacible 2015/08/10 22:38:10 Done.
272 iter_id < last_known_positions_.end(); ++iter_id) { 319 last_known_positions_.begin(); iter_id < last_known_positions_.end();
273 if ((*iter_id) == extension->id()) 320 ++iter_id) {
321 if ((*iter_id) == id)
274 return new_index; // We've found the right position. 322 return new_index; // We've found the right position.
275 // Found an id, need to see if it is visible. 323 // Found an id, need to see if it is visible.
276 for (ExtensionList::const_iterator iter_ext = toolbar_items_.begin(); 324 for (ActionIdList::const_iterator iter_ext =
277 iter_ext < toolbar_items_.end(); ++iter_ext) { 325 toolbar_items_.begin(); iter_ext < toolbar_items_.end(); ++iter_ext) {
278 if ((*iter_ext)->id() == (*iter_id)) { 326 if ((*iter_ext) == (*iter_id)) {
279 // This extension is visible, update the index value. 327 // This extension is visible, update the index value.
280 ++new_index; 328 ++new_index;
281 break; 329 break;
282 } 330 }
283 } 331 }
284 } 332 }
285 333
286 // Position not found. 334 // Position not found.
287 return toolbar_items_.size(); 335 return toolbar_items_.size();
288 } 336 }
289 337
290 bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) { 338 bool ToolbarActionsModel::ShouldAddExtension(
339 const extensions::Extension* extension) {
291 // In incognito mode, don't add any extensions that aren't incognito-enabled. 340 // In incognito mode, don't add any extensions that aren't incognito-enabled.
292 if (profile_->IsOffTheRecord() && 341 if (profile_->IsOffTheRecord() &&
293 !util::IsIncognitoEnabled(extension->id(), profile_)) 342 !extensions::util::IsIncognitoEnabled(extension->id(), profile_))
294 return false; 343 return false;
295 344
296 ExtensionActionManager* action_manager = 345 extensions::ExtensionActionManager* action_manager =
297 ExtensionActionManager::Get(profile_); 346 extensions::ExtensionActionManager::Get(profile_);
298 if (include_all_extensions_) { 347 if (include_all_extensions_) {
299 // In this case, we don't care about the browser action visibility, because 348 // In this case, we don't care about the browser action visibility, because
300 // we want to show each extension regardless. 349 // we want to show each extension regardless.
301 // TODO(devlin): Extension actions which are not visible should be moved to
302 // the overflow menu by default.
303 return action_manager->GetExtensionAction(*extension) != NULL; 350 return action_manager->GetExtensionAction(*extension) != NULL;
304 } 351 }
305 352
306 return action_manager->GetBrowserAction(*extension) && 353 return action_manager->GetBrowserAction(*extension) &&
307 extension_action_api_->GetBrowserActionVisibility(extension->id()); 354 extension_action_api_->GetBrowserActionVisibility(extension->id());
308 } 355 }
309 356
310 void ExtensionToolbarModel::AddExtension(const Extension* extension) { 357 void ToolbarActionsModel::AddExtension(const extensions::Extension* extension) {
311 // We only use AddExtension() once the system is initialized. 358 // We only use AddExtension() once the system is initialized.
312 DCHECK(extensions_initialized_); 359 DCHECK(actions_initialized_);
313 if (!ShouldAddExtension(extension)) 360 if (!ShouldAddExtension(extension))
314 return; 361 return;
315 362
316 // See if we have a last known good position for this extension. 363 // See if we have a last known good position for this extension.
317 bool is_new_extension = 364 bool is_new_extension =
318 std::find(last_known_positions_.begin(), 365 std::find(last_known_positions_.begin(),
319 last_known_positions_.end(), 366 last_known_positions_.end(),
320 extension->id()) == last_known_positions_.end(); 367 extension->id()) == last_known_positions_.end();
321 368
322 // New extensions go at the right (end) of the visible extensions. Other 369 // New extensions go at the right (end) of the visible extensions. Other
323 // extensions go at their previous position. 370 // extensions go at their previous position.
324 size_t new_index = 0; 371 size_t new_index = 0;
325 if (is_new_extension) { 372 if (is_new_extension) {
326 new_index = Manifest::IsComponentLocation(extension->location()) ? 373 new_index = extensions::Manifest::IsComponentLocation(
327 0 : visible_icon_count(); 374 extension->location()) ? 0 : visible_icon_count();
328 // For the last-known position, we use the index of the extension that is 375 // For the last-known position, we use the index of the extension that is
329 // just before this extension, plus one. (Note that this isn't the same 376 // just before this extension, plus one. (Note that this isn't the same
330 // as new_index + 1, because last_known_positions_ can include disabled 377 // as new_index + 1, because last_known_positions_ can include disabled
331 // extensions.) 378 // extensions.)
332 int new_last_known_index = 379 int new_last_known_index =
333 new_index == 0 ? 0 : 380 new_index == 0 ? 0 :
334 std::find(last_known_positions_.begin(), 381 std::find(last_known_positions_.begin(),
335 last_known_positions_.end(), 382 last_known_positions_.end(),
336 toolbar_items_[new_index - 1]->id()) - 383 toolbar_items_[new_index - 1]) -
337 last_known_positions_.begin() + 1; 384 last_known_positions_.begin() + 1;
338 // In theory, the extension before this one should always 385 // In theory, the extension before this one should always
339 // be in last known positions, but if something funny happened with prefs, 386 // be in last known positions, but if something funny happened with prefs,
340 // make sure we handle it. 387 // make sure we handle it.
341 // TODO(devlin): Track down these cases so we can CHECK this. 388 // TODO(devlin): Track down these cases so we can CHECK this.
342 new_last_known_index = 389 new_last_known_index =
343 std::min<int>(new_last_known_index, last_known_positions_.size()); 390 std::min<int>(new_last_known_index, last_known_positions_.size());
344 last_known_positions_.insert( 391 last_known_positions_.insert(
345 last_known_positions_.begin() + new_last_known_index, extension->id()); 392 last_known_positions_.begin() + new_last_known_index, extension->id());
346 UpdatePrefs(); 393 UpdatePrefs();
347 } else { 394 } else {
348 new_index = FindNewPositionFromLastKnownGood(extension); 395 new_index = FindNewPositionFromLastKnownGood(extension->id());
349 } 396 }
350 397
351 toolbar_items_.insert(toolbar_items_.begin() + new_index, extension); 398 action_id_to_type_.insert(
399 std::pair<std::string, ActionType>(extension->id(), ACTION_EXTENSION));
400 toolbar_items_.insert(toolbar_items_.begin() + new_index, extension->id());
352 401
353 // If we're currently highlighting, then even though we add a browser action 402 // If we're currently highlighting, then even though we add a browser action
354 // to the full list (|toolbar_items_|, there won't be another *visible* 403 // to the full list (|toolbar_items_|, there won't be another *visible*
355 // browser action, which was what the observers care about. 404 // browser action, which was what the observers care about.
356 if (!is_highlighting()) { 405 if (!is_highlighting()) {
357 FOR_EACH_OBSERVER(Observer, observers_, 406 FOR_EACH_OBSERVER(Observer, observers_,
358 OnToolbarExtensionAdded(extension, new_index)); 407 OnToolbarActionAdded(extension->id(), new_index));
359 408
360 int visible_count_delta = 0; 409 int visible_count_delta = 0;
361 if (is_new_extension && !all_icons_visible()) { 410 if (is_new_extension && !all_icons_visible()) {
362 // If this is a new extension (and not all extensions are visible), we 411 // If this is a new extension (and not all extensions are visible), we
363 // expand the toolbar out so that the new one can be seen. 412 // expand the toolbar out so that the new one can be seen.
364 visible_count_delta = 1; 413 visible_count_delta = 1;
365 } else if (profile_->IsOffTheRecord()) { 414 } else if (profile_->IsOffTheRecord()) {
366 // If this is an incognito profile, we also have to check to make sure the 415 // If this is an incognito profile, we also have to check to make sure the
367 // overflow matches the main bar's status. 416 // overflow matches the main bar's status.
368 ExtensionToolbarModel* main_model = 417 ToolbarActionsModel* main_model =
369 ExtensionToolbarModel::Get(profile_->GetOriginalProfile()); 418 ToolbarActionsModel::Get(profile_->GetOriginalProfile());
370 // Find what the index will be in the main bar. Because Observer calls are 419 // Find what the index will be in the main bar. Because Observer calls are
371 // nondeterministic, we can't just assume the main bar will have the 420 // nondeterministic, we can't just assume the main bar will have the
372 // extension and look it up. 421 // extension and look it up.
373 size_t main_index = 422 size_t main_index =
374 main_model->FindNewPositionFromLastKnownGood(extension); 423 main_model->FindNewPositionFromLastKnownGood(extension->id());
375 bool visible = main_index < main_model->visible_icon_count(); 424 bool visible = main_index < main_model->visible_icon_count();
376 // We may need to adjust the visible count if the incognito bar isn't 425 // We may need to adjust the visible count if the incognito bar isn't
377 // showing all icons and this one is visible, or if it is showing all 426 // showing all icons and this one is visible, or if it is showing all
378 // icons and this is hidden. 427 // icons and this is hidden.
379 if (visible && !all_icons_visible()) 428 if (visible && !all_icons_visible())
380 visible_count_delta = 1; 429 visible_count_delta = 1;
381 else if (!visible && all_icons_visible()) 430 else if (!visible && all_icons_visible())
382 visible_count_delta = -1; 431 visible_count_delta = -1;
383 } 432 }
384 433
385 if (visible_count_delta) 434 if (visible_count_delta)
386 SetVisibleIconCount(visible_icon_count() + visible_count_delta); 435 SetVisibleIconCount(visible_icon_count() + visible_count_delta);
387 } 436 }
388 437
389 MaybeUpdateVisibilityPref(extension, new_index); 438 MaybeUpdateVisibilityPref(extension->id(), new_index);
390 } 439 }
391 440
392 void ExtensionToolbarModel::RemoveExtension(const Extension* extension) { 441 void ToolbarActionsModel::RemoveExtension(
393 ExtensionList::iterator pos = 442 const extensions::Extension* extension) {
394 std::find(toolbar_items_.begin(), toolbar_items_.end(), extension); 443 ActionIdList::iterator pos =
444 std::find(toolbar_items_.begin(), toolbar_items_.end(),
445 extension->id());
395 if (pos == toolbar_items_.end()) 446 if (pos == toolbar_items_.end())
396 return; 447 return;
397 448
398 // If our visible count is set to the current size, we need to decrement it. 449 // If our visible count is set to the current size, we need to decrement it.
399 if (visible_icon_count_ == static_cast<int>(toolbar_items_.size())) 450 if (visible_icon_count_ == static_cast<int>(toolbar_items_.size()))
400 SetVisibleIconCount(toolbar_items_.size() - 1); 451 SetVisibleIconCount(toolbar_items_.size() - 1);
401 452
402 toolbar_items_.erase(pos); 453 toolbar_items_.erase(pos);
403 454
404 // If we're in highlight mode, we also have to remove the extension from 455 // If we're in highlight mode, we also have to remove the extension from
405 // the highlighted list. 456 // the highlighted list.
406 if (is_highlighting()) { 457 if (is_highlighting()) {
407 pos = std::find(highlighted_items_.begin(), 458 pos = std::find(highlighted_items_.begin(),
408 highlighted_items_.end(), 459 highlighted_items_.end(),
409 extension); 460 extension->id());
410 if (pos != highlighted_items_.end()) { 461 if (pos != highlighted_items_.end()) {
411 highlighted_items_.erase(pos); 462 highlighted_items_.erase(pos);
412 FOR_EACH_OBSERVER(Observer, observers_, 463 FOR_EACH_OBSERVER(Observer, observers_,
413 OnToolbarExtensionRemoved(extension)); 464 OnToolbarActionRemoved(extension->id()));
414 // If the highlighted list is now empty, we stop highlighting. 465 // If the highlighted list is now empty, we stop highlighting.
415 if (highlighted_items_.empty()) 466 if (highlighted_items_.empty())
416 StopHighlighting(); 467 StopHighlighting();
417 } 468 }
418 } else { 469 } else {
419 FOR_EACH_OBSERVER(Observer, observers_, 470 FOR_EACH_OBSERVER(Observer, observers_,
420 OnToolbarExtensionRemoved(extension)); 471 OnToolbarActionRemoved(extension->id()));
421 } 472 }
422 473
423 UpdatePrefs(); 474 UpdatePrefs();
424 } 475 }
425 476
426 // Combine the currently enabled extensions that have browser actions (which 477 // Combine the currently enabled extensions that have browser actions (which
427 // we get from the ExtensionRegistry) with the ordering we get from the 478 // we get from the ExtensionRegistry) and component actions (which we get from
428 // pref service. For robustness we use a somewhat inefficient process: 479 // ComponentToolbarActionsFactory ) with the ordering we get from the pref
429 // 1. Create a vector of extensions sorted by their pref values. This vector may 480 // service. For robustness we use a somewhat inefficient process:
481 // 1. Create a vector of actions sorted by their pref values. This vector may
430 // have holes. 482 // have holes.
431 // 2. Create a vector of extensions that did not have a pref value. 483 // 2. Create a vector of actions that did not have a pref value.
432 // 3. Remove holes from the sorted vector and append the unsorted vector. 484 // 3. Remove holes from the sorted vector and append the unsorted vector.
433 void ExtensionToolbarModel::InitializeExtensionList() { 485 void ToolbarActionsModel::InitializeActionList() {
434 DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet. 486 DCHECK(toolbar_items_.empty()); // We shouldn't have any items yet.
487 DCHECK(action_id_to_type_.empty());
435 488
436 last_known_positions_ = extension_prefs_->GetToolbarOrder(); 489 last_known_positions_ = prefs_service_->GetToolbarOrder();
437 if (profile_->IsOffTheRecord()) 490 if (profile_->IsOffTheRecord())
438 IncognitoPopulate(); 491 IncognitoPopulate();
439 else 492 else
440 Populate(&last_known_positions_); 493 Populate(&last_known_positions_);
441 494
442 MaybeUpdateVisibilityPrefs(); 495 MaybeUpdateVisibilityPrefs();
443 } 496 }
444 497
445 void ExtensionToolbarModel::Populate(ExtensionIdList* positions) { 498 void ToolbarActionsModel::Populate(ActionIdList* positions) {
446 DCHECK(!profile_->IsOffTheRecord()); 499 DCHECK(!profile_->IsOffTheRecord());
447 const ExtensionSet& extensions = 500
448 ExtensionRegistry::Get(profile_)->enabled_extensions();
449 // Items that have explicit positions. 501 // Items that have explicit positions.
450 ExtensionList sorted(positions->size(), NULL); 502 ActionIdList sorted(positions->size());
451 // The items that don't have explicit positions. 503 // The items that don't have explicit positions.
452 ExtensionList unsorted; 504 ActionIdList unsorted;
453 505
454 // Create the lists. 506 // Populate the lists.
455 int hidden = 0; 507 int hidden = 0;
456 for (const scoped_refptr<const Extension>& extension : extensions) { 508 int browser_actions_count = 0;
509 int component_actions_count = 0;
510
511 // First, add the extension action ids to the lists.
512 const extensions::ExtensionSet& extensions =
513 extension_registry_->enabled_extensions();
514 for (const scoped_refptr<const extensions::Extension>& extension :
515 extensions) {
457 if (!ShouldAddExtension(extension.get())) { 516 if (!ShouldAddExtension(extension.get())) {
458 if (!extension_action_api_->GetBrowserActionVisibility(extension->id())) 517 if (!extension_action_api_->GetBrowserActionVisibility(extension->id()))
459 ++hidden; 518 ++hidden;
460 continue; 519 continue;
461 } 520 }
462 521
463 ExtensionIdList::const_iterator pos = 522 ActionIdList::const_iterator pos =
464 std::find(positions->begin(), positions->end(), extension->id()); 523 std::find(positions->begin(), positions->end(), extension->id());
465 if (pos != positions->end()) { 524 if (pos != positions->end()) {
466 sorted[pos - positions->begin()] = extension; 525 sorted[pos - positions->begin()] = extension->id();
467 } else { 526 } else {
468 // Unknown extension - push it to the back of unsorted, and add it to the 527 // Unknown extension - push it to the back of unsorted, and add it to the
469 // list of ids at the end. 528 // list of ids at the end.
470 unsorted.push_back(extension); 529 unsorted.push_back(extension->id());
471 positions->push_back(extension->id()); 530 positions->push_back(extension->id());
472 } 531 }
473 } 532 }
474 533
534 // Next, add the component action ids to the lists.
535 ActionIdList component_ids =
536 ComponentToolbarActionsFactory::GetComponentIds();
537 for (const std::string& id : component_ids) {
538 ActionIdList::const_iterator pos =
539 std::find(positions->begin(), positions->end(), id);
540 if (pos != positions->end()) {
Devlin 2015/08/06 22:04:56 Instead of duplicating this logic, can we just gen
apacible 2015/08/10 22:38:10 Done.
541 sorted[pos - positions->begin()] = id;
542 } else {
543 // New component - push it to the back of unsorted, and add it to the
544 // list of ids at the end. This should only be the case when there is
545 // a browser feature using a new component action.
546 unsorted.push_back(id);
547 positions->push_back(id);
548 }
549 }
550
475 // Merge the lists. 551 // Merge the lists.
476 sorted.insert(sorted.end(), unsorted.begin(), unsorted.end()); 552 sorted.insert(sorted.end(), unsorted.begin(), unsorted.end());
477 toolbar_items_.reserve(sorted.size()); 553 toolbar_items_.reserve(sorted.size());
478 554
479 for (const scoped_refptr<const Extension>& extension : sorted) { 555 for (const std::string& action_id : sorted) {
480 // It's possible for the extension order to contain items that aren't 556 // Check the type of action.
481 // actually loaded on this machine. For example, when extension sync is on, 557 if (std::find(component_ids.begin(), component_ids.end(), action_id) ==
Devlin 2015/08/06 22:04:55 These lookups still make me wonder if we should ha
apacible 2015/08/10 22:38:10 I add to the struct of string, type after this che
Devlin 2015/08/13 21:21:10 That's not quite what I was suggesting. I was won
apacible 2015/08/15 08:46:40 Talked offline: - Created ToolbarItem struct. - Pa
482 // we sync the extension order as-is but double-check with the user before 558 component_ids.end()) {
483 // syncing NPAPI-containing extensions, so if one of those is not actually 559 // It's possible for the extension order to contain items that aren't
484 // synced, we'll get a NULL in the list. This sort of case can also happen 560 // actually loaded on this machine. For example, when extension sync is
485 // if some error prevents an extension from loading. 561 // on, we sync the extension order as-is but double-check with the user
486 if (extension.get()) { 562 // before syncing NPAPI-containing extensions, so if one of those is not
487 // We don't notify observers of the added extension yet. Rather, observers 563 // actually synced, we'll get a NULL in the list. This sort of case can
488 // should wait for the "OnToolbarModelInitialized" notification, and then 564 // also happen if some error prevents an extension from loading.
489 // bulk-update. (This saves a lot of bouncing-back-and-forth here, and 565 if (GetExtensionById(action_id)) {
490 // allows observers to ensure that the extension system is always 566 // We don't notify observers of the added extension yet. Rather,
Devlin 2015/08/06 22:04:55 This comment applies to both component and extensi
apacible 2015/08/10 22:38:09 Done.
491 // initialized before using the extensions). 567 // observers should wait for the "OnToolbarModelInitialized"
492 toolbar_items_.push_back(extension); 568 // notification, and then bulk-update. (This saves a lot of
569 // bouncing-back-and-forth here, and allows observers to ensure that
570 // the extension system is always initialized before using the
571 // extensions).
572 action_id_to_type_.insert(
573 std::pair<std::string, ActionType>(action_id, ACTION_EXTENSION));
574 toolbar_items_.push_back(action_id);
575 browser_actions_count++;
Devlin 2015/08/06 22:04:56 nitty nit: prefer pre-increment.
apacible 2015/08/10 22:38:10 Done.
576 }
577 } else {
578 // Always add component actions.
579 action_id_to_type_.insert(
580 std::pair<std::string, ActionType>(action_id, ACTION_COMPONENT));
581 toolbar_items_.push_back(action_id);
582 component_actions_count++;
493 } 583 }
494 } 584 }
495 585
586 // Histogram names are prefixed with "ExtensionToolbarModel" rather than
587 // "ToolbarActionsModel" for historical reasons.
496 UMA_HISTOGRAM_COUNTS_100( 588 UMA_HISTOGRAM_COUNTS_100(
497 "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden); 589 "ExtensionToolbarModel.BrowserActionsPermanentlyHidden", hidden);
498 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount", 590 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsCount",
591 browser_actions_count);
592 UMA_HISTOGRAM_COUNTS_100("ToolbarActionsModel.ComponentActionsCount",
593 component_actions_count);
594 UMA_HISTOGRAM_COUNTS_100("ToolbarActionsModel.OverallActionsCount",
499 toolbar_items_.size()); 595 toolbar_items_.size());
500 596
501 if (!toolbar_items_.empty()) { 597 if (!toolbar_items_.empty()) {
502 // Visible count can be -1, meaning: 'show all'. Since UMA converts negative 598 // Visible count can be -1, meaning: 'show all'. Since UMA converts negative
503 // values to 0, this would be counted as 'show none' unless we convert it to 599 // values to 0, this would be counted as 'show none' unless we convert it to
504 // max. 600 // max.
601 int visible_browser_icon_size = visible_icon_count_ -
602 component_actions_count;
505 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsVisible", 603 UMA_HISTOGRAM_COUNTS_100("ExtensionToolbarModel.BrowserActionsVisible",
506 visible_icon_count_ == -1 ? 604 visible_icon_count_ == -1 ?
507 base::HistogramBase::kSampleType_MAX : 605 base::HistogramBase::kSampleType_MAX :
508 visible_icon_count_); 606 visible_browser_icon_size);
Devlin 2015/08/06 22:04:56 UMA for visible toolbar actions would be good, too
apacible 2015/08/10 22:38:09 Done.
509 } 607 }
510 } 608 }
511 609
512 void ExtensionToolbarModel::IncognitoPopulate() { 610 void ToolbarActionsModel::IncognitoPopulate() {
513 DCHECK(profile_->IsOffTheRecord()); 611 DCHECK(profile_->IsOffTheRecord());
514 const ExtensionToolbarModel* original_model = 612 const ToolbarActionsModel* original_model =
515 ExtensionToolbarModel::Get(profile_->GetOriginalProfile()); 613 ToolbarActionsModel::Get(profile_->GetOriginalProfile());
516 614
517 // Find the absolute value of the original model's count. 615 // Find the absolute value of the original model's count.
518 int original_visible = original_model->visible_icon_count(); 616 int original_visible = original_model->visible_icon_count();
519 617
520 // In incognito mode, we show only those extensions that are 618 std::map<std::string, ActionType> original_action_id_to_type =
521 // incognito-enabled. Further, any actions that were overflowed in regular 619 original_model->action_id_to_type();
522 // mode are still overflowed. Order is the same as in regular mode. 620
621 // In incognito mode, we show only those actions that are incognito-enabled
622 // Further, any actions that were overflowed in regular mode are still
623 // overflowed. Order is the same as in regular mode.
523 visible_icon_count_ = 0; 624 visible_icon_count_ = 0;
524 for (ExtensionList::const_iterator iter = 625
626 for (ActionIdList::const_iterator iter =
525 original_model->toolbar_items_.begin(); 627 original_model->toolbar_items_.begin();
526 iter != original_model->toolbar_items_.end(); ++iter) { 628 iter != original_model->toolbar_items_.end(); ++iter) {
527 if (ShouldAddExtension(iter->get())) { 629 if (original_action_id_to_type.count(*iter) == 0)
630 continue;
631
632 if (original_action_id_to_type.find(*iter)->second == ACTION_EXTENSION) {
633 if (ShouldAddExtension(GetExtensionById(*iter))) {
634 toolbar_items_.push_back(*iter);
635 if (iter - original_model->toolbar_items_.begin() < original_visible)
636 ++visible_icon_count_;
637 }
638 } else {
639 // Always show component actions.
Devlin 2015/08/06 22:04:56 Why not respect the user's choice to hide them? I
apacible 2015/08/10 22:38:10 Good point. How would I go about finding how to hi
Devlin 2015/08/13 21:21:10 The decision is set by whether or not it's visible
apacible 2015/08/15 08:46:40 Talked offline; updated comment. As a start, we'l
528 toolbar_items_.push_back(*iter); 640 toolbar_items_.push_back(*iter);
529 if (iter - original_model->toolbar_items_.begin() < original_visible) 641 if (iter - original_model->toolbar_items_.begin() < original_visible)
530 ++visible_icon_count_; 642 ++visible_icon_count_;
531 } 643 }
532 } 644 }
533 } 645 }
534 646
535 void ExtensionToolbarModel::UpdatePrefs() { 647 void ToolbarActionsModel::UpdatePrefs() {
536 if (!extension_prefs_ || profile_->IsOffTheRecord()) 648 if (!prefs_service_ || profile_->IsOffTheRecord())
537 return; 649 return;
538 650
539 // Don't observe change caused by self. 651 // Don't observe change caused by self.
540 pref_change_registrar_.Remove(pref_names::kToolbar); 652 pref_change_registrar_.Remove(extensions::pref_names::kToolbar);
541 extension_prefs_->SetToolbarOrder(last_known_positions_); 653 prefs_service_->SetToolbarOrder(last_known_positions_);
542 pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_); 654 pref_change_registrar_.Add(extensions::pref_names::kToolbar,
655 pref_change_callback_);
543 } 656 }
544 657
545 void ExtensionToolbarModel::MaybeUpdateVisibilityPref( 658 void ToolbarActionsModel::MaybeUpdateVisibilityPref(
546 const Extension* extension, size_t index) { 659 const std::string& id, size_t index) {
660 // Component Actions are always shown; visibility should not change.
Devlin 2015/08/06 22:04:56 This isn't necessarily true. That said, this pref
apacible 2015/08/10 22:38:10 Done.
661 if (IsKnownActionWithType(id, ACTION_COMPONENT))
662 return;
663
547 // We only update the visibility pref for hidden/not hidden based on the 664 // We only update the visibility pref for hidden/not hidden based on the
548 // overflow menu with the new toolbar design. 665 // overflow menu with the new toolbar design.
549 if (include_all_extensions_ && !profile_->IsOffTheRecord()) { 666 if (include_all_extensions_ && !profile_->IsOffTheRecord()) {
550 bool visible = index < visible_icon_count(); 667 bool visible = index < visible_icon_count();
551 if (visible != extension_action_api_->GetBrowserActionVisibility( 668 if (visible != extension_action_api_->GetBrowserActionVisibility(id)) {
552 extension->id())) {
553 // Don't observe changes caused by ourselves. 669 // Don't observe changes caused by ourselves.
554 bool was_registered = false; 670 bool was_registered = false;
555 if (extension_action_observer_.IsObserving(extension_action_api_)) { 671 if (extension_action_observer_.IsObserving(extension_action_api_)) {
556 was_registered = true; 672 was_registered = true;
557 extension_action_observer_.RemoveAll(); 673 extension_action_observer_.RemoveAll();
558 } 674 }
559 extension_action_api_->SetBrowserActionVisibility(extension->id(), 675 extension_action_api_->SetBrowserActionVisibility(id, visible);
560 visible);
561 if (was_registered) 676 if (was_registered)
562 extension_action_observer_.Add(extension_action_api_); 677 extension_action_observer_.Add(extension_action_api_);
563 } 678 }
564 } 679 }
565 } 680 }
566 681
567 void ExtensionToolbarModel::MaybeUpdateVisibilityPrefs() { 682 void ToolbarActionsModel::MaybeUpdateVisibilityPrefs() {
568 for (size_t i = 0u; i < toolbar_items_.size(); ++i) 683 for (size_t i = 0u; i < toolbar_items_.size(); ++i)
569 MaybeUpdateVisibilityPref(toolbar_items_[i].get(), i); 684 MaybeUpdateVisibilityPref(toolbar_items_[i], i);
570 } 685 }
571 686
572 void ExtensionToolbarModel::OnExtensionToolbarPrefChange() { 687 void ToolbarActionsModel::OnActionToolbarPrefChange() {
573 // If extensions are not ready, defer to later Populate() call. 688 // If extensions are not ready, defer to later Populate() call.
574 if (!extensions_initialized_) 689 if (!actions_initialized_)
575 return; 690 return;
576 691
577 // Recalculate |last_known_positions_| to be |pref_positions| followed by 692 // Recalculate |last_known_positions_| to be |pref_positions| followed by
578 // ones that are only in |last_known_positions_|. 693 // ones that are only in |last_known_positions_|.
579 ExtensionIdList pref_positions = extension_prefs_->GetToolbarOrder(); 694 ActionIdList pref_positions = prefs_service_->GetToolbarOrder();
580 size_t pref_position_size = pref_positions.size(); 695 size_t pref_position_size = pref_positions.size();
581 for (size_t i = 0; i < last_known_positions_.size(); ++i) { 696 for (size_t i = 0; i < last_known_positions_.size(); ++i) {
582 if (std::find(pref_positions.begin(), pref_positions.end(), 697 if (std::find(pref_positions.begin(), pref_positions.end(),
583 last_known_positions_[i]) == pref_positions.end()) { 698 last_known_positions_[i]) == pref_positions.end()) {
584 pref_positions.push_back(last_known_positions_[i]); 699 pref_positions.push_back(last_known_positions_[i]);
585 } 700 }
586 } 701 }
587 last_known_positions_.swap(pref_positions); 702 last_known_positions_.swap(pref_positions);
588 703
589 int desired_index = 0; 704 int desired_index = 0;
590 // Loop over the updated list of last known positions, moving any extensions 705 // Loop over the updated list of last known positions, moving any extensions
591 // that are in the wrong place. 706 // that are in the wrong place.
592 for (const std::string& id : last_known_positions_) { 707 for (const std::string& id : last_known_positions_) {
593 int current_index = GetIndexForId(id); 708 int current_index = GetIndexForId(id);
594 if (current_index == -1) 709 if (current_index == -1)
595 continue; 710 continue;
596 if (current_index != desired_index) { 711 if (current_index != desired_index) {
597 scoped_refptr<const Extension> extension = toolbar_items_[current_index]; 712 std::string extension_id = toolbar_items_[current_index];
598 toolbar_items_.erase(toolbar_items_.begin() + current_index); 713 toolbar_items_.erase(toolbar_items_.begin() + current_index);
599 toolbar_items_.insert(toolbar_items_.begin() + desired_index, extension); 714 toolbar_items_.insert(toolbar_items_.begin() + desired_index,
715 extension_id);
600 // Notify the observers to keep them up-to-date. 716 // Notify the observers to keep them up-to-date.
601 FOR_EACH_OBSERVER( 717 FOR_EACH_OBSERVER(
602 Observer, observers_, 718 Observer, observers_,
603 OnToolbarExtensionMoved(extension.get(), desired_index)); 719 OnToolbarActionMoved(extension_id, desired_index));
604 } 720 }
605 ++desired_index; 721 ++desired_index;
606 } 722 }
607 723
608 if (last_known_positions_.size() > pref_position_size) { 724 if (last_known_positions_.size() > pref_position_size) {
609 // Need to update pref because we have extra icons. But can't call 725 // Need to update pref because we have extra icons. But can't call
610 // UpdatePrefs() directly within observation closure. 726 // UpdatePrefs() directly within observation closure.
611 base::ThreadTaskRunnerHandle::Get()->PostTask( 727 base::ThreadTaskRunnerHandle::Get()->PostTask(
612 FROM_HERE, base::Bind(&ExtensionToolbarModel::UpdatePrefs, 728 FROM_HERE, base::Bind(&ToolbarActionsModel::UpdatePrefs,
613 weak_ptr_factory_.GetWeakPtr())); 729 weak_ptr_factory_.GetWeakPtr()));
614 } 730 }
615 } 731 }
616 732
617 int ExtensionToolbarModel::GetIndexForId(const std::string& id) const { 733 int ToolbarActionsModel::GetIndexForId(const std::string& id) const {
618 for (size_t i = 0; i < toolbar_items().size(); ++i) { 734 for (size_t i = 0; i < toolbar_items_.size(); ++i) {
Devlin 2015/08/06 22:04:56 Again, toolbar_items() can potentially return diff
apacible 2015/08/10 22:38:10 Done.
619 if (toolbar_items()[i]->id() == id) 735 if (toolbar_items_[i] == id)
620 return i; 736 return i;
621 } 737 }
622 return -1; 738 return -1;
623 } 739 }
624 740
625 bool ExtensionToolbarModel::ShowExtensionActionPopup( 741 bool ToolbarActionsModel::ShowToolbarActionPopup(const std::string& id,
626 const Extension* extension, 742 Browser* browser,
627 Browser* browser, 743 bool grant_active_tab) {
628 bool grant_active_tab) {
629 base::ObserverListBase<Observer>::Iterator it(&observers_); 744 base::ObserverListBase<Observer>::Iterator it(&observers_);
630 Observer* obs = NULL; 745 Observer* obs = NULL;
631 // Look for the Observer associated with the browser. 746 // Look for the Observer associated with the browser.
632 // This would be cleaner if we had an abstract class for the Toolbar UI 747 // This would be cleaner if we had an abstract class for the Toolbar UI
633 // (like we do for LocationBar), but sadly, we don't. 748 // (like we do for LocationBar), but sadly, we don't.
634 while ((obs = it.GetNext()) != NULL) { 749 while ((obs = it.GetNext()) != NULL) {
635 if (obs->GetBrowser() == browser) 750 if (obs->GetBrowser() == browser)
636 return obs->ShowExtensionActionPopup(extension, grant_active_tab); 751 return obs->ShowToolbarActionPopup(id, grant_active_tab);
637 } 752 }
638 return false; 753 return false;
639 } 754 }
640 755
641 void ExtensionToolbarModel::EnsureVisibility( 756 void ToolbarActionsModel::EnsureVisibility(const ActionIdList& ids) {
642 const ExtensionIdList& extension_ids) {
643 if (all_icons_visible()) 757 if (all_icons_visible())
644 return; // Already showing all. 758 return; // Already showing all.
645 759
646 // Otherwise, make sure we have enough room to show all the extensions 760 // Otherwise, make sure we have enough room to show all the extensions
647 // requested. 761 // requested.
648 if (visible_icon_count() < extension_ids.size()) 762 if (visible_icon_count() < ids.size())
649 SetVisibleIconCount(extension_ids.size()); 763 SetVisibleIconCount(ids.size());
650 764
651 if (all_icons_visible()) 765 if (all_icons_visible())
652 return; // May have been set to max by SetVisibleIconCount. 766 return; // May have been set to max by SetVisibleIconCount.
653 767
654 // Guillotine's Delight: Move an orange noble to the front of the line. 768 // Guillotine's Delight: Move an orange noble to the front of the line.
655 for (ExtensionIdList::const_iterator it = extension_ids.begin(); 769 for (ActionIdList::const_iterator it = ids.begin();
656 it != extension_ids.end(); ++it) { 770 it != ids.end(); ++it) {
657 for (ExtensionList::const_iterator extension = toolbar_items_.begin(); 771 for (ActionIdList::const_iterator id = toolbar_items_.begin();
658 extension != toolbar_items_.end(); ++extension) { 772 id != toolbar_items_.end(); ++id) {
659 if ((*extension)->id() == (*it)) { 773 if ((*id) == (*it)) {
660 if (extension - toolbar_items_.begin() >= 774 if (id - toolbar_items_.begin() >=
661 static_cast<int>(visible_icon_count())) 775 static_cast<int>(visible_icon_count()))
662 MoveExtensionIcon((*extension)->id(), 0); 776 MoveActionIcon((*id), 0);
663 break; 777 break;
664 } 778 }
665 } 779 }
666 } 780 }
667 } 781 }
668 782
669 bool ExtensionToolbarModel::HighlightExtensions( 783 bool ToolbarActionsModel::HighlightActions(const ActionIdList& ids,
670 const ExtensionIdList& extension_ids, 784 HighlightType highlight_type) {
671 HighlightType highlight_type) {
672 highlighted_items_.clear(); 785 highlighted_items_.clear();
673 786
674 for (ExtensionIdList::const_iterator id = extension_ids.begin(); 787 for (std::string action_id : ids) {
675 id != extension_ids.end(); 788 for (std::string toolbar_item_id : toolbar_items_) {
676 ++id) { 789 if (action_id == toolbar_item_id)
677 for (ExtensionList::const_iterator extension = toolbar_items_.begin(); 790 highlighted_items_.push_back(toolbar_item_id);
678 extension != toolbar_items_.end();
679 ++extension) {
680 if (*id == (*extension)->id())
681 highlighted_items_.push_back(*extension);
682 } 791 }
683 } 792 }
684 793
685 // If we have any items in |highlighted_items_|, then we entered highlighting 794 // If we have any items in |highlighted_items_|, then we entered highlighting
686 // mode. 795 // mode.
687 if (highlighted_items_.size()) { 796 if (highlighted_items_.size()) {
688 // It's important that is_highlighting_ is changed immediately before the 797 // It's important that is_highlighting_ is changed immediately before the
689 // observers are notified since it changes the result of toolbar_items(). 798 // observers are notified since it changes the result of toolbar_items().
690 highlight_type_ = highlight_type; 799 highlight_type_ = highlight_type;
691 FOR_EACH_OBSERVER(Observer, observers_, 800 FOR_EACH_OBSERVER(Observer, observers_,
692 OnToolbarHighlightModeChanged(true)); 801 OnToolbarHighlightModeChanged(true));
693 802
694 // We set the visible icon count after the highlight mode change because 803 // We set the visible icon count after the highlight mode change because
695 // the UI actions are created/destroyed during highlight, and doing that 804 // the UI actions are created/destroyed during highlight, and doing that
696 // prior to changing the size allows us to still have smooth animations. 805 // prior to changing the size allows us to still have smooth animations.
697 if (visible_icon_count() < extension_ids.size()) 806 if (visible_icon_count() < ids.size())
698 SetVisibleIconCount(extension_ids.size()); 807 SetVisibleIconCount(ids.size());
699 808
700 return true; 809 return true;
701 } 810 }
702 811
703 // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if 812 // Otherwise, we didn't enter highlighting mode (and, in fact, exited it if
704 // we were otherwise in it). 813 // we were otherwise in it).
705 if (is_highlighting()) 814 if (is_highlighting())
706 StopHighlighting(); 815 StopHighlighting();
707 return false; 816 return false;
708 } 817 }
709 818
710 void ExtensionToolbarModel::StopHighlighting() { 819 void ToolbarActionsModel::StopHighlighting() {
711 if (is_highlighting()) { 820 if (is_highlighting()) {
712 // It's important that is_highlighting_ is changed immediately before the 821 // It's important that is_highlighting_ is changed immediately before the
713 // observers are notified since it changes the result of toolbar_items(). 822 // observers are notified since it changes the result of toolbar_items().
714 highlight_type_ = HIGHLIGHT_NONE; 823 highlight_type_ = HIGHLIGHT_NONE;
715 FOR_EACH_OBSERVER(Observer, observers_, 824 FOR_EACH_OBSERVER(Observer, observers_,
716 OnToolbarHighlightModeChanged(false)); 825 OnToolbarHighlightModeChanged(false));
717 826
718 // For the same reason, we don't clear highlighted_items_ until after the 827 // For the same reason, we don't clear highlighted_items_ until after the
719 // mode changed. 828 // mode changed.
720 highlighted_items_.clear(); 829 highlighted_items_.clear();
721 830
722 // We set the visible icon count after the highlight mode change because 831 // We set the visible icon count after the highlight mode change because
723 // the UI actions are created/destroyed during highlight, and doing that 832 // the UI actions are created/destroyed during highlight, and doing that
724 // prior to changing the size allows us to still have smooth animations. 833 // prior to changing the size allows us to still have smooth animations.
725 int saved_icon_count = prefs_->GetInteger(pref_names::kToolbarSize); 834 int saved_icon_count = prefs_->GetInteger(
835 extensions::pref_names::kToolbarSize);
726 if (saved_icon_count != visible_icon_count_) 836 if (saved_icon_count != visible_icon_count_)
727 SetVisibleIconCount(saved_icon_count); 837 SetVisibleIconCount(saved_icon_count);
728 } 838 }
729 } 839 }
730 840
731 bool ExtensionToolbarModel::RedesignIsShowingNewIcons() const { 841 bool ToolbarActionsModel::RedesignIsShowingNewIcons() const {
732 for (const scoped_refptr<const Extension>& extension : toolbar_items_) { 842 for (std::string id : toolbar_items_) {
Devlin 2015/08/06 22:04:55 const &
apacible 2015/08/10 22:38:10 Done.
733 // Without the redesign, we only show extensions with browser actions. 843 if (IsKnownActionWithType(id, ACTION_EXTENSION)) {
734 // Any extension without a browser action is an indication that we're 844 // Without the redesign, we only show extensions with browser actions.
735 // showing something new. 845 // Any extension without a browser action is an indication that we're
736 if (!extension->manifest()->HasKey(manifest_keys::kBrowserAction)) 846 // showing something new.
737 return true; 847 if (!GetExtensionById(id)->manifest()->HasKey(
848 extensions::manifest_keys::kBrowserAction))
849 return true;
850 }
738 } 851 }
739 return false; 852 return false;
740 } 853 }
741 854
742 } // namespace extensions 855 bool ToolbarActionsModel::IsKnownActionWithType(const std::string& id,
856 ActionType type) const {
857 return action_id_to_type_.count(id) > 0 &&
858 action_id_to_type_.find(id)->second == type;
859 }
860
861 const extensions::Extension* ToolbarActionsModel::GetExtensionById(
862 const std::string& id) const {
863 return extension_registry_->enabled_extensions().GetByID(id);
864 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698