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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |