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