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

Side by Side Diff: chrome/browser/ui/views/toolbar/browser_actions_container.cc

Issue 675023002: Make extensions that desire to act pop out if in overflow (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/views/toolbar/browser_actions_container.h" 5 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "chrome/browser/extensions/extension_action_manager.h" 9 #include "chrome/browser/extensions/extension_action_manager.h"
10 #include "chrome/browser/extensions/tab_helper.h" 10 #include "chrome/browser/extensions/tab_helper.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 // TODO(devlin): We should move this to the model, once it supports component 53 // TODO(devlin): We should move this to the model, once it supports component
54 // actions. 54 // actions.
55 ScopedVector<ToolbarActionViewController> GetToolbarActions( 55 ScopedVector<ToolbarActionViewController> GetToolbarActions(
56 extensions::ExtensionToolbarModel* model, 56 extensions::ExtensionToolbarModel* model,
57 Browser* browser) { 57 Browser* browser) {
58 ScopedVector<ToolbarActionViewController> actions; 58 ScopedVector<ToolbarActionViewController> actions;
59 59
60 // Extension actions come first. 60 // Extension actions come first.
61 extensions::ExtensionActionManager* action_manager = 61 extensions::ExtensionActionManager* action_manager =
62 extensions::ExtensionActionManager::Get(browser->profile()); 62 extensions::ExtensionActionManager::Get(browser->profile());
63 const extensions::ExtensionList& toolbar_items = model->toolbar_items(); 63 const extensions::ExtensionList& toolbar_items = model->GetItemOrderForTab(
64 browser->tab_strip_model()->GetActiveWebContents());
64 for (const scoped_refptr<const Extension>& extension : toolbar_items) { 65 for (const scoped_refptr<const Extension>& extension : toolbar_items) {
65 actions.push_back(new ExtensionActionViewController( 66 actions.push_back(new ExtensionActionViewController(
66 extension.get(), 67 extension.get(),
67 browser, 68 browser,
68 action_manager->GetExtensionAction(*extension))); 69 action_manager->GetExtensionAction(*extension)));
69 } 70 }
70 71
71 // Component actions come second. 72 // Component actions come second.
72 ScopedVector<ToolbarActionViewController> component_actions = 73 ScopedVector<ToolbarActionViewController> component_actions =
73 ComponentToolbarActionsFactory::GetInstance()-> 74 ComponentToolbarActionsFactory::GetInstance()->
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 : initialized_(false), 119 : initialized_(false),
119 profile_(browser->profile()), 120 profile_(browser->profile()),
120 browser_(browser), 121 browser_(browser),
121 main_container_(main_container), 122 main_container_(main_container),
122 popup_owner_(NULL), 123 popup_owner_(NULL),
123 model_(extensions::ExtensionToolbarModel::Get(browser->profile())), 124 model_(extensions::ExtensionToolbarModel::Get(browser->profile())),
124 container_width_(0), 125 container_width_(0),
125 resize_area_(NULL), 126 resize_area_(NULL),
126 chevron_(NULL), 127 chevron_(NULL),
127 suppress_chevron_(false), 128 suppress_chevron_(false),
129 suppress_animation_(false),
130 suppress_layout_(false),
128 resize_amount_(0), 131 resize_amount_(0),
129 animation_target_size_(0) { 132 animation_target_size_(0) {
130 set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR); 133 set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR);
131 if (model_) // |model_| can be NULL in views unittests. 134 if (model_) // |model_| can be NULL in views unittests.
132 model_->AddObserver(this); 135 model_->AddObserver(this);
133 136
134 bool overflow_experiment = 137 bool overflow_experiment =
135 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled(); 138 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled();
136 DCHECK(!in_overflow_mode() || overflow_experiment); 139 DCHECK(!in_overflow_mode() || overflow_experiment);
137 140
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 BrowserActionView* BrowserActionsContainer::GetViewForExtension( 190 BrowserActionView* BrowserActionsContainer::GetViewForExtension(
188 const Extension* extension) { 191 const Extension* extension) {
189 for (BrowserActionView* view : browser_action_views_) { 192 for (BrowserActionView* view : browser_action_views_) {
190 if (view->view_controller()->GetId() == extension->id()) 193 if (view->view_controller()->GetId() == extension->id())
191 return view; 194 return view;
192 } 195 }
193 return NULL; 196 return NULL;
194 } 197 }
195 198
196 void BrowserActionsContainer::RefreshBrowserActionViews() { 199 void BrowserActionsContainer::RefreshBrowserActionViews() {
200 if (browser_action_views_.empty())
201 return; // Nothing to do.
202
203 // When we do a bulk-refresh of views (such as when we switch tabs), we don't
204 // animate the difference. We only animate when it's a change driven by the
205 // action.
206 suppress_animation_ = true;
Peter Kasting 2014/10/30 22:06:00 Nit: Use base::AutoReset to be safe against recurs
Devlin 2014/10/31 17:44:09 Done.
207 // Don't layout until the end.
208 suppress_layout_ = true;
209
197 for (BrowserActionView* view : browser_action_views_) 210 for (BrowserActionView* view : browser_action_views_)
198 view->UpdateState(); 211 view->UpdateState();
212
213 suppress_layout_ = false;
214 ReorderViews(); // Also triggers a layout.
215
216 suppress_animation_ = false;
199 } 217 }
200 218
201 void BrowserActionsContainer::CreateBrowserActionViews() { 219 void BrowserActionsContainer::CreateBrowserActionViews() {
202 DCHECK(browser_action_views_.empty()); 220 DCHECK(browser_action_views_.empty());
203 if (!model_) 221 if (!model_)
204 return; 222 return;
205 223
224 // We don't Layout while creating views. Instead, Layout() once at the end.
225 suppress_layout_ = true;
Peter Kasting 2014/10/30 22:06:00 Nit: AutoReset here too, perhaps
Devlin 2014/10/31 17:44:09 Done.
226
206 ScopedVector<ToolbarActionViewController> actions = 227 ScopedVector<ToolbarActionViewController> actions =
207 GetToolbarActions(model_, browser_); 228 GetToolbarActions(model_, browser_);
208 for (ToolbarActionViewController* controller : actions) { 229 for (ToolbarActionViewController* controller : actions) {
209 BrowserActionView* view = 230 BrowserActionView* view =
210 new BrowserActionView(make_scoped_ptr(controller), browser_, this); 231 new BrowserActionView(make_scoped_ptr(controller), browser_, this);
211 browser_action_views_.push_back(view); 232 browser_action_views_.push_back(view);
212 AddChildView(view); 233 AddChildView(view);
213 } 234 }
214 actions.weak_clear(); 235 actions.weak_clear();
236
237 suppress_layout_ = false;
238
239 Layout();
240 SchedulePaint();
215 } 241 }
216 242
217 void BrowserActionsContainer::DeleteBrowserActionViews() { 243 void BrowserActionsContainer::DeleteBrowserActionViews() {
218 HideActivePopup(); 244 HideActivePopup();
219 STLDeleteElements(&browser_action_views_); 245 STLDeleteElements(&browser_action_views_);
220 } 246 }
221 247
222 size_t BrowserActionsContainer::VisibleBrowserActions() const { 248 size_t BrowserActionsContainer::VisibleBrowserActions() const {
223 size_t visible_actions = 0; 249 size_t visible_actions = 0;
224 for (const BrowserActionView* view : browser_action_views_) { 250 for (const BrowserActionView* view : browser_action_views_) {
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 int min_width = std::min(MinimumNonemptyWidth(), IconCountToWidth(-1)); 381 int min_width = std::min(MinimumNonemptyWidth(), IconCountToWidth(-1));
356 return gfx::Size(min_width, IconHeight()); 382 return gfx::Size(min_width, IconHeight());
357 } 383 }
358 384
359 void BrowserActionsContainer::Layout() { 385 void BrowserActionsContainer::Layout() {
360 if (browser_action_views_.empty()) { 386 if (browser_action_views_.empty()) {
361 SetVisible(false); 387 SetVisible(false);
362 return; 388 return;
363 } 389 }
364 390
391 if (suppress_layout_)
Peter Kasting 2014/10/30 22:05:59 Nit: I think this should happen at the top of the
Devlin 2014/10/31 17:44:09 Done.
392 return;
393
365 SetVisible(true); 394 SetVisible(true);
366 if (resize_area_) 395 if (resize_area_)
367 resize_area_->SetBounds(0, 0, kItemSpacing, height()); 396 resize_area_->SetBounds(0, 0, kItemSpacing, height());
368 397
369 // If the icons don't all fit, show the chevron (unless suppressed). 398 // If the icons don't all fit, show the chevron (unless suppressed).
370 int max_x = GetPreferredSize().width(); 399 int max_x = GetPreferredSize().width();
371 if (IconCountToWidth(-1) > max_x && !suppress_chevron_ && chevron_) { 400 if (IconCountToWidth(-1) > max_x && !suppress_chevron_ && chevron_) {
372 chevron_->SetVisible(true); 401 chevron_->SetVisible(true);
373 gfx::Size chevron_size(chevron_->GetPreferredSize()); 402 gfx::Size chevron_size(chevron_->GetPreferredSize());
374 max_x -= chevron_size.width() + kChevronSpacing; 403 max_x -= chevron_size.width() + kChevronSpacing;
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 resize_amount_ = 0; 659 resize_amount_ = 0;
631 suppress_chevron_ = false; 660 suppress_chevron_ = false;
632 SetChevronVisibility(); 661 SetChevronVisibility();
633 OnBrowserActionVisibilityChanged(); 662 OnBrowserActionVisibilityChanged();
634 663
635 FOR_EACH_OBSERVER(BrowserActionsContainerObserver, 664 FOR_EACH_OBSERVER(BrowserActionsContainerObserver,
636 observers_, 665 observers_,
637 OnBrowserActionsContainerAnimationEnded()); 666 OnBrowserActionsContainerAnimationEnded());
638 } 667 }
639 668
640 content::WebContents* BrowserActionsContainer::GetCurrentWebContents() { 669 content::WebContents* BrowserActionsContainer::GetCurrentWebContents() const {
641 return browser_->tab_strip_model()->GetActiveWebContents(); 670 return browser_->tab_strip_model()->GetActiveWebContents();
642 } 671 }
643 672
644 extensions::ActiveTabPermissionGranter* 673 extensions::ActiveTabPermissionGranter*
645 BrowserActionsContainer::GetActiveTabPermissionGranter() { 674 BrowserActionsContainer::GetActiveTabPermissionGranter() {
646 content::WebContents* web_contents = GetCurrentWebContents(); 675 content::WebContents* web_contents = GetCurrentWebContents();
647 if (!web_contents) 676 if (!web_contents)
648 return NULL; 677 return NULL;
649 return extensions::TabHelper::FromWebContents(web_contents)-> 678 return extensions::TabHelper::FromWebContents(web_contents)->
650 active_tab_permission_granter(); 679 active_tab_permission_granter();
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 bool grant_active_tab) { 902 bool grant_active_tab) {
874 // Don't override another popup, and only show in the active window. 903 // Don't override another popup, and only show in the active window.
875 if (popup_owner_ || !browser_->window()->IsActive()) 904 if (popup_owner_ || !browser_->window()->IsActive())
876 return false; 905 return false;
877 906
878 BrowserActionView* view = GetViewForExtension(extension); 907 BrowserActionView* view = GetViewForExtension(extension);
879 return view && view->view_controller()->ExecuteAction(grant_active_tab); 908 return view && view->view_controller()->ExecuteAction(grant_active_tab);
880 } 909 }
881 910
882 void BrowserActionsContainer::ToolbarVisibleCountChanged() { 911 void BrowserActionsContainer::ToolbarVisibleCountChanged() {
883 if (GetPreferredWidth() != container_width_) 912 if (GetPreferredWidth() != container_width_) {
884 Animate(gfx::Tween::EASE_OUT, GetIconCount()); 913 Animate(gfx::Tween::EASE_OUT, GetIconCount());
914 } else if (animation_target_size_ != 0) {
915 // It's possible that we're right where we're supposed to be in terms of
916 // icon count, but that we're also currently resizing. If this is the case,
917 // end the current animation with the current width.
918 animation_target_size_ = container_width_;
919 resize_animation_->Reset();
920 }
885 } 921 }
886 922
887 void BrowserActionsContainer::ToolbarHighlightModeChanged( 923 void BrowserActionsContainer::ToolbarHighlightModeChanged(
888 bool is_highlighting) { 924 bool is_highlighting) {
889 // The visual highlighting is done in OnPaint(). It's a bit of a pain that 925 // The visual highlighting is done in OnPaint(). It's a bit of a pain that
890 // we delete and recreate everything here, but given everything else going on 926 // we delete and recreate everything here, but given everything else going on
891 // (the lack of highlight, n more extensions appearing, etc), it's not worth 927 // (the lack of highlight, n more extensions appearing, etc), it's not worth
892 // the extra complexity to create and insert only the new extensions. 928 // the extra complexity to create and insert only the new extensions.
893 DeleteBrowserActionViews(); 929 DeleteBrowserActionViews();
894 CreateBrowserActionViews(); 930 CreateBrowserActionViews();
895 Animate(gfx::Tween::LINEAR, GetIconCount()); 931 Animate(gfx::Tween::LINEAR, GetIconCount());
896 } 932 }
897 933
934 void BrowserActionsContainer::ToolbarReorderNecessary(
935 content::WebContents* web_contents) {
936 if (GetCurrentWebContents() == web_contents)
937 ReorderViews();
938 }
939
898 Browser* BrowserActionsContainer::GetBrowser() { 940 Browser* BrowserActionsContainer::GetBrowser() {
899 return browser_; 941 return browser_;
900 } 942 }
901 943
902 void BrowserActionsContainer::LoadImages() { 944 void BrowserActionsContainer::LoadImages() {
903 if (in_overflow_mode()) 945 if (in_overflow_mode())
904 return; // Overflow mode has neither a chevron nor highlighting. 946 return; // Overflow mode has neither a chevron nor highlighting.
905 947
906 ui::ThemeProvider* tp = GetThemeProvider(); 948 ui::ThemeProvider* tp = GetThemeProvider();
907 if (tp && chevron_) { 949 if (tp && chevron_) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 int BrowserActionsContainer::MinimumNonemptyWidth() const { 1015 int BrowserActionsContainer::MinimumNonemptyWidth() const {
974 if (!chevron_) 1016 if (!chevron_)
975 return ToolbarView::kStandardSpacing; 1017 return ToolbarView::kStandardSpacing;
976 return (ToolbarView::kStandardSpacing * 2) + kChevronSpacing + 1018 return (ToolbarView::kStandardSpacing * 2) + kChevronSpacing +
977 chevron_->GetPreferredSize().width(); 1019 chevron_->GetPreferredSize().width();
978 } 1020 }
979 1021
980 void BrowserActionsContainer::Animate(gfx::Tween::Type tween_type, 1022 void BrowserActionsContainer::Animate(gfx::Tween::Type tween_type,
981 size_t num_visible_icons) { 1023 size_t num_visible_icons) {
982 int target_size = IconCountToWidth(num_visible_icons); 1024 int target_size = IconCountToWidth(num_visible_icons);
983 if (resize_animation_ && !disable_animations_during_testing_) { 1025 if (resize_animation_ && !disable_animations_during_testing_ &&
1026 !suppress_animation_) {
984 // Animate! We have to set the animation_target_size_ after calling Reset(), 1027 // Animate! We have to set the animation_target_size_ after calling Reset(),
985 // because that could end up calling AnimationEnded which clears the value. 1028 // because that could end up calling AnimationEnded which clears the value.
986 resize_animation_->Reset(); 1029 resize_animation_->Reset();
987 resize_animation_->SetTweenType(tween_type); 1030 resize_animation_->SetTweenType(tween_type);
988 animation_target_size_ = target_size; 1031 animation_target_size_ = target_size;
989 resize_animation_->Show(); 1032 resize_animation_->Show();
990 } else { 1033 } else {
991 animation_target_size_ = target_size; 1034 animation_target_size_ = target_size;
992 AnimationEnded(resize_animation_.get()); 1035 AnimationEnded(resize_animation_.get());
993 } 1036 }
994 } 1037 }
995 1038
1039 void BrowserActionsContainer::ReorderViews() {
1040 extensions::ExtensionList new_order =
1041 model_->GetItemOrderForTab(GetCurrentWebContents());
1042 if (new_order.empty())
1043 return; // Nothing to do.
1044
1045 // Run through the views and compare them to the desired order. If something
1046 // is out of place, find the correct spot for it.
1047 for (size_t i = 0; i < new_order.size() - 1; ++i) {
1048 if (new_order[i]->id() !=
1049 browser_action_views_[i]->view_controller()->GetId()) {
1050 // Find where the correct view is (it's guaranteed to be after our current
1051 // index, since everything up to this point is correct).
Peter Kasting 2014/10/30 22:06:00 Is it conceivable that the two sets of views are n
Devlin 2014/10/31 17:44:09 Hmm...I don't think so. Views are added to the co
1052 size_t j = i + 1;
1053 while (new_order[i]->id() !=
1054 browser_action_views_[j]->view_controller()->GetId())
1055 ++j;
1056 std::swap(browser_action_views_[i], browser_action_views_[j]);
Peter Kasting 2014/10/30 22:06:00 I wonder if std::rotate() would make more sense th
Devlin 2014/10/31 17:44:09 The reason not to do that is because ReorderViews(
Peter Kasting 2014/10/31 19:01:07 Fine with me.
1057 }
1058 }
1059
1060 // Our visible browser actions may have changed - re-Layout() and check the
1061 // size.
1062 ToolbarVisibleCountChanged();
1063 OnBrowserActionVisibilityChanged();
1064 }
1065
996 size_t BrowserActionsContainer::GetIconCount() const { 1066 size_t BrowserActionsContainer::GetIconCount() const {
997 if (!model_) 1067 if (!model_)
998 return 0u; 1068 return 0u;
999 1069
1000 // Find the absolute value for the model's visible count. 1070 // Find the absolute value for the model's visible count.
1001 int model_visible_size = model_->GetVisibleIconCount(); 1071 int model_visible_size =
1072 model_->GetVisibleIconCountForTab(GetCurrentWebContents());
1002 size_t absolute_model_visible_size = model_visible_size == -1 ? 1073 size_t absolute_model_visible_size = model_visible_size == -1 ?
1003 model_->toolbar_items().size() : model_visible_size; 1074 model_->toolbar_items().size() : model_visible_size;
1004 1075
1005 #if !defined(NDEBUG) 1076 #if !defined(NDEBUG)
Peter Kasting 2014/10/30 22:06:00 Nit: While here: use DCHECK_IS_ON instead of looki
Devlin 2014/10/31 17:44:09 Good idea.
1006 // Good time for some sanity checks: We should never try to display more 1077 // Good time for some sanity checks: We should never try to display more
1007 // icons than we have, and we should always have a view per item in the model. 1078 // icons than we have, and we should always have a view per item in the model.
1008 // (The only exception is if this is in initialization.) 1079 // (The only exception is if this is in initialization.)
1009 if (initialized_) { 1080 if (initialized_ && !suppress_layout_) {
1010 size_t num_extension_actions = 0u; 1081 size_t num_extension_actions = 0u;
1011 for (BrowserActionView* view : browser_action_views_) { 1082 for (BrowserActionView* view : browser_action_views_) {
1012 // No component action should ever have a valid extension id, so we can 1083 // No component action should ever have a valid extension id, so we can
1013 // use this to check the extension amount. 1084 // use this to check the extension amount.
1014 // TODO(devlin): Fix this to just check model size when the model also 1085 // TODO(devlin): Fix this to just check model size when the model also
1015 // includes component actions. 1086 // includes component actions.
1016 if (crx_file::id_util::IdIsValid(view->view_controller()->GetId())) 1087 if (crx_file::id_util::IdIsValid(view->view_controller()->GetId()))
1017 ++num_extension_actions; 1088 ++num_extension_actions;
1018 } 1089 }
1019 DCHECK_LE(absolute_model_visible_size, num_extension_actions); 1090 DCHECK_LE(absolute_model_visible_size, num_extension_actions);
1020 DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions); 1091 DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions);
1021 } 1092 }
1022 #endif 1093 #endif
1023 1094
1024 // The overflow displays any icons not shown by the main bar. 1095 // The overflow displays any icons not shown by the main bar.
1025 return in_overflow_mode() ? 1096 return in_overflow_mode() ?
1026 model_->toolbar_items().size() - absolute_model_visible_size : 1097 model_->toolbar_items().size() - absolute_model_visible_size :
1027 absolute_model_visible_size; 1098 absolute_model_visible_size;
1028 } 1099 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698