| 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" |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 | 278 |
| 279 //////////////////////////////////////////////////////////////////////////////// | 279 //////////////////////////////////////////////////////////////////////////////// |
| 280 // BrowserActionsContainer | 280 // BrowserActionsContainer |
| 281 | 281 |
| 282 BrowserActionsContainer::BrowserActionsContainer( | 282 BrowserActionsContainer::BrowserActionsContainer( |
| 283 Profile* profile, ToolbarView* toolbar) | 283 Profile* profile, ToolbarView* toolbar) |
| 284 : profile_(profile), | 284 : profile_(profile), |
| 285 toolbar_(toolbar), | 285 toolbar_(toolbar), |
| 286 popup_(NULL), | 286 popup_(NULL), |
| 287 popup_button_(NULL), | 287 popup_button_(NULL), |
| 288 model_(NULL), |
| 288 resize_gripper_(NULL), | 289 resize_gripper_(NULL), |
| 289 chevron_(NULL), | 290 chevron_(NULL), |
| 290 suppress_chevron_(false), | 291 suppress_chevron_(false), |
| 291 resize_amount_(0), | 292 resize_amount_(0), |
| 292 animation_target_size_(0), | 293 animation_target_size_(0), |
| 293 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { | 294 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { |
| 295 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
| 296 |
| 294 ExtensionsService* extension_service = profile->GetExtensionsService(); | 297 ExtensionsService* extension_service = profile->GetExtensionsService(); |
| 295 if (!extension_service) // The |extension_service| can be NULL in Incognito. | 298 if (!extension_service) // The |extension_service| can be NULL in Incognito. |
| 296 return; | 299 return; |
| 297 | 300 |
| 298 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
| 299 Source<Profile>(profile_)); | |
| 300 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
| 301 Source<Profile>(profile_)); | |
| 302 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, | |
| 303 Source<Profile>(profile_)); | |
| 304 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 301 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 305 Source<Profile>(profile_)); | 302 Source<Profile>(profile_)); |
| 306 | 303 |
| 304 model_ = extension_service->toolbar_model(); |
| 305 model_->AddObserver(this); |
| 306 |
| 307 resize_animation_.reset(new SlideAnimation(this)); | 307 resize_animation_.reset(new SlideAnimation(this)); |
| 308 | |
| 309 resize_gripper_ = new views::ResizeGripper(this); | 308 resize_gripper_ = new views::ResizeGripper(this); |
| 310 resize_gripper_->SetVisible(false); | 309 resize_gripper_->SetVisible(false); |
| 311 AddChildView(resize_gripper_); | 310 AddChildView(resize_gripper_); |
| 312 | 311 |
| 313 // TODO(glen): Come up with a new bitmap for the chevron. | 312 // TODO(glen): Come up with a new bitmap for the chevron. |
| 314 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 313 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 315 SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); | 314 SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); |
| 316 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); | 315 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); |
| 317 chevron_->SetVisible(false); | 316 chevron_->SetVisible(false); |
| 318 chevron_->SetIcon(*chevron_image); | 317 chevron_->SetIcon(*chevron_image); |
| 319 // Chevron contains >> that should point left in LTR locales. | 318 // Chevron contains >> that should point left in LTR locales. |
| 320 chevron_->EnableCanvasFlippingForRTLUI(true); | 319 chevron_->EnableCanvasFlippingForRTLUI(true); |
| 321 AddChildView(chevron_); | 320 AddChildView(chevron_); |
| 322 | 321 |
| 323 int predefined_width = | 322 int predefined_width = |
| 324 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); | 323 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); |
| 325 container_size_ = gfx::Size(predefined_width, kButtonSize); | 324 container_size_ = gfx::Size(predefined_width, kButtonSize); |
| 326 | |
| 327 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); | |
| 328 } | 325 } |
| 329 | 326 |
| 330 BrowserActionsContainer::~BrowserActionsContainer() { | 327 BrowserActionsContainer::~BrowserActionsContainer() { |
| 328 if (model_) |
| 329 model_->RemoveObserver(this); |
| 331 CloseOverflowMenu(); | 330 CloseOverflowMenu(); |
| 332 HidePopup(); | 331 HidePopup(); |
| 333 DeleteBrowserActionViews(); | 332 DeleteBrowserActionViews(); |
| 334 } | 333 } |
| 335 | 334 |
| 336 // Static. | 335 // Static. |
| 337 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { | 336 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { |
| 338 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); | 337 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); |
| 339 } | 338 } |
| 340 | 339 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 356 } | 355 } |
| 357 | 356 |
| 358 return NULL; | 357 return NULL; |
| 359 } | 358 } |
| 360 | 359 |
| 361 void BrowserActionsContainer::RefreshBrowserActionViews() { | 360 void BrowserActionsContainer::RefreshBrowserActionViews() { |
| 362 for (size_t i = 0; i < browser_action_views_.size(); ++i) | 361 for (size_t i = 0; i < browser_action_views_.size(); ++i) |
| 363 browser_action_views_[i]->button()->UpdateState(); | 362 browser_action_views_[i]->button()->UpdateState(); |
| 364 } | 363 } |
| 365 | 364 |
| 366 void BrowserActionsContainer::AddBrowserAction(Extension* extension) { | |
| 367 #if defined(DEBUG) | |
| 368 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | |
| 369 DCHECK(browser_action_views_[i]->button()->extension() != extension) << | |
| 370 "Asked to add a browser action view for an extension that already " | |
| 371 "exists."; | |
| 372 } | |
| 373 #endif | |
| 374 if (!extension->browser_action()) | |
| 375 return; | |
| 376 | |
| 377 // Before we change anything, determine the number of visible browser actions. | |
| 378 size_t visible_actions = VisibleBrowserActions(); | |
| 379 | |
| 380 // Add the new browser action to the vector and the view hierarchy. | |
| 381 BrowserActionView* view = new BrowserActionView(extension, this); | |
| 382 browser_action_views_.push_back(view); | |
| 383 AddChildView(view); | |
| 384 | |
| 385 // For details on why we do the following see the class comments in the | |
| 386 // header. | |
| 387 | |
| 388 // Determine if we need to increase (we only do that if the container was | |
| 389 // showing all icons before the addition of this icon). We use -1 because | |
| 390 // we don't want to count the view that we just added. | |
| 391 if (visible_actions < browser_action_views_.size() - 1) { | |
| 392 // Some icons were hidden, don't increase the size of the container. | |
| 393 OnBrowserActionVisibilityChanged(); | |
| 394 } else { | |
| 395 // Container was at max, increase the size of it by one icon. | |
| 396 animation_target_size_ = IconCountToWidth(visible_actions + 1); | |
| 397 | |
| 398 // We don't want the chevron to appear while we animate. See documentation | |
| 399 // in the header for why we do this. | |
| 400 suppress_chevron_ = !chevron_->IsVisible(); | |
| 401 | |
| 402 // Animate! | |
| 403 resize_animation_->Reset(); | |
| 404 resize_animation_->SetTweenType(SlideAnimation::NONE); | |
| 405 resize_animation_->Show(); | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { | |
| 410 if (!extension->browser_action()) | |
| 411 return; | |
| 412 | |
| 413 if (popup_ && popup_->host()->extension() == extension) { | |
| 414 HidePopup(); | |
| 415 } | |
| 416 | |
| 417 // Before we change anything, determine the number of visible browser actions. | |
| 418 int visible_actions = VisibleBrowserActions(); | |
| 419 | |
| 420 for (std::vector<BrowserActionView*>::iterator iter = | |
| 421 browser_action_views_.begin(); iter != browser_action_views_.end(); | |
| 422 ++iter) { | |
| 423 if ((*iter)->button()->extension() == extension) { | |
| 424 RemoveChildView(*iter); | |
| 425 delete *iter; | |
| 426 browser_action_views_.erase(iter); | |
| 427 | |
| 428 // For details on why we do the following see the class comments in the | |
| 429 // header. | |
| 430 | |
| 431 // Calculate the target size we'll animate to (end state). This might be | |
| 432 // the same size (if the icon we are removing is in the overflow bucket | |
| 433 // and there are other icons there). We don't decrement visible_actions | |
| 434 // because we want the container to stay the same size (clamping will take | |
| 435 // care of shrinking the container if there aren't enough icons to show). | |
| 436 animation_target_size_ = | |
| 437 ClampToNearestIconCount(IconCountToWidth(visible_actions)); | |
| 438 | |
| 439 // Animate! | |
| 440 resize_animation_->Reset(); | |
| 441 resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); | |
| 442 resize_animation_->Show(); | |
| 443 return; | |
| 444 } | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 void BrowserActionsContainer::CloseOverflowMenu() { | 365 void BrowserActionsContainer::CloseOverflowMenu() { |
| 449 // Close the overflow menu if open (and the context menu off of that). | 366 // Close the overflow menu if open (and the context menu off of that). |
| 450 if (overflow_menu_.get()) | 367 if (overflow_menu_.get()) |
| 451 overflow_menu_->CancelMenu(); | 368 overflow_menu_->CancelMenu(); |
| 452 } | 369 } |
| 453 | 370 |
| 454 void BrowserActionsContainer::DeleteBrowserActionViews() { | 371 void BrowserActionsContainer::DeleteBrowserActionViews() { |
| 455 if (!browser_action_views_.empty()) { | 372 if (!browser_action_views_.empty()) { |
| 456 for (size_t i = 0; i < browser_action_views_.size(); ++i) | 373 for (size_t i = 0; i < browser_action_views_.size(); ++i) |
| 457 RemoveChildView(browser_action_views_[i]); | 374 RemoveChildView(browser_action_views_[i]); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 DetachableToolbarView::PaintVerticalDivider( | 547 DetachableToolbarView::PaintVerticalDivider( |
| 631 canvas, x, height(), kDividerVerticalPadding, | 548 canvas, x, height(), kDividerVerticalPadding, |
| 632 DetachableToolbarView::kEdgeDividerColor, | 549 DetachableToolbarView::kEdgeDividerColor, |
| 633 DetachableToolbarView::kMiddleDividerColor, | 550 DetachableToolbarView::kMiddleDividerColor, |
| 634 GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); | 551 GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); |
| 635 } | 552 } |
| 636 | 553 |
| 637 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, | 554 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, |
| 638 views::View* parent, | 555 views::View* parent, |
| 639 views::View* child) { | 556 views::View* child) { |
| 557 // No extensions (e.g., incognito). |
| 558 if (!model_) |
| 559 return; |
| 560 |
| 640 if (is_add && child == this) { | 561 if (is_add && child == this) { |
| 562 // Initial toolbar button creation and placement in the widget hierarchy. |
| 641 // We do this here instead of in the constructor because AddBrowserAction | 563 // We do this here instead of in the constructor because AddBrowserAction |
| 642 // calls Layout on the Toolbar, which needs this object to be constructed | 564 // calls Layout on the Toolbar, which needs this object to be constructed |
| 643 // before its Layout function is called. | 565 // before its Layout function is called. |
| 644 ExtensionsService* extension_service = profile_->GetExtensionsService(); | 566 for (ExtensionList::iterator iter = model_->begin(); |
| 645 if (!extension_service) | 567 iter != model_->end(); ++iter) { |
| 646 return; // The |extension_service| can be NULL in Incognito. | 568 BrowserActionView* view = new BrowserActionView(*iter, this); |
| 647 for (size_t i = 0; i < extension_service->extensions()->size(); ++i) | 569 browser_action_views_.push_back(view); |
| 648 AddBrowserAction(extension_service->extensions()->at(i)); | 570 AddChildView(view); |
| 571 } |
| 649 } | 572 } |
| 650 } | 573 } |
| 651 | 574 |
| 652 void BrowserActionsContainer::Observe(NotificationType type, | 575 void BrowserActionsContainer::Observe(NotificationType type, |
| 653 const NotificationSource& source, | 576 const NotificationSource& source, |
| 654 const NotificationDetails& details) { | 577 const NotificationDetails& details) { |
| 655 switch (type.value) { | 578 switch (type.value) { |
| 656 case NotificationType::EXTENSION_LOADED: | |
| 657 CloseOverflowMenu(); | |
| 658 AddBrowserAction(Details<Extension>(details).ptr()); | |
| 659 OnBrowserActionVisibilityChanged(); | |
| 660 break; | |
| 661 | |
| 662 case NotificationType::EXTENSION_UNLOADED: | |
| 663 case NotificationType::EXTENSION_UNLOADED_DISABLED: | |
| 664 CloseOverflowMenu(); | |
| 665 RemoveBrowserAction(Details<Extension>(details).ptr()); | |
| 666 OnBrowserActionVisibilityChanged(); | |
| 667 break; | |
| 668 | |
| 669 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: | 579 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: |
| 670 // If we aren't the host of the popup, then disregard the notification. | 580 // If we aren't the host of the popup, then disregard the notification. |
| 671 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) | 581 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) |
| 672 return; | 582 return; |
| 673 | 583 |
| 674 HidePopup(); | 584 HidePopup(); |
| 675 break; | 585 break; |
| 676 | 586 |
| 677 default: | 587 default: |
| 678 NOTREACHED() << "Unexpected notification"; | 588 NOTREACHED() << "Unexpected notification"; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 } else { | 668 } else { |
| 759 // A negative |pixels| count indicates caller wants to know the max width | 669 // A negative |pixels| count indicates caller wants to know the max width |
| 760 // that fits all icons; | 670 // that fits all icons; |
| 761 icon_count = browser_action_views_.size(); | 671 icon_count = browser_action_views_.size(); |
| 762 } | 672 } |
| 763 | 673 |
| 764 int returning = extras + (icon_count * icon_width); | 674 int returning = extras + (icon_count * icon_width); |
| 765 return returning; | 675 return returning; |
| 766 } | 676 } |
| 767 | 677 |
| 678 void BrowserActionsContainer::BrowserActionAdded(Extension* extension, |
| 679 int index) { |
| 680 #if defined(DEBUG) |
| 681 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 682 DCHECK(browser_action_views_[i]->button()->extension() != extension) << |
| 683 "Asked to add a browser action view for an extension that already " |
| 684 "exists."; |
| 685 } |
| 686 #endif |
| 687 |
| 688 CloseOverflowMenu(); |
| 689 |
| 690 // Before we change anything, determine the number of visible browser actions. |
| 691 size_t visible_actions = VisibleBrowserActions(); |
| 692 |
| 693 // Add the new browser action to the vector and the view hierarchy. |
| 694 BrowserActionView* view = new BrowserActionView(extension, this); |
| 695 browser_action_views_.push_back(view); |
| 696 AddChildView(index, view); |
| 697 |
| 698 // For details on why we do the following see the class comments in the |
| 699 // header. |
| 700 |
| 701 // Determine if we need to increase (we only do that if the container was |
| 702 // showing all icons before the addition of this icon). We use -1 because |
| 703 // we don't want to count the view that we just added. |
| 704 if (visible_actions < browser_action_views_.size() - 1) { |
| 705 // Some icons were hidden, don't increase the size of the container. |
| 706 OnBrowserActionVisibilityChanged(); |
| 707 } else { |
| 708 // Container was at max, increase the size of it by one icon. |
| 709 animation_target_size_ = IconCountToWidth(visible_actions + 1); |
| 710 |
| 711 // We don't want the chevron to appear while we animate. See documentation |
| 712 // in the header for why we do this. |
| 713 suppress_chevron_ = !chevron_->IsVisible(); |
| 714 |
| 715 // Animate! |
| 716 resize_animation_->Reset(); |
| 717 resize_animation_->SetTweenType(SlideAnimation::NONE); |
| 718 resize_animation_->Show(); |
| 719 } |
| 720 } |
| 721 |
| 722 void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { |
| 723 CloseOverflowMenu(); |
| 724 |
| 725 if (popup_ && popup_->host()->extension() == extension) |
| 726 HidePopup(); |
| 727 |
| 728 // Before we change anything, determine the number of visible browser actions. |
| 729 size_t visible_actions = VisibleBrowserActions(); |
| 730 |
| 731 for (std::vector<BrowserActionView*>::iterator iter = |
| 732 browser_action_views_.begin(); iter != browser_action_views_.end(); |
| 733 ++iter) { |
| 734 if ((*iter)->button()->extension() == extension) { |
| 735 RemoveChildView(*iter); |
| 736 delete *iter; |
| 737 browser_action_views_.erase(iter); |
| 738 |
| 739 // For details on why we do the following see the class comments in the |
| 740 // header. |
| 741 |
| 742 // Calculate the target size we'll animate to (end state). This might be |
| 743 // the same size (if the icon we are removing is in the overflow bucket |
| 744 // and there are other icons there). We don't decrement visible_actions |
| 745 // because we want the container to stay the same size (clamping will take |
| 746 // care of shrinking the container if there aren't enough icons to show). |
| 747 animation_target_size_ = |
| 748 ClampToNearestIconCount(IconCountToWidth(visible_actions)); |
| 749 |
| 750 // Animate! |
| 751 resize_animation_->Reset(); |
| 752 resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); |
| 753 resize_animation_->Show(); |
| 754 return; |
| 755 } |
| 756 } |
| 757 } |
| 758 |
| 768 int BrowserActionsContainer::WidthOfNonIconArea() const { | 759 int BrowserActionsContainer::WidthOfNonIconArea() const { |
| 769 int chevron_size = (chevron_->IsVisible()) ? | 760 int chevron_size = (chevron_->IsVisible()) ? |
| 770 chevron_->GetPreferredSize().width() : 0; | 761 chevron_->GetPreferredSize().width() : 0; |
| 771 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + | 762 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + |
| 772 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; | 763 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; |
| 773 } | 764 } |
| 774 | 765 |
| 775 int BrowserActionsContainer::IconCountToWidth(int icons) const { | 766 int BrowserActionsContainer::IconCountToWidth(int icons) const { |
| 776 DCHECK(icons >= 0); | 767 DCHECK(icons >= 0); |
| 777 if (icons == 0) | 768 if (icons == 0) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { | 826 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { |
| 836 container_size_.set_width(animation_target_size_); | 827 container_size_.set_width(animation_target_size_); |
| 837 animation_target_size_ = 0; | 828 animation_target_size_ = 0; |
| 838 resize_amount_ = 0; | 829 resize_amount_ = 0; |
| 839 OnBrowserActionVisibilityChanged(); | 830 OnBrowserActionVisibilityChanged(); |
| 840 suppress_chevron_ = false; | 831 suppress_chevron_ = false; |
| 841 | 832 |
| 842 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, | 833 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, |
| 843 container_size_.width()); | 834 container_size_.width()); |
| 844 } | 835 } |
| OLD | NEW |