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

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

Issue 766263003: [Extension Toolbar] Refactor and finish pop out logic for actions (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/ui/toolbar/toolbar_actions_bar.h" 5 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "chrome/browser/extensions/extension_action_manager.h" 8 #include "chrome/browser/extensions/extension_action_manager.h"
9 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/sessions/session_tab_helper.h" 10 #include "chrome/browser/sessions/session_tab_helper.h"
11 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_window.h" 12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/extensions/extension_action_view_controller.h" 13 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h" 14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
15 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h" 16 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
16 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" 17 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
17 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h" 18 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h"
18 #include "components/crx_file/id_util.h" 19 #include "components/crx_file/id_util.h"
19 #include "extensions/browser/extension_system.h" 20 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/runtime_data.h" 21 #include "extensions/browser/runtime_data.h"
21 #include "extensions/common/extension.h" 22 #include "extensions/common/extension.h"
22 #include "extensions/common/feature_switch.h" 23 #include "extensions/common/feature_switch.h"
23 #include "grit/theme_resources.h" 24 #include "grit/theme_resources.h"
24 #include "ui/base/resource/resource_bundle.h" 25 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/image/image_skia.h" 26 #include "ui/gfx/image/image_skia.h"
26 27
27 namespace { 28 namespace {
28 29
30 using WeakToolbarActions = std::vector<ToolbarActionViewController*>;
31
29 #if defined(OS_MACOSX) 32 #if defined(OS_MACOSX)
30 const int kItemSpacing = 2; 33 const int kItemSpacing = 2;
31 const int kLeftPadding = kItemSpacing + 1; 34 const int kLeftPadding = kItemSpacing + 1;
32 const int kRightPadding = 0; 35 const int kRightPadding = 0;
33 const int kOverflowLeftPadding = kItemSpacing; 36 const int kOverflowLeftPadding = kItemSpacing;
34 const int kOverflowRightPadding = kItemSpacing; 37 const int kOverflowRightPadding = kItemSpacing;
35 #else 38 #else
36 // Matches ToolbarView::kStandardSpacing; 39 // Matches ToolbarView::kStandardSpacing;
37 const int kLeftPadding = 3; 40 const int kLeftPadding = 3;
38 const int kRightPadding = kLeftPadding; 41 const int kRightPadding = kLeftPadding;
(...skipping 13 matching lines...) Expand all
52 initialized = true; 55 initialized = true;
53 gfx::ImageSkia* skia = 56 gfx::ImageSkia* skia =
54 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 57 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
55 IDR_BROWSER_ACTION); 58 IDR_BROWSER_ACTION);
56 icon_height = skia->height(); 59 icon_height = skia->height();
57 icon_width = skia->width(); 60 icon_width = skia->width();
58 } 61 }
59 return type == WIDTH ? icon_width : icon_height; 62 return type == WIDTH ? icon_width : icon_height;
60 } 63 }
61 64
65 // Sorts |to_sort| to match |reference|, using |equal| as a comparison
66 // function. This allows comparing two different types without needing to
67 // construct a more cumbersome comparator class.
68 template<typename Type1, typename Type2>
69 void SortContainer(std::vector<Type1>* to_sort,
70 const std::vector<Type2>& reference,
71 bool (*equal)(const Type1&, const Type2&)) {
72 DCHECK_GE(to_sort->size(), reference.size()) <<
73 "|to_sort| must contain all elements in |reference|.";
74 if (reference.empty())
75 return;
76 // Run through the each element and compare it to the reference. If something
77 // is out of place, find the correct spot for it.
78 for (size_t i = 0; i < reference.size() - 1; ++i) {
79 if (!(*equal)(to_sort->at(i), reference[i])) {
80 // Find where the correct index (it's guaranteed to be after our current
Finnur 2014/12/12 15:06:07 nit: Missing the word 'is'?
Devlin 2014/12/12 18:27:06 Done.
81 // index, since everything up to this point is correct), and swap.
82 size_t j = i + 1;
83 while (!(*equal)(to_sort->at(j), reference[i])) {
84 ++j;
85 DCHECK_LE(j, to_sort->size()) <<
86 "Item in |reference| not found in |to_sort|.";
87 }
88 std::swap(to_sort->at(i), to_sort->at(j));
89 }
90 }
91 }
92
62 } // namespace 93 } // namespace
63 94
95 bool ToolbarActionsBar::pop_out_actions_to_run = false;
96
97 // A class to implement an optional tab ordering that "pops out" actions that
98 // want to run on a particular page, as part of our experimentation with how to
99 // best signal that actions like extension page actions want to run.
100 // TODO(devlin): Once we finally settle on the right behavior, determine if
101 // we need this.
102 class ToolbarActionsBar::TabOrderHelper
103 : public TabStripModelObserver {
104 public:
105 TabOrderHelper(ToolbarActionsBar* toolbar,
106 Browser* browser,
107 extensions::ExtensionToolbarModel* model);
108 ~TabOrderHelper() override;
109
110 // Returns the number of extra icons that should appear on the given |tab_id|
111 // because of actions that are going to pop out.
112 size_t GetExtraIconCount(int tab_id);
113
114 // Returns the item order of actions for the tab with the given
115 // |web_contents|.
116 WeakToolbarActions GetActionOrder(content::WebContents* web_contents);
117
118 // Notifies the TabOrderHelper that a given |action| does/doesn't want to run
119 // on the tab indicated by |tab_id|.
120 void SetActionWantsToRun(ToolbarActionViewController* action,
121 int tab_id,
122 bool wants_to_run);
123
124 // Notifies the TabOrderHelper that a given |action| has been removed.
125 void ActionRemoved(ToolbarActionViewController* action);
126
127 // Handles a resize, including updating any actions that want to act and
128 // updating the model.
129 void HandleResize(size_t resized_count, int tab_id);
130
131 // Handles a drag and drop, including updating any actions that want to act
132 // and updating the model.
133 void HandleDragDrop(int dragged,
134 int dropped,
135 ToolbarActionsBar::DragType drag_type,
136 int tab_id);
137
138 private:
139 // TabStripModelObserver:
140 void TabInsertedAt(content::WebContents* web_contents,
141 int index,
142 bool foreground) override;
143 void TabDetachedAt(content::WebContents* web_contents, int index) override;
144 void TabStripModelDeleted() override;
145
146 // The set of tabs for the given action (the key) is currently "popped out".
147 // "Popped out" actions are those that were in the overflow menu normally, but
148 // want to run and are moved to the main bar so the user can see them.
149 std::map<ToolbarActionViewController*, std::set<int>> popped_out_in_tabs_;
150
151 // The set of tab ids that have been checked for whether actions need to be
152 // popped out or not.
153 std::set<int> tabs_checked_for_pop_out_;
154
155 // The owning ToolbarActionsBar.
156 ToolbarActionsBar* toolbar_;
157
158 // The associated toolbar model.
159 extensions::ExtensionToolbarModel* model_;
160
161 // A scoped tab strip observer so we can clean up |tabs_checked_for_popout_|.
162 ScopedObserver<TabStripModel, TabStripModelObserver> tab_strip_observer_;
163
164 DISALLOW_COPY_AND_ASSIGN(TabOrderHelper);
165 };
166
167 ToolbarActionsBar::TabOrderHelper::TabOrderHelper(
168 ToolbarActionsBar* toolbar,
169 Browser* browser,
170 extensions::ExtensionToolbarModel* model)
171 : toolbar_(toolbar),
172 model_(model),
173 tab_strip_observer_(this) {
174 tab_strip_observer_.Add(browser->tab_strip_model());
175 }
176
177 ToolbarActionsBar::TabOrderHelper::~TabOrderHelper() {
178 }
179
180 size_t ToolbarActionsBar::TabOrderHelper::GetExtraIconCount(int tab_id) {
181 size_t extra_icons = 0;
182 const WeakToolbarActions& toolbar_actions = toolbar_->toolbar_actions();
183 for (ToolbarActionViewController* action : toolbar_actions) {
184 auto actions_tabs = popped_out_in_tabs_.find(action);
185 if (actions_tabs != popped_out_in_tabs_.end() &&
186 actions_tabs->second.count(tab_id))
187 ++extra_icons;
188 }
189 return extra_icons;
190 }
191
192 void ToolbarActionsBar::TabOrderHelper::HandleResize(size_t resized_count,
193 int tab_id) {
194 int extra = GetExtraIconCount(tab_id);
195 size_t tab_icon_count = model_->visible_icon_count() + extra;
196 bool reorder_necessary = false;
197 const WeakToolbarActions& toolbar_actions = toolbar_->toolbar_actions();
198 if (resized_count < tab_icon_count) {
199 for (int i = resized_count; i < extra; ++i) {
200 // If an extension that was popped out to act is overflowed, then it
201 // should no longer be popped out, and it also doesn't count for adjusting
202 // the visible count (since it wasn't really out to begin with).
203 if (popped_out_in_tabs_[toolbar_actions[i]].count(tab_id)) {
204 reorder_necessary = true;
205 popped_out_in_tabs_[toolbar_actions[i]].erase(tab_id);
206 ++(resized_count);
207 }
208 }
209 } else {
210 // If the user increases the toolbar size while actions that popped out are
211 // visible, we need to re-arrange the icons in other windows to be
212 // consistent with what the user sees.
213 // That is, if the normal order is A, B, [C, D] (with C and D hidden), C
214 // pops out to act, and then the user increases the size of the toolbar,
215 // the user sees uncovering D (since C is already out). This is what should
216 // happen in all windows.
217 for (size_t i = tab_icon_count; i < resized_count; ++i) {
218 if (toolbar_actions[i]->GetId() !=
219 model_->toolbar_items()[i - extra]->id())
220 model_->MoveExtensionIcon(toolbar_actions[i]->GetId(), i - extra);
221 }
222 }
223
224 resized_count -= extra;
225 model_->SetVisibleIconCount(resized_count);
226 if (reorder_necessary)
227 toolbar_->ReorderActions();
228 }
229
230 void ToolbarActionsBar::TabOrderHelper::HandleDragDrop(
231 int dragged_index,
232 int dropped_index,
233 ToolbarActionsBar::DragType drag_type,
234 int tab_id) {
235 const WeakToolbarActions& toolbar_actions = toolbar_->toolbar_actions();
236 ToolbarActionViewController* action = toolbar_actions[dragged_index];
237 int delta = 0;
238 switch (drag_type) {
239 case ToolbarActionsBar::DRAG_TO_OVERFLOW:
240 // If the user moves an action back into overflow, then we don't adjust
241 // the base visible count, but do stop popping that action out.
242 if (popped_out_in_tabs_[action].count(tab_id))
243 popped_out_in_tabs_[action].erase(tab_id);
244 else
245 delta = -1;
246 break;
247 case ToolbarActionsBar::DRAG_TO_MAIN:
248 delta = 1;
249 break;
250 case ToolbarActionsBar::DRAG_TO_SAME:
251 // If the user moves an action that had popped out to be on the toolbar,
252 // then we treat it as "pinning" the action, and adjust the base visible
253 // count to accommodate.
254 if (popped_out_in_tabs_[action].count(tab_id)) {
255 delta = 1;
256 popped_out_in_tabs_[action].erase(tab_id);
257 }
258 break;
259 }
260
261 // If there are any actions that are in front of the dropped index only
262 // because they were popped out, decrement the dropped index.
263 for (int i = 0; i < dropped_index; ++i) {
264 if (i != dragged_index &&
265 model_->GetIndexForId(toolbar_actions[i]->GetId()) >= dropped_index)
266 --dropped_index;
267 }
268
269 model_->MoveExtensionIcon(action->GetId(), dropped_index);
270
271 if (delta)
272 model_->SetVisibleIconCount(model_->visible_icon_count() + delta);
273 }
274
275 void ToolbarActionsBar::TabOrderHelper::SetActionWantsToRun(
276 ToolbarActionViewController* action,
277 int tab_id,
278 bool wants_to_run) {
279 bool is_overflowed = model_->GetIndexForId(action->GetId()) >=
280 static_cast<int>(model_->visible_icon_count());
281 bool reorder_necessary = false;
282 if (wants_to_run && is_overflowed) {
283 popped_out_in_tabs_[action].insert(tab_id);
284 reorder_necessary = true;
285 } else if (!wants_to_run && popped_out_in_tabs_[action].count(tab_id)) {
286 popped_out_in_tabs_[action].erase(tab_id);
287 reorder_necessary = true;
288 }
289 if (reorder_necessary)
290 toolbar_->ReorderActions();
291 }
292
293 void ToolbarActionsBar::TabOrderHelper::ActionRemoved(
294 ToolbarActionViewController* action) {
295 popped_out_in_tabs_.erase(action);
296 }
297
298 WeakToolbarActions ToolbarActionsBar::TabOrderHelper::GetActionOrder(
299 content::WebContents* web_contents) {
300 WeakToolbarActions toolbar_actions = toolbar_->toolbar_actions();
301 // First, make sure that we've checked any actions that want to run.
302 int tab_id = SessionTabHelper::IdForTab(web_contents);
303 if (!tabs_checked_for_pop_out_.count(tab_id)) {
304 tabs_checked_for_pop_out_.insert(tab_id);
305 for (ToolbarActionViewController* toolbar_action : toolbar_actions) {
306 if (toolbar_action->WantsToRun(web_contents))
307 popped_out_in_tabs_[toolbar_action].insert(tab_id);
308 }
309 }
310
311 // Then, shift any actions that want to run to the front.
312 size_t insert_at = 0;
313 // Rotate any actions that want to run to the boundary between visible and
314 // overflowed actions.
315 for (WeakToolbarActions::iterator iter =
316 toolbar_actions.begin() + model_->visible_icon_count();
317 iter != toolbar_actions.end(); ++iter) {
318 if (popped_out_in_tabs_[(*iter)].count(tab_id)) {
319 std::rotate(toolbar_actions.begin() + insert_at, iter, iter + 1);
320 ++insert_at;
321 }
322 }
323
324 return toolbar_actions;
325 }
326
327 void ToolbarActionsBar::TabOrderHelper::TabInsertedAt(
328 content::WebContents* web_contents,
329 int index,
330 bool foreground) {
331 if (foreground)
332 toolbar_->ReorderActions();
333 }
334
335 void ToolbarActionsBar::TabOrderHelper::TabDetachedAt(
336 content::WebContents* web_contents,
337 int index) {
338 int tab_id = SessionTabHelper::IdForTab(web_contents);
339 for (auto& tabs : popped_out_in_tabs_)
340 tabs.second.erase(tab_id);
341 tabs_checked_for_pop_out_.erase(tab_id);
342 }
343
344 void ToolbarActionsBar::TabOrderHelper::TabStripModelDeleted() {
345 tab_strip_observer_.RemoveAll();
346 }
347
64 ToolbarActionsBar::PlatformSettings::PlatformSettings(bool in_overflow_mode) 348 ToolbarActionsBar::PlatformSettings::PlatformSettings(bool in_overflow_mode)
65 : left_padding(in_overflow_mode ? kOverflowLeftPadding : kLeftPadding), 349 : left_padding(in_overflow_mode ? kOverflowLeftPadding : kLeftPadding),
66 right_padding(in_overflow_mode ? kOverflowRightPadding : kRightPadding), 350 right_padding(in_overflow_mode ? kOverflowRightPadding : kRightPadding),
67 item_spacing(kItemSpacing), 351 item_spacing(kItemSpacing),
68 icons_per_overflow_menu_row(1), 352 icons_per_overflow_menu_row(1),
69 chevron_enabled(!extensions::FeatureSwitch::extension_action_redesign()-> 353 chevron_enabled(!extensions::FeatureSwitch::extension_action_redesign()->
70 IsEnabled()) { 354 IsEnabled()) {
71 } 355 }
72 356
73 ToolbarActionsBar::ToolbarActionsBar(ToolbarActionsBarDelegate* delegate, 357 ToolbarActionsBar::ToolbarActionsBar(ToolbarActionsBarDelegate* delegate,
74 Browser* browser, 358 Browser* browser,
75 bool in_overflow_mode) 359 ToolbarActionsBar* main_bar)
76 : delegate_(delegate), 360 : delegate_(delegate),
77 browser_(browser), 361 browser_(browser),
78 model_(extensions::ExtensionToolbarModel::Get(browser_->profile())), 362 model_(extensions::ExtensionToolbarModel::Get(browser_->profile())),
79 in_overflow_mode_(in_overflow_mode), 363 main_bar_(main_bar),
80 platform_settings_(in_overflow_mode), 364 overflow_bar_(nullptr),
365 platform_settings_(main_bar != nullptr),
81 model_observer_(this), 366 model_observer_(this),
82 tab_strip_observer_(this),
83 suppress_layout_(false), 367 suppress_layout_(false),
84 suppress_animation_(true) { 368 suppress_animation_(true) {
85 if (model_) // |model_| can be null in unittests. 369 if (model_) // |model_| can be null in unittests.
86 model_observer_.Add(model_); 370 model_observer_.Add(model_);
87 tab_strip_observer_.Add(browser_->tab_strip_model()); 371 if (in_overflow_mode())
372 main_bar_->overflow_bar_ = this;
373 else if (pop_out_actions_to_run)
374 tab_order_helper_.reset(new TabOrderHelper(this, browser_, model_));
88 } 375 }
89 376
90 ToolbarActionsBar::~ToolbarActionsBar() { 377 ToolbarActionsBar::~ToolbarActionsBar() {
91 // We don't just call DeleteActions() here because it makes assumptions about 378 // We don't just call DeleteActions() here because it makes assumptions about
92 // the order of deletion between the views and the ToolbarActionsBar. 379 // the order of deletion between the views and the ToolbarActionsBar.
93 DCHECK(toolbar_actions_.empty()) << 380 DCHECK(toolbar_actions_.empty()) <<
94 "Must call DeleteActions() before destruction."; 381 "Must call DeleteActions() before destruction.";
382 if (in_overflow_mode())
383 main_bar_->overflow_bar_ = nullptr;
384 DCHECK(overflow_bar_ == nullptr) << "Overflow bar cannot outlive main bar";
95 } 385 }
96 386
97 // static 387 // static
98 int ToolbarActionsBar::IconWidth(bool include_padding) { 388 int ToolbarActionsBar::IconWidth(bool include_padding) {
99 return GetIconDimension(WIDTH) + (include_padding ? kItemSpacing : 0); 389 return GetIconDimension(WIDTH) + (include_padding ? kItemSpacing : 0);
100 } 390 }
101 391
102 // static 392 // static
103 int ToolbarActionsBar::IconHeight() { 393 int ToolbarActionsBar::IconHeight() {
104 return GetIconDimension(HEIGHT); 394 return GetIconDimension(HEIGHT);
105 } 395 }
106 396
107 gfx::Size ToolbarActionsBar::GetPreferredSize() const { 397 gfx::Size ToolbarActionsBar::GetPreferredSize() const {
108 int icon_count = GetIconCount(); 398 int icon_count = GetIconCount();
109 if (in_overflow_mode_) { 399 if (in_overflow_mode()) {
110 // In overflow, we always have a preferred size of a full row (even if we 400 // In overflow, we always have a preferred size of a full row (even if we
111 // don't use it), and always of at least one row. The parent may decide to 401 // don't use it), and always of at least one row. The parent may decide to
112 // show us even when empty, e.g. as a drag target for dragging in icons from 402 // show us even when empty, e.g. as a drag target for dragging in icons from
113 // the main container. 403 // the main container.
114 int row_count = ((std::max(0, icon_count - 1)) / 404 int row_count = ((std::max(0, icon_count - 1)) /
115 platform_settings_.icons_per_overflow_menu_row) + 1; 405 platform_settings_.icons_per_overflow_menu_row) + 1;
116 return gfx::Size( 406 return gfx::Size(
117 IconCountToWidth(platform_settings_.icons_per_overflow_menu_row), 407 IconCountToWidth(platform_settings_.icons_per_overflow_menu_row),
118 row_count * IconHeight()); 408 row_count * IconHeight());
119 } 409 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 // Now we add an extra between-item padding value so the space can be divided 457 // Now we add an extra between-item padding value so the space can be divided
168 // evenly by (size of icon with padding). 458 // evenly by (size of icon with padding).
169 return static_cast<size_t>(std::max( 459 return static_cast<size_t>(std::max(
170 0, available_space + platform_settings_.item_spacing) / IconWidth(true)); 460 0, available_space + platform_settings_.item_spacing) / IconWidth(true));
171 } 461 }
172 462
173 size_t ToolbarActionsBar::GetIconCount() const { 463 size_t ToolbarActionsBar::GetIconCount() const {
174 if (!model_) 464 if (!model_)
175 return 0u; 465 return 0u;
176 466
177 size_t visible_icons = model_->visible_icon_count(); 467 size_t extra_icons = 0;
468 if (tab_order_helper_) {
469 extra_icons = tab_order_helper_->GetExtraIconCount(
470 SessionTabHelper::IdForTab(
471 browser_->tab_strip_model()->GetActiveWebContents()));
472 }
473
474 size_t visible_icons = in_overflow_mode() ?
475 toolbar_actions_.size() - main_bar_->GetIconCount() :
476 model_->visible_icon_count() + extra_icons;
477
178 #if DCHECK_IS_ON 478 #if DCHECK_IS_ON
179 // Good time for some sanity checks: We should never try to display more 479 // Good time for some sanity checks: We should never try to display more
180 // icons than we have, and we should always have a view per item in the model. 480 // icons than we have, and we should always have a view per item in the model.
181 // (The only exception is if this is in initialization.) 481 // (The only exception is if this is in initialization.)
182 if (!toolbar_actions_.empty() && !suppress_layout_ && 482 if (!toolbar_actions_.empty() && !suppress_layout_ &&
183 model_->extensions_initialized()) { 483 model_->extensions_initialized()) {
184 size_t num_extension_actions = 0u; 484 size_t num_extension_actions = 0u;
185 for (ToolbarActionViewController* action : toolbar_actions_) { 485 for (ToolbarActionViewController* action : toolbar_actions_) {
186 // No component action should ever have a valid extension id, so we can 486 // No component action should ever have a valid extension id, so we can
187 // use this to check the extension amount. 487 // use this to check the extension amount.
188 // TODO(devlin): Fix this to just check model size when the model also 488 // TODO(devlin): Fix this to just check model size when the model also
189 // includes component actions. 489 // includes component actions.
190 if (crx_file::id_util::IdIsValid(action->GetId())) 490 if (crx_file::id_util::IdIsValid(action->GetId()))
191 ++num_extension_actions; 491 ++num_extension_actions;
192 } 492 }
193 DCHECK_LE(visible_icons, num_extension_actions); 493 DCHECK_LE(visible_icons, num_extension_actions);
194 DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions); 494 DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions);
195 } 495 }
196 #endif 496 #endif
197 497
198 int tab_id = SessionTabHelper::IdForTab( 498 return visible_icons;
199 browser_->tab_strip_model()->GetActiveWebContents());
200 for (ToolbarActionViewController* action : toolbar_actions_) {
201 auto actions_tabs = popped_out_in_tabs_.find(action);
202 if (actions_tabs != popped_out_in_tabs_.end() &&
203 actions_tabs->second.count(tab_id))
204 ++visible_icons;
205 }
206
207 // The overflow displays any icons not shown by the main bar.
208 return in_overflow_mode_ ?
209 model_->toolbar_items().size() - visible_icons : visible_icons;
210 } 499 }
211 500
212 void ToolbarActionsBar::CreateActions() { 501 void ToolbarActionsBar::CreateActions() {
213 DCHECK(toolbar_actions_.empty()); 502 DCHECK(toolbar_actions_.empty());
214 // We wait for the extension system to be initialized before we add any 503 // We wait for the extension system to be initialized before we add any
215 // actions, as they rely on the extension system to function. 504 // actions, as they rely on the extension system to function.
216 if (!model_ || !model_->extensions_initialized()) 505 if (!model_ || !model_->extensions_initialized())
217 return; 506 return;
218 507
219 { 508 {
(...skipping 19 matching lines...) Expand all
239 ComponentToolbarActionsFactory::GetInstance()-> 528 ComponentToolbarActionsFactory::GetInstance()->
240 GetComponentToolbarActions(); 529 GetComponentToolbarActions();
241 DCHECK(component_actions.empty() || 530 DCHECK(component_actions.empty() ||
242 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()); 531 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
243 toolbar_actions_.insert(toolbar_actions_.end(), 532 toolbar_actions_.insert(toolbar_actions_.end(),
244 component_actions.begin(), 533 component_actions.begin(),
245 component_actions.end()); 534 component_actions.end());
246 component_actions.weak_clear(); 535 component_actions.weak_clear();
247 } 536 }
248 537
249 if (!toolbar_actions_.empty()) 538 if (!toolbar_actions_.empty()) {
250 ReorderActions(); 539 if (in_overflow_mode())
540 CopyActionOrder();
541 else
542 ReorderActions();
543 }
251 544
252 for (size_t i = 0; i < toolbar_actions_.size(); ++i) 545 for (size_t i = 0; i < toolbar_actions_.size(); ++i)
253 delegate_->AddViewForAction(toolbar_actions_[i], i); 546 delegate_->AddViewForAction(toolbar_actions_[i], i);
254 } 547 }
255 548
256 // Once the actions are created, we should animate the changes. 549 // Once the actions are created, we should animate the changes.
257 suppress_animation_ = false; 550 suppress_animation_ = false;
258 } 551 }
259 552
260 void ToolbarActionsBar::DeleteActions() { 553 void ToolbarActionsBar::DeleteActions() {
(...skipping 14 matching lines...) Expand all
275 // Don't layout until the end. 568 // Don't layout until the end.
276 base::AutoReset<bool> layout_resetter(&suppress_layout_, true); 569 base::AutoReset<bool> layout_resetter(&suppress_layout_, true);
277 for (ToolbarActionViewController* action : toolbar_actions_) 570 for (ToolbarActionViewController* action : toolbar_actions_)
278 action->UpdateState(); 571 action->UpdateState();
279 } 572 }
280 573
281 ReorderActions(); // Also triggers a draw. 574 ReorderActions(); // Also triggers a draw.
282 } 575 }
283 576
284 void ToolbarActionsBar::SetOverflowRowWidth(int width) { 577 void ToolbarActionsBar::SetOverflowRowWidth(int width) {
285 DCHECK(in_overflow_mode_); 578 DCHECK(in_overflow_mode());
286 platform_settings_.icons_per_overflow_menu_row = 579 platform_settings_.icons_per_overflow_menu_row =
287 std::max((width - kItemSpacing) / IconWidth(true), 1); 580 std::max((width - kItemSpacing) / IconWidth(true), 1);
288 } 581 }
289 582
290 void ToolbarActionsBar::OnResizeComplete(int width) { 583 void ToolbarActionsBar::OnResizeComplete(int width) {
291 DCHECK(!in_overflow_mode_); // The user can't resize the overflow container. 584 DCHECK(!in_overflow_mode()); // The user can't resize the overflow container.
292 size_t resized_count = WidthToIconCount(width); 585 size_t resized_count = WidthToIconCount(width);
293 size_t tab_icon_count = GetIconCount(); 586 // Save off the desired number of visible icons. We do this now instead of
294 int tab_id = SessionTabHelper::IdForTab(GetCurrentWebContents()); 587 // at the end of the animation so that even if the browser is shut down
295 int delta = tab_icon_count - model_->visible_icon_count(); 588 // while animating, the right value will be restored on next run.
296 bool reorder_necessary = false; 589 if (tab_order_helper_) {
297 if (resized_count < tab_icon_count) { 590 tab_order_helper_->HandleResize(
298 for (int i = resized_count; i < delta; ++i) { 591 resized_count,
299 // If an extension that was popped out to act is overflowed, then it 592 SessionTabHelper::IdForTab(GetCurrentWebContents()));
300 // should no longer be popped out, and it also doesn't count for adjusting
301 // the visible count (since it wasn't really out to begin with).
302 if (popped_out_in_tabs_[toolbar_actions_[i]].count(tab_id)) {
303 reorder_necessary = true;
304 popped_out_in_tabs_[toolbar_actions_[i]].erase(tab_id);
305 ++resized_count;
306 }
307 }
308 } else { 593 } else {
309 // If the user increases the toolbar size while actions that popped out are 594 model_->SetVisibleIconCount(resized_count);
310 // visible, we need to re-arrange the icons in other windows to be
311 // consistent with what the user sees.
312 // That is, if the normal order is A, B, [C, D] (with C and D hidden), C
313 // pops out to act, and then the user increases the size of the toolbar,
314 // the user sees uncovering D (since C is already out). This is what should
315 // happen in all windows.
316 for (size_t i = tab_icon_count; i < resized_count; ++i) {
317 if (toolbar_actions_[i]->GetId() !=
318 model_->toolbar_items()[i - delta]->id())
319 model_->MoveExtensionIcon(toolbar_actions_[i]->GetId(), i - delta);
320 }
321 } 595 }
322 resized_count -= delta;
323 // Save off the desired number of visible icons. We do this now instead of at
324 // the end of the animation so that even if the browser is shut down while
325 // animating, the right value will be restored on next run.
326 model_->SetVisibleIconCount(resized_count);
327 if (reorder_necessary)
328 ReorderActions();
329 } 596 }
330 597
331 void ToolbarActionsBar::OnDragDrop(int dragged_index, 598 void ToolbarActionsBar::OnDragDrop(int dragged_index,
332 int dropped_index, 599 int dropped_index,
333 DragType drag_type) { 600 DragType drag_type) {
334 ToolbarActionViewController* action = toolbar_actions_[dragged_index]; 601 // All drag-and-drop commands should go to the main bar.
335 int tab_id = SessionTabHelper::IdForTab(GetCurrentWebContents()); 602 DCHECK(!in_overflow_mode());
336 int delta = 0; 603
337 switch (drag_type) { 604 if (tab_order_helper_) {
338 case DRAG_TO_OVERFLOW: 605 tab_order_helper_->HandleDragDrop(
339 // If the user moves an action back into overflow, then we don't adjust 606 dragged_index,
340 // the base visible count, but do stop popping that action out. 607 dropped_index,
341 if (popped_out_in_tabs_[action].count(tab_id)) 608 drag_type,
342 popped_out_in_tabs_[action].erase(tab_id); 609 SessionTabHelper::IdForTab(GetCurrentWebContents()));
343 else 610 } else {
344 delta = -1; 611 int delta = 0;
345 break; 612 if (drag_type == DRAG_TO_OVERFLOW)
346 case DRAG_TO_MAIN: 613 delta = -1;
614 else if (drag_type == DRAG_TO_MAIN)
347 delta = 1; 615 delta = 1;
348 break; 616 model_->MoveExtensionIcon(toolbar_actions_[dragged_index]->GetId(),
349 case DRAG_TO_SAME: 617 dropped_index);
350 // If the user moves an action that had popped out to be on the toolbar, 618 if (delta)
351 // then we treat it as "pinning" the action, and adjust the base visible 619 model_->SetVisibleIconCount(model_->visible_icon_count() + delta);
352 // count to accommodate.
353 if (popped_out_in_tabs_[action].count(tab_id)) {
354 delta = 1;
355 popped_out_in_tabs_[action].erase(tab_id);
356 }
357 break;
358 } 620 }
359
360 // If there are any actions that are in front of the dropped index only
361 // because they were popped out, decrement the dropped index.
362 for (int i = 0; i < dropped_index; ++i) {
363 if (i != dragged_index &&
364 model_->GetIndexForId(toolbar_actions_[i]->GetId()) >= dropped_index)
365 --dropped_index;
366 }
367
368 model_->MoveExtensionIcon(action->GetId(), dropped_index);
369
370 if (delta)
371 model_->SetVisibleIconCount(model_->visible_icon_count() + delta);
372 } 621 }
373 622
374 void ToolbarActionsBar::ToolbarExtensionAdded( 623 void ToolbarActionsBar::ToolbarExtensionAdded(
375 const extensions::Extension* extension, 624 const extensions::Extension* extension,
376 int index) { 625 int index) {
377 DCHECK(GetActionForId(extension->id()) == nullptr) << 626 DCHECK(GetActionForId(extension->id()) == nullptr) <<
378 "Asked to add a toolbar action view for an extension that already exists"; 627 "Asked to add a toolbar action view for an extension that already exists";
379 628
380 toolbar_actions_.insert( 629 toolbar_actions_.insert(
381 toolbar_actions_.begin() + index, 630 toolbar_actions_.begin() + index,
(...skipping 25 matching lines...) Expand all
407 void ToolbarActionsBar::ToolbarExtensionRemoved( 656 void ToolbarActionsBar::ToolbarExtensionRemoved(
408 const extensions::Extension* extension) { 657 const extensions::Extension* extension) {
409 ToolbarActions::iterator iter = toolbar_actions_.begin(); 658 ToolbarActions::iterator iter = toolbar_actions_.begin();
410 while (iter != toolbar_actions_.end() && (*iter)->GetId() != extension->id()) 659 while (iter != toolbar_actions_.end() && (*iter)->GetId() != extension->id())
411 ++iter; 660 ++iter;
412 661
413 if (iter == toolbar_actions_.end()) 662 if (iter == toolbar_actions_.end())
414 return; 663 return;
415 664
416 delegate_->RemoveViewForAction(*iter); 665 delegate_->RemoveViewForAction(*iter);
417 popped_out_in_tabs_.erase(*iter); 666 if (tab_order_helper_)
667 tab_order_helper_->ActionRemoved(*iter);
418 toolbar_actions_.erase(iter); 668 toolbar_actions_.erase(iter);
419 669
420 // If the extension is being upgraded we don't want the bar to shrink 670 // If the extension is being upgraded we don't want the bar to shrink
421 // because the icon is just going to get re-added to the same location. 671 // because the icon is just going to get re-added to the same location.
422 if (!extensions::ExtensionSystem::Get(browser_->profile())->runtime_data()-> 672 if (!extensions::ExtensionSystem::Get(browser_->profile())->runtime_data()->
423 IsBeingUpgraded(extension->id())) { 673 IsBeingUpgraded(extension->id())) {
424 if (toolbar_actions_.size() > model_->visible_icon_count()) { 674 if (toolbar_actions_.size() > model_->visible_icon_count()) {
425 // If we have more icons than we can show, then we must not be changing 675 // If we have more icons than we can show, then we must not be changing
426 // the container size (since we either removed an icon from the main 676 // the container size (since we either removed an icon from the main
427 // area and one from the overflow list will have shifted in, or we 677 // area and one from the overflow list will have shifted in, or we
(...skipping 19 matching lines...) Expand all
447 } 697 }
448 698
449 void ToolbarActionsBar::ToolbarExtensionUpdated( 699 void ToolbarActionsBar::ToolbarExtensionUpdated(
450 const extensions::Extension* extension) { 700 const extensions::Extension* extension) {
451 ToolbarActionViewController* action = GetActionForId(extension->id()); 701 ToolbarActionViewController* action = GetActionForId(extension->id());
452 // There might not be a view in cases where we are highlighting or if we 702 // There might not be a view in cases where we are highlighting or if we
453 // haven't fully initialized the actions. 703 // haven't fully initialized the actions.
454 if (action) { 704 if (action) {
455 content::WebContents* web_contents = GetCurrentWebContents(); 705 content::WebContents* web_contents = GetCurrentWebContents();
456 action->UpdateState(); 706 action->UpdateState();
457 bool wants_to_run = action->WantsToRun(web_contents);
458 707
459 // The action may need to be popped in or out of overflow. 708 if (tab_order_helper_) {
460 int index = std::find(toolbar_actions_.begin(), 709 tab_order_helper_->SetActionWantsToRun(
461 toolbar_actions_.end(), 710 action,
462 action) - toolbar_actions_.begin(); 711 SessionTabHelper::IdForTab(web_contents),
463 bool reorder_necessary = false; 712 action->WantsToRun(web_contents));
464 int tab_id = SessionTabHelper::IdForTab(web_contents);
465 if (wants_to_run && static_cast<size_t>(index) >= GetIconCount()) {
466 popped_out_in_tabs_[action].insert(tab_id);
467 reorder_necessary = true;
468 } else if (!wants_to_run && popped_out_in_tabs_[action].count(tab_id)) {
469 popped_out_in_tabs_[action].erase(tab_id);
470 reorder_necessary = true;
471 } 713 }
472 if (reorder_necessary)
473 ReorderActions();
474 } 714 }
475 } 715 }
476 716
477 bool ToolbarActionsBar::ShowExtensionActionPopup( 717 bool ToolbarActionsBar::ShowExtensionActionPopup(
478 const extensions::Extension* extension, 718 const extensions::Extension* extension,
479 bool grant_active_tab) { 719 bool grant_active_tab) {
480 // Don't override another popup, and only show in the active window. 720 // Don't override another popup, and only show in the active window.
481 if (delegate_->IsPopupRunning() || !browser_->window()->IsActive()) 721 if (delegate_->IsPopupRunning() || !browser_->window()->IsActive())
482 return false; 722 return false;
483 723
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 void ToolbarActionsBar::OnToolbarModelInitialized() { 764 void ToolbarActionsBar::OnToolbarModelInitialized() {
525 // We shouldn't have any actions before the model is initialized. 765 // We shouldn't have any actions before the model is initialized.
526 DCHECK(toolbar_actions_.empty()); 766 DCHECK(toolbar_actions_.empty());
527 CreateActions(); 767 CreateActions();
528 } 768 }
529 769
530 Browser* ToolbarActionsBar::GetBrowser() { 770 Browser* ToolbarActionsBar::GetBrowser() {
531 return browser_; 771 return browser_;
532 } 772 }
533 773
534 void ToolbarActionsBar::TabInsertedAt(content::WebContents* web_contents,
535 int index,
536 bool foreground) {
537 if (foreground)
538 ReorderActions();
539 }
540
541 void ToolbarActionsBar::TabDetachedAt(content::WebContents* web_contents,
542 int index) {
543 int tab_id = SessionTabHelper::IdForTab(web_contents);
544 for (auto& tabs : popped_out_in_tabs_)
545 tabs.second.erase(tab_id);
546 tabs_checked_for_pop_out_.erase(tab_id);
547 }
548
549 void ToolbarActionsBar::TabStripModelDeleted() {
550 tab_strip_observer_.RemoveAll();
551 }
552
553 void ToolbarActionsBar::ReorderActions() { 774 void ToolbarActionsBar::ReorderActions() {
554 if (toolbar_actions_.empty()) 775 if (toolbar_actions_.empty() || in_overflow_mode())
555 return; 776 return;
556 777
557 // First, reset the order to that of the model. Run through the views and 778 // First, reset the order to that of the model.
558 // compare them to the model; if something is out of place, find the correct 779 auto compare = [](ToolbarActionViewController* const& action,
559 // spot for it. 780 const scoped_refptr<const extensions::Extension>& ext) {
560 const extensions::ExtensionList& model_order = model_->toolbar_items(); 781 return action->GetId() == ext->id();
561 for (int i = 0; i < static_cast<int>(model_order.size() - 1); ++i) { 782 };
562 if (model_order[i]->id() != toolbar_actions_[i]->GetId()) { 783 SortContainer(&toolbar_actions_.get(), model_->toolbar_items(), +compare);
Finnur 2014/12/12 15:06:06 The + there is causing a compile failure.
Devlin 2014/12/12 18:27:06 Ah, C++11 lambdas, aren't you lovely. Fixed.
563 // Find where the correct view is (it's guaranteed to be after our current
564 // index, since everything up to this point is correct).
565 size_t j = i + 1;
566 while (model_order[i]->id() != toolbar_actions_[j]->GetId())
567 ++j;
568 std::swap(toolbar_actions_[i], toolbar_actions_[j]);
569 }
570 }
571 784
572 // Only adjust the order if the model isn't highlighting a particular subset. 785 // Only adjust the order if the model isn't highlighting a particular
573 if (!model_->is_highlighting()) { 786 // subset (and the specialized tab order is enabled).
574 // First, make sure that we've checked any actions that want to run. 787 if (!model_->is_highlighting() && tab_order_helper_) {
575 content::WebContents* web_contents = GetCurrentWebContents(); 788 WeakToolbarActions new_order =
576 int tab_id = SessionTabHelper::IdForTab(web_contents); 789 tab_order_helper_->GetActionOrder(GetCurrentWebContents());
577 if (!tabs_checked_for_pop_out_.count(tab_id)) { 790 auto compare = [](ToolbarActionViewController* const& first,
578 tabs_checked_for_pop_out_.insert(tab_id); 791 ToolbarActionViewController* const& second) {
579 for (ToolbarActionViewController* toolbar_action : toolbar_actions_) { 792 return first == second;
580 if (toolbar_action->WantsToRun(web_contents)) 793 };
581 popped_out_in_tabs_[toolbar_action].insert(tab_id); 794 SortContainer(
582 } 795 &toolbar_actions_.get(), new_order, +compare);
583 }
584
585 // Then, shift any actions that want to run to the front.
586 size_t insert_at = 0;
587 // Rotate any actions that want to run to the boundary between visible and
588 // overflowed actions.
589 for (ToolbarActions::iterator iter =
590 toolbar_actions_.begin() + model_->visible_icon_count();
591 iter != toolbar_actions_.end(); ++iter) {
592 if (popped_out_in_tabs_[(*iter)].count(tab_id)) {
593 std::rotate(toolbar_actions_.begin() + insert_at, iter, iter + 1);
594 ++insert_at;
595 }
596 }
597 } 796 }
598 797
599 // Our visible browser actions may have changed - re-Layout() and check the 798 // Our visible browser actions may have changed - re-Layout() and check the
600 // size (if we aren't suppressing the layout). 799 // size (if we aren't suppressing the layout).
601 if (!suppress_layout_) { 800 if (!suppress_layout_) {
602 ResizeDelegate(gfx::Tween::EASE_OUT, false); 801 ResizeDelegate(gfx::Tween::EASE_OUT, false);
603 delegate_->Redraw(true); 802 delegate_->Redraw(true);
604 } 803 }
804
805 if (overflow_bar_)
806 overflow_bar_->CopyActionOrder();
807 }
808
809 void ToolbarActionsBar::CopyActionOrder() {
810 DCHECK(in_overflow_mode());
811 if (!main_bar_->toolbar_actions().empty()) {
812 auto compare = [](ToolbarActionViewController* const& first,
813 ToolbarActionViewController* const& second) {
814 return first->GetId() == second->GetId();
815 };
816 SortContainer(
817 &toolbar_actions_.get(), main_bar_->toolbar_actions(), +compare);
818 if (!suppress_layout_) {
819 ResizeDelegate(gfx::Tween::EASE_OUT, false);
820 delegate_->Redraw(true);
821 }
822 }
605 } 823 }
606 824
607 ToolbarActionViewController* ToolbarActionsBar::GetActionForId( 825 ToolbarActionViewController* ToolbarActionsBar::GetActionForId(
608 const std::string& id) { 826 const std::string& id) {
609 for (ToolbarActionViewController* action : toolbar_actions_) { 827 for (ToolbarActionViewController* action : toolbar_actions_) {
610 if (action->GetId() == id) 828 if (action->GetId() == id)
611 return action; 829 return action;
612 } 830 }
613 return nullptr; 831 return nullptr;
614 } 832 }
615 833
616 content::WebContents* ToolbarActionsBar::GetCurrentWebContents() { 834 content::WebContents* ToolbarActionsBar::GetCurrentWebContents() {
617 return browser_->tab_strip_model()->GetActiveWebContents(); 835 return browser_->tab_strip_model()->GetActiveWebContents();
618 } 836 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/toolbar/toolbar_actions_bar.h ('k') | chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698