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