OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/views/browser_actions_container.h" | 5 #include "chrome/browser/views/browser_actions_container.h" |
6 | 6 |
7 #include "app/gfx/canvas.h" | 7 #include "app/gfx/canvas.h" |
8 #include "app/resource_bundle.h" | 8 #include "app/resource_bundle.h" |
9 #include "app/slide_animation.h" | 9 #include "app/slide_animation.h" |
10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "chrome/browser/browser.h" | 12 #include "chrome/browser/browser.h" |
13 #include "chrome/browser/browser_theme_provider.h" | 13 #include "chrome/browser/browser_theme_provider.h" |
14 #include "chrome/browser/browser_window.h" | 14 #include "chrome/browser/browser_window.h" |
15 #include "chrome/browser/extensions/extension_browser_event_router.h" | 15 #include "chrome/browser/extensions/extension_browser_event_router.h" |
16 #include "chrome/browser/extensions/extensions_service.h" | 16 #include "chrome/browser/extensions/extensions_service.h" |
17 #include "chrome/browser/extensions/extension_tabs_module.h" | 17 #include "chrome/browser/extensions/extension_tabs_module.h" |
18 #include "chrome/browser/renderer_host/render_widget_host_view.h" | 18 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
19 #include "chrome/browser/profile.h" | 19 #include "chrome/browser/profile.h" |
20 #include "chrome/browser/view_ids.h" | 20 #include "chrome/browser/view_ids.h" |
21 #include "chrome/browser/views/detachable_toolbar_view.h" | 21 #include "chrome/browser/views/detachable_toolbar_view.h" |
22 #include "chrome/browser/views/extensions/browser_action_drag_data.h" | 22 #include "chrome/browser/views/extensions/browser_action_drag_data.h" |
23 #include "chrome/browser/views/extensions/browser_action_overflow_menu_controlle
r.h" | |
24 #include "chrome/browser/views/extensions/extension_popup.h" | 23 #include "chrome/browser/views/extensions/extension_popup.h" |
25 #include "chrome/browser/views/toolbar_view.h" | 24 #include "chrome/browser/views/toolbar_view.h" |
26 #include "chrome/common/notification_source.h" | 25 #include "chrome/common/notification_source.h" |
27 #include "chrome/common/notification_type.h" | 26 #include "chrome/common/notification_type.h" |
28 #include "chrome/common/pref_names.h" | 27 #include "chrome/common/pref_names.h" |
29 #include "grit/app_resources.h" | 28 #include "grit/app_resources.h" |
30 #include "third_party/skia/include/core/SkBitmap.h" | 29 #include "third_party/skia/include/core/SkBitmap.h" |
31 #include "third_party/skia/include/core/SkTypeface.h" | 30 #include "third_party/skia/include/core/SkTypeface.h" |
32 #include "third_party/skia/include/effects/SkGradientShader.h" | 31 #include "third_party/skia/include/effects/SkGradientShader.h" |
33 #include "views/controls/button/menu_button.h" | 32 #include "views/controls/button/menu_button.h" |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 | 293 |
295 BrowserActionsContainer::BrowserActionsContainer( | 294 BrowserActionsContainer::BrowserActionsContainer( |
296 Profile* profile, ToolbarView* toolbar) | 295 Profile* profile, ToolbarView* toolbar) |
297 : profile_(profile), | 296 : profile_(profile), |
298 toolbar_(toolbar), | 297 toolbar_(toolbar), |
299 popup_(NULL), | 298 popup_(NULL), |
300 popup_button_(NULL), | 299 popup_button_(NULL), |
301 model_(NULL), | 300 model_(NULL), |
302 resize_gripper_(NULL), | 301 resize_gripper_(NULL), |
303 chevron_(NULL), | 302 chevron_(NULL), |
| 303 overflow_menu_(NULL), |
304 suppress_chevron_(false), | 304 suppress_chevron_(false), |
305 resize_amount_(0), | 305 resize_amount_(0), |
306 animation_target_size_(0), | 306 animation_target_size_(0), |
307 drop_indicator_position_(-1), | 307 drop_indicator_position_(-1), |
308 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { | 308 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
| 309 ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) { |
309 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); | 310 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
310 | 311 |
311 ExtensionsService* extension_service = profile->GetExtensionsService(); | 312 ExtensionsService* extension_service = profile->GetExtensionsService(); |
312 if (!extension_service) // The |extension_service| can be NULL in Incognito. | 313 if (!extension_service) // The |extension_service| can be NULL in Incognito. |
313 return; | 314 return; |
314 | 315 |
315 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 316 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
316 Source<Profile>(profile_)); | 317 Source<Profile>(profile_)); |
317 | 318 |
318 model_ = extension_service->toolbar_model(); | 319 model_ = extension_service->toolbar_model(); |
(...skipping 21 matching lines...) Expand all Loading... |
340 // except when no width has been saved. So, in that case ask the model | 341 // except when no width has been saved. So, in that case ask the model |
341 // how many icons we'll show and set initial size to that. | 342 // how many icons we'll show and set initial size to that. |
342 predefined_width = IconCountToWidth(model_->size()); | 343 predefined_width = IconCountToWidth(model_->size()); |
343 } | 344 } |
344 container_size_ = gfx::Size(predefined_width, kButtonSize); | 345 container_size_ = gfx::Size(predefined_width, kButtonSize); |
345 } | 346 } |
346 | 347 |
347 BrowserActionsContainer::~BrowserActionsContainer() { | 348 BrowserActionsContainer::~BrowserActionsContainer() { |
348 if (model_) | 349 if (model_) |
349 model_->RemoveObserver(this); | 350 model_->RemoveObserver(this); |
| 351 StopShowFolderDropMenuTimer(); |
350 CloseOverflowMenu(); | 352 CloseOverflowMenu(); |
351 HidePopup(); | 353 HidePopup(); |
352 DeleteBrowserActionViews(); | 354 DeleteBrowserActionViews(); |
353 } | 355 } |
354 | 356 |
355 // Static. | 357 // Static. |
356 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { | 358 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { |
357 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); | 359 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); |
358 } | 360 } |
359 | 361 |
(...skipping 17 matching lines...) Expand all Loading... |
377 return NULL; | 379 return NULL; |
378 } | 380 } |
379 | 381 |
380 void BrowserActionsContainer::RefreshBrowserActionViews() { | 382 void BrowserActionsContainer::RefreshBrowserActionViews() { |
381 for (size_t i = 0; i < browser_action_views_.size(); ++i) | 383 for (size_t i = 0; i < browser_action_views_.size(); ++i) |
382 browser_action_views_[i]->button()->UpdateState(); | 384 browser_action_views_[i]->button()->UpdateState(); |
383 } | 385 } |
384 | 386 |
385 void BrowserActionsContainer::CloseOverflowMenu() { | 387 void BrowserActionsContainer::CloseOverflowMenu() { |
386 // Close the overflow menu if open (and the context menu off of that). | 388 // Close the overflow menu if open (and the context menu off of that). |
387 if (overflow_menu_.get()) | 389 if (overflow_menu_) |
388 overflow_menu_->CancelMenu(); | 390 overflow_menu_->CancelMenu(); |
389 } | 391 } |
390 | 392 |
| 393 void BrowserActionsContainer::StopShowFolderDropMenuTimer() { |
| 394 show_menu_task_factory_.RevokeAll(); |
| 395 } |
| 396 |
| 397 void BrowserActionsContainer::StartShowFolderDropMenuTimer() { |
| 398 int delay = View::GetMenuShowDelay(); |
| 399 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 400 show_menu_task_factory_.NewRunnableMethod( |
| 401 &BrowserActionsContainer::ShowDropFolder), |
| 402 delay); |
| 403 } |
| 404 |
| 405 void BrowserActionsContainer::ShowDropFolder() { |
| 406 DCHECK(!overflow_menu_); |
| 407 overflow_menu_ = new BrowserActionOverflowMenuController( |
| 408 this, chevron_, browser_action_views_, VisibleBrowserActions()); |
| 409 overflow_menu_->set_observer(this); |
| 410 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true); |
| 411 } |
| 412 |
| 413 void BrowserActionsContainer::SetDropIndicator(int x_pos) { |
| 414 if (drop_indicator_position_ != x_pos) { |
| 415 drop_indicator_position_ = x_pos; |
| 416 SchedulePaint(); |
| 417 } |
| 418 } |
| 419 |
391 void BrowserActionsContainer::CreateBrowserActionViews() { | 420 void BrowserActionsContainer::CreateBrowserActionViews() { |
392 DCHECK(browser_action_views_.empty()); | 421 DCHECK(browser_action_views_.empty()); |
393 for (ExtensionList::iterator iter = model_->begin(); | 422 for (ExtensionList::iterator iter = model_->begin(); |
394 iter != model_->end(); ++iter) { | 423 iter != model_->end(); ++iter) { |
395 BrowserActionView* view = new BrowserActionView(*iter, this); | 424 BrowserActionView* view = new BrowserActionView(*iter, this); |
396 browser_action_views_.push_back(view); | 425 browser_action_views_.push_back(view); |
397 AddChildView(view); | 426 AddChildView(view); |
398 } | 427 } |
399 } | 428 } |
400 | 429 |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 return false; | 657 return false; |
629 return drop_data.IsFromProfile(profile_); | 658 return drop_data.IsFromProfile(profile_); |
630 } | 659 } |
631 | 660 |
632 void BrowserActionsContainer::OnDragEntered( | 661 void BrowserActionsContainer::OnDragEntered( |
633 const views::DropTargetEvent& event) { | 662 const views::DropTargetEvent& event) { |
634 } | 663 } |
635 | 664 |
636 int BrowserActionsContainer::OnDragUpdated( | 665 int BrowserActionsContainer::OnDragUpdated( |
637 const views::DropTargetEvent& event) { | 666 const views::DropTargetEvent& event) { |
| 667 // First check if we are above the chevron (overflow) menu. |
| 668 if (GetViewForPoint(event.location()) == chevron_) { |
| 669 SetDropIndicator(-1); |
| 670 |
| 671 if (show_menu_task_factory_.empty() && !overflow_menu_) |
| 672 StartShowFolderDropMenuTimer(); |
| 673 return DragDropTypes::DRAG_MOVE; |
| 674 } else { |
| 675 StopShowFolderDropMenuTimer(); |
| 676 } |
| 677 |
638 // Modifying the x value before clamping affects how far you have to drag to | 678 // Modifying the x value before clamping affects how far you have to drag to |
639 // get the drop indicator to shift to another position. Modifying after | 679 // get the drop indicator to shift to another position. Modifying after |
640 // clamping affects where the drop indicator is drawn. | 680 // clamping affects where the drop indicator is drawn. |
641 | 681 |
642 // We add half a button size so that when you drag a button to the right and | 682 // We add half a button size so that when you drag a button to the right and |
643 // you are half-way dragging across a button the drop indicator moves from the | 683 // you are half-way dragging across a button the drop indicator moves from the |
644 // left of that button to the right of that button. | 684 // left of that button to the right of that button. |
645 int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding); | 685 int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding); |
646 if (chevron_->IsVisible()) | 686 if (chevron_->IsVisible()) |
647 x += chevron_->bounds().width(); | 687 x += chevron_->bounds().width(); |
648 x = ClampToNearestIconCount(x, false); | 688 x = ClampToNearestIconCount(x, false); |
649 | 689 |
650 if (!UILayoutIsRightToLeft() && chevron_->IsVisible()) { | 690 if (!UILayoutIsRightToLeft() && chevron_->IsVisible()) { |
651 // The clamping function includes the chevron width. In LTR locales, the | 691 // The clamping function includes the chevron width. In LTR locales, the |
652 // chevron is on the right and we never want to account for its width. In | 692 // chevron is on the right and we never want to account for its width. In |
653 // RTL it is on the left and we always want to count the width. | 693 // RTL it is on the left and we always want to count the width. |
654 x -= chevron_->width(); | 694 x -= chevron_->width(); |
655 } | 695 } |
656 | 696 |
657 // Clamping gives us a value where the next button will be drawn, but we want | 697 // Clamping gives us a value where the next button will be drawn, but we want |
658 // to subtract the padding (and then some) to make it appear in-between the | 698 // to subtract the padding (and then some) to make it appear in-between the |
659 // buttons. | 699 // buttons. |
660 drop_indicator_position_ = x - kBrowserActionButtonPadding - | 700 SetDropIndicator(x - kBrowserActionButtonPadding - |
661 (UILayoutIsRightToLeft() ? kDropIndicatorOffsetRtl : | 701 (UILayoutIsRightToLeft() ? kDropIndicatorOffsetRtl : |
662 kDropIndicatorOffsetLtr); | 702 kDropIndicatorOffsetLtr)); |
663 | |
664 SchedulePaint(); | |
665 return DragDropTypes::DRAG_MOVE; | 703 return DragDropTypes::DRAG_MOVE; |
666 } | 704 } |
667 | 705 |
668 void BrowserActionsContainer::OnDragExited() { | 706 void BrowserActionsContainer::OnDragExited() { |
| 707 StopShowFolderDropMenuTimer(); |
669 drop_indicator_position_ = -1; | 708 drop_indicator_position_ = -1; |
670 SchedulePaint(); | 709 SchedulePaint(); |
671 } | 710 } |
672 | 711 |
673 int BrowserActionsContainer::OnPerformDrop( | 712 int BrowserActionsContainer::OnPerformDrop( |
674 const views::DropTargetEvent& event) { | 713 const views::DropTargetEvent& event) { |
675 BrowserActionDragData data; | 714 BrowserActionDragData data; |
676 if (!data.Read(event.GetData())) | 715 if (!data.Read(event.GetData())) |
677 return DragDropTypes::DRAG_NONE; | 716 return DragDropTypes::DRAG_NONE; |
678 | 717 |
(...skipping 25 matching lines...) Expand all Loading... |
704 // * Well, it can also point to the end, but not when dragging to the left. :) | 743 // * Well, it can also point to the end, but not when dragging to the left. :) |
705 if (i > data.index()) | 744 if (i > data.index()) |
706 --i; | 745 --i; |
707 | 746 |
708 model_->MoveBrowserAction(dragging, i); | 747 model_->MoveBrowserAction(dragging, i); |
709 | 748 |
710 OnDragExited(); // Perform clean up after dragging. | 749 OnDragExited(); // Perform clean up after dragging. |
711 return DragDropTypes::DRAG_MOVE; | 750 return DragDropTypes::DRAG_MOVE; |
712 } | 751 } |
713 | 752 |
| 753 void BrowserActionsContainer::MoveBrowserAction( |
| 754 const std::string& extension_id, size_t new_index) { |
| 755 ExtensionsService* service = profile_->GetExtensionsService(); |
| 756 Extension* extension = service->GetExtensionById(extension_id, false); |
| 757 model_->MoveBrowserAction(extension, new_index); |
| 758 SchedulePaint(); |
| 759 } |
| 760 |
714 void BrowserActionsContainer::Observe(NotificationType type, | 761 void BrowserActionsContainer::Observe(NotificationType type, |
715 const NotificationSource& source, | 762 const NotificationSource& source, |
716 const NotificationDetails& details) { | 763 const NotificationDetails& details) { |
717 switch (type.value) { | 764 switch (type.value) { |
718 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: | 765 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: |
719 // If we aren't the host of the popup, then disregard the notification. | 766 // If we aren't the host of the popup, then disregard the notification. |
720 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) | 767 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) |
721 return; | 768 return; |
722 | 769 |
723 HidePopup(); | 770 HidePopup(); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 // This is a bit annoying. If you click on the button that generated the | 812 // This is a bit annoying. If you click on the button that generated the |
766 // current popup, then we first get this lost focus message, and then | 813 // current popup, then we first get this lost focus message, and then |
767 // we get the click action. This results in the popup being immediately | 814 // we get the click action. This results in the popup being immediately |
768 // shown again. To workaround this, we put in a delay. | 815 // shown again. To workaround this, we put in a delay. |
769 MessageLoop::current()->PostTask(FROM_HERE, | 816 MessageLoop::current()->PostTask(FROM_HERE, |
770 task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup)); | 817 task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup)); |
771 } | 818 } |
772 | 819 |
773 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { | 820 void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { |
774 if (source == chevron_) { | 821 if (source == chevron_) { |
775 overflow_menu_.reset(new BrowserActionOverflowMenuController( | 822 overflow_menu_ = new BrowserActionOverflowMenuController( |
776 this, chevron_, browser_action_views_, VisibleBrowserActions())); | 823 this, chevron_, browser_action_views_, VisibleBrowserActions()); |
777 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow()); | 824 overflow_menu_->set_observer(this); |
| 825 overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), false); |
778 } | 826 } |
779 } | 827 } |
780 | 828 |
781 void BrowserActionsContainer::WriteDragData( | 829 void BrowserActionsContainer::WriteDragData( |
782 View* sender, int press_x, int press_y, OSExchangeData* data) { | 830 View* sender, int press_x, int press_y, OSExchangeData* data) { |
783 DCHECK(data); | 831 DCHECK(data); |
784 | 832 |
785 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | 833 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
786 if (browser_action_views_[i]->button() == sender) { | 834 if (browser_action_views_[i]->button() == sender) { |
787 BrowserActionDragData drag_data( | 835 BrowserActionDragData drag_data( |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1000 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { | 1048 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { |
1001 container_size_.set_width(animation_target_size_); | 1049 container_size_.set_width(animation_target_size_); |
1002 animation_target_size_ = 0; | 1050 animation_target_size_ = 0; |
1003 resize_amount_ = 0; | 1051 resize_amount_ = 0; |
1004 OnBrowserActionVisibilityChanged(); | 1052 OnBrowserActionVisibilityChanged(); |
1005 suppress_chevron_ = false; | 1053 suppress_chevron_ = false; |
1006 | 1054 |
1007 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, | 1055 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, |
1008 container_size_.width()); | 1056 container_size_.width()); |
1009 } | 1057 } |
| 1058 |
| 1059 void BrowserActionsContainer::NotifyMenuDeleted( |
| 1060 BrowserActionOverflowMenuController* controller) { |
| 1061 DCHECK(controller == overflow_menu_); |
| 1062 overflow_menu_ = NULL; |
| 1063 } |
OLD | NEW |