| 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 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 | 261 |
| 262 //////////////////////////////////////////////////////////////////////////////// | 262 //////////////////////////////////////////////////////////////////////////////// |
| 263 // BrowserActionsContainer | 263 // BrowserActionsContainer |
| 264 | 264 |
| 265 BrowserActionsContainer::BrowserActionsContainer( | 265 BrowserActionsContainer::BrowserActionsContainer( |
| 266 Profile* profile, ToolbarView* toolbar) | 266 Profile* profile, ToolbarView* toolbar) |
| 267 : profile_(profile), | 267 : profile_(profile), |
| 268 toolbar_(toolbar), | 268 toolbar_(toolbar), |
| 269 popup_(NULL), | 269 popup_(NULL), |
| 270 popup_button_(NULL), | 270 popup_button_(NULL), |
| 271 model_(NULL), |
| 271 resize_gripper_(NULL), | 272 resize_gripper_(NULL), |
| 272 chevron_(NULL), | 273 chevron_(NULL), |
| 273 suppress_chevron_(false), | 274 suppress_chevron_(false), |
| 274 resize_amount_(0), | 275 resize_amount_(0), |
| 275 animation_target_size_(0), | 276 animation_target_size_(0), |
| 276 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { | 277 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { |
| 278 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
| 279 |
| 277 ExtensionsService* extension_service = profile->GetExtensionsService(); | 280 ExtensionsService* extension_service = profile->GetExtensionsService(); |
| 278 if (!extension_service) // The |extension_service| can be NULL in Incognito. | 281 if (!extension_service) // The |extension_service| can be NULL in Incognito. |
| 279 return; | 282 return; |
| 280 | 283 |
| 281 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
| 282 Source<Profile>(profile_)); | |
| 283 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
| 284 Source<Profile>(profile_)); | |
| 285 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, | |
| 286 Source<Profile>(profile_)); | |
| 287 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 284 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 288 Source<Profile>(profile_)); | 285 Source<Profile>(profile_)); |
| 289 | 286 |
| 287 model_ = extension_service->toolbar_model(); |
| 288 model_->AddObserver(this); |
| 289 |
| 290 resize_animation_.reset(new SlideAnimation(this)); | 290 resize_animation_.reset(new SlideAnimation(this)); |
| 291 | |
| 292 resize_gripper_ = new views::ResizeGripper(this); | 291 resize_gripper_ = new views::ResizeGripper(this); |
| 293 resize_gripper_->SetVisible(false); | 292 resize_gripper_->SetVisible(false); |
| 294 AddChildView(resize_gripper_); | 293 AddChildView(resize_gripper_); |
| 295 | 294 |
| 296 // TODO(glen): Come up with a new bitmap for the chevron. | 295 // TODO(glen): Come up with a new bitmap for the chevron. |
| 297 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 296 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 298 SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); | 297 SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); |
| 299 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); | 298 chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); |
| 300 chevron_->SetVisible(false); | 299 chevron_->SetVisible(false); |
| 301 chevron_->SetIcon(*chevron_image); | 300 chevron_->SetIcon(*chevron_image); |
| 302 // Chevron contains >> that should point left in LTR locales. | 301 // Chevron contains >> that should point left in LTR locales. |
| 303 chevron_->EnableCanvasFlippingForRTLUI(true); | 302 chevron_->EnableCanvasFlippingForRTLUI(true); |
| 304 AddChildView(chevron_); | 303 AddChildView(chevron_); |
| 305 | 304 |
| 306 int predefined_width = | 305 int predefined_width = |
| 307 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); | 306 profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); |
| 308 container_size_ = gfx::Size(predefined_width, kButtonSize); | 307 container_size_ = gfx::Size(predefined_width, kButtonSize); |
| 309 | |
| 310 SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); | |
| 311 } | 308 } |
| 312 | 309 |
| 313 BrowserActionsContainer::~BrowserActionsContainer() { | 310 BrowserActionsContainer::~BrowserActionsContainer() { |
| 314 HidePopup(); | 311 HidePopup(); |
| 315 DeleteBrowserActionViews(); | 312 DeleteBrowserActionViews(); |
| 316 } | 313 } |
| 317 | 314 |
| 318 // Static. | 315 // Static. |
| 319 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { | 316 void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { |
| 320 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); | 317 prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 338 } | 335 } |
| 339 | 336 |
| 340 return NULL; | 337 return NULL; |
| 341 } | 338 } |
| 342 | 339 |
| 343 void BrowserActionsContainer::RefreshBrowserActionViews() { | 340 void BrowserActionsContainer::RefreshBrowserActionViews() { |
| 344 for (size_t i = 0; i < browser_action_views_.size(); ++i) | 341 for (size_t i = 0; i < browser_action_views_.size(); ++i) |
| 345 browser_action_views_[i]->button()->UpdateState(); | 342 browser_action_views_[i]->button()->UpdateState(); |
| 346 } | 343 } |
| 347 | 344 |
| 348 void BrowserActionsContainer::AddBrowserAction(Extension* extension) { | |
| 349 #if defined(DEBUG) | |
| 350 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | |
| 351 DCHECK(browser_action_views_[i]->button()->extension() != extension) << | |
| 352 "Asked to add a browser action view for an extension that already " | |
| 353 "exists."; | |
| 354 } | |
| 355 #endif | |
| 356 if (!extension->browser_action()) | |
| 357 return; | |
| 358 | |
| 359 // Before we change anything, determine the number of visible browser actions. | |
| 360 size_t visible_actions = 0; | |
| 361 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | |
| 362 if (browser_action_views_[i]->IsVisible()) | |
| 363 ++visible_actions; | |
| 364 } | |
| 365 | |
| 366 // Add the new browser action to the vector and the view hierarchy. | |
| 367 BrowserActionView* view = new BrowserActionView(extension, this); | |
| 368 browser_action_views_.push_back(view); | |
| 369 AddChildView(view); | |
| 370 | |
| 371 // For details on why we do the following see the class comments in the | |
| 372 // header. | |
| 373 | |
| 374 // Determine if we need to increase (we only do that if the container was | |
| 375 // showing all icons before the addition of this icon). We use -1 because | |
| 376 // we don't want to count the view that we just added. | |
| 377 if (visible_actions < browser_action_views_.size() - 1) { | |
| 378 // Some icons were hidden, don't increase the size of the container. | |
| 379 OnBrowserActionVisibilityChanged(); | |
| 380 } else { | |
| 381 // Container was at max, increase the size of it by one icon. | |
| 382 animation_target_size_ = IconCountToWidth(visible_actions + 1); | |
| 383 | |
| 384 // We don't want the chevron to appear while we animate. See documentation | |
| 385 // in the header for why we do this. | |
| 386 suppress_chevron_ = !chevron_->IsVisible(); | |
| 387 | |
| 388 // Animate! | |
| 389 resize_animation_->Reset(); | |
| 390 resize_animation_->SetTweenType(SlideAnimation::NONE); | |
| 391 resize_animation_->Show(); | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { | |
| 396 if (!extension->browser_action()) | |
| 397 return; | |
| 398 | |
| 399 if (popup_ && popup_->host()->extension() == extension) { | |
| 400 HidePopup(); | |
| 401 } | |
| 402 | |
| 403 // Before we change anything, determine the number of visible browser actions. | |
| 404 int visible_actions = 0; | |
| 405 for (size_t i = 0; i < browser_action_views_.size(); ++i) { | |
| 406 if (browser_action_views_[i]->IsVisible()) | |
| 407 ++visible_actions; | |
| 408 } | |
| 409 | |
| 410 for (std::vector<BrowserActionView*>::iterator iter = | |
| 411 browser_action_views_.begin(); iter != browser_action_views_.end(); | |
| 412 ++iter) { | |
| 413 if ((*iter)->button()->extension() == extension) { | |
| 414 RemoveChildView(*iter); | |
| 415 delete *iter; | |
| 416 browser_action_views_.erase(iter); | |
| 417 | |
| 418 // For details on why we do the following see the class comments in the | |
| 419 // header. | |
| 420 | |
| 421 // Calculate the target size we'll animate to (end state). This might be | |
| 422 // the same size (if the icon we are removing is in the overflow bucket | |
| 423 // and there are other icons there). We don't decrement visible_actions | |
| 424 // because we want the container to stay the same size (clamping will take | |
| 425 // care of shrinking the container if there aren't enough icons to show). | |
| 426 animation_target_size_ = | |
| 427 ClampToNearestIconCount(IconCountToWidth(visible_actions)); | |
| 428 | |
| 429 // Animate! | |
| 430 resize_animation_->Reset(); | |
| 431 resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); | |
| 432 resize_animation_->Show(); | |
| 433 return; | |
| 434 } | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 void BrowserActionsContainer::DeleteBrowserActionViews() { | 345 void BrowserActionsContainer::DeleteBrowserActionViews() { |
| 439 if (!browser_action_views_.empty()) { | 346 if (!browser_action_views_.empty()) { |
| 440 for (size_t i = 0; i < browser_action_views_.size(); ++i) | 347 for (size_t i = 0; i < browser_action_views_.size(); ++i) |
| 441 RemoveChildView(browser_action_views_[i]); | 348 RemoveChildView(browser_action_views_[i]); |
| 442 STLDeleteContainerPointers(browser_action_views_.begin(), | 349 STLDeleteContainerPointers(browser_action_views_.begin(), |
| 443 browser_action_views_.end()); | 350 browser_action_views_.end()); |
| 444 browser_action_views_.clear(); | 351 browser_action_views_.clear(); |
| 445 } | 352 } |
| 446 } | 353 } |
| 447 | 354 |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 canvas, | 515 canvas, |
| 609 width() - kDividerHorizontalMargin, height(), kDividerVerticalPadding, | 516 width() - kDividerHorizontalMargin, height(), kDividerVerticalPadding, |
| 610 DetachableToolbarView::kEdgeDividerColor, | 517 DetachableToolbarView::kEdgeDividerColor, |
| 611 DetachableToolbarView::kMiddleDividerColor, | 518 DetachableToolbarView::kMiddleDividerColor, |
| 612 GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); | 519 GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); |
| 613 } | 520 } |
| 614 | 521 |
| 615 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, | 522 void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, |
| 616 views::View* parent, | 523 views::View* parent, |
| 617 views::View* child) { | 524 views::View* child) { |
| 525 // No extensions (e.g., incognito). |
| 526 if (!model_) |
| 527 return; |
| 528 |
| 618 if (is_add && child == this) { | 529 if (is_add && child == this) { |
| 530 // Initial toolbar button creation + packing. |
| 619 // We do this here instead of in the constructor because AddBrowserAction | 531 // We do this here instead of in the constructor because AddBrowserAction |
| 620 // calls Layout on the Toolbar, which needs this object to be constructed | 532 // calls Layout on the Toolbar, which needs this object to be constructed |
| 621 // before its Layout function is called. | 533 // before its Layout function is called. |
| 622 ExtensionsService* extension_service = profile_->GetExtensionsService(); | 534 for (ExtensionList::iterator iter = model_->begin(); |
| 623 if (!extension_service) | 535 iter != model_->end(); ++iter) { |
| 624 return; // The |extension_service| can be NULL in Incognito. | 536 BrowserActionView* view = new BrowserActionView(*iter, this); |
| 625 for (size_t i = 0; i < extension_service->extensions()->size(); ++i) | 537 browser_action_views_.push_back(view); |
| 626 AddBrowserAction(extension_service->extensions()->at(i)); | 538 AddChildView(view); |
| 539 } |
| 627 } | 540 } |
| 628 } | 541 } |
| 629 | 542 |
| 630 void BrowserActionsContainer::Observe(NotificationType type, | 543 void BrowserActionsContainer::Observe(NotificationType type, |
| 631 const NotificationSource& source, | 544 const NotificationSource& source, |
| 632 const NotificationDetails& details) { | 545 const NotificationDetails& details) { |
| 633 switch (type.value) { | 546 switch (type.value) { |
| 634 case NotificationType::EXTENSION_LOADED: | |
| 635 AddBrowserAction(Details<Extension>(details).ptr()); | |
| 636 OnBrowserActionVisibilityChanged(); | |
| 637 break; | |
| 638 | |
| 639 case NotificationType::EXTENSION_UNLOADED: | |
| 640 case NotificationType::EXTENSION_UNLOADED_DISABLED: | |
| 641 RemoveBrowserAction(Details<Extension>(details).ptr()); | |
| 642 OnBrowserActionVisibilityChanged(); | |
| 643 break; | |
| 644 | |
| 645 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: | 547 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: |
| 646 // If we aren't the host of the popup, then disregard the notification. | 548 // If we aren't the host of the popup, then disregard the notification. |
| 647 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) | 549 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) |
| 648 return; | 550 return; |
| 649 | 551 |
| 650 HidePopup(); | 552 HidePopup(); |
| 651 break; | 553 break; |
| 652 | 554 |
| 653 default: | 555 default: |
| 654 NOTREACHED() << "Unexpected notification"; | 556 NOTREACHED() << "Unexpected notification"; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 } else { | 632 } else { |
| 731 // A negative |pixels| count indicates caller wants to know the max width | 633 // A negative |pixels| count indicates caller wants to know the max width |
| 732 // that fits all icons; | 634 // that fits all icons; |
| 733 icon_count = browser_action_views_.size(); | 635 icon_count = browser_action_views_.size(); |
| 734 } | 636 } |
| 735 | 637 |
| 736 int returning = extras + (icon_count * icon_width); | 638 int returning = extras + (icon_count * icon_width); |
| 737 return returning; | 639 return returning; |
| 738 } | 640 } |
| 739 | 641 |
| 642 void BrowserActionsContainer::BrowserActionAdded(Extension* extension, |
| 643 int index) { |
| 644 #if defined(DEBUG) |
| 645 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 646 DCHECK(browser_action_views_[i]->button()->extension() != extension) << |
| 647 "Asked to add a browser action view for an extension that already " |
| 648 "exists."; |
| 649 } |
| 650 #endif |
| 651 |
| 652 // Before we change anything, determine the number of visible browser actions. |
| 653 size_t visible_actions = 0; |
| 654 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 655 if (browser_action_views_[i]->IsVisible()) |
| 656 ++visible_actions; |
| 657 } |
| 658 |
| 659 // Add the new browser action to the vector and the view hierarchy. |
| 660 BrowserActionView* view = new BrowserActionView(extension, this); |
| 661 browser_action_views_.push_back(view); |
| 662 AddChildView(index, view); |
| 663 |
| 664 // For details on why we do the following see the class comments in the |
| 665 // header. |
| 666 |
| 667 // Determine if we need to increase (we only do that if the container was |
| 668 // showing all icons before the addition of this icon). We use -1 because |
| 669 // we don't want to count the view that we just added. |
| 670 if (visible_actions < browser_action_views_.size() - 1) { |
| 671 // Some icons were hidden, don't increase the size of the container. |
| 672 OnBrowserActionVisibilityChanged(); |
| 673 } else { |
| 674 // Container was at max, increase the size of it by one icon. |
| 675 animation_target_size_ = IconCountToWidth(visible_actions + 1); |
| 676 |
| 677 // We don't want the chevron to appear while we animate. See documentation |
| 678 // in the header for why we do this. |
| 679 suppress_chevron_ = !chevron_->IsVisible(); |
| 680 |
| 681 // Animate! |
| 682 resize_animation_->Reset(); |
| 683 resize_animation_->SetTweenType(SlideAnimation::NONE); |
| 684 resize_animation_->Show(); |
| 685 } |
| 686 } |
| 687 |
| 688 void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { |
| 689 if (popup_ && popup_->host()->extension() == extension) |
| 690 HidePopup(); |
| 691 |
| 692 // Before we change anything, determine the number of visible browser actions. |
| 693 int visible_actions = 0; |
| 694 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 695 if (browser_action_views_[i]->IsVisible()) |
| 696 ++visible_actions; |
| 697 } |
| 698 |
| 699 for (std::vector<BrowserActionView*>::iterator iter = |
| 700 browser_action_views_.begin(); iter != browser_action_views_.end(); |
| 701 ++iter) { |
| 702 if ((*iter)->button()->extension() == extension) { |
| 703 RemoveChildView(*iter); |
| 704 delete *iter; |
| 705 browser_action_views_.erase(iter); |
| 706 |
| 707 // For details on why we do the following see the class comments in the |
| 708 // header. |
| 709 |
| 710 // Calculate the target size we'll animate to (end state). This might be |
| 711 // the same size (if the icon we are removing is in the overflow bucket |
| 712 // and there are other icons there). We don't decrement visible_actions |
| 713 // because we want the container to stay the same size (clamping will take |
| 714 // care of shrinking the container if there aren't enough icons to show). |
| 715 animation_target_size_ = |
| 716 ClampToNearestIconCount(IconCountToWidth(visible_actions)); |
| 717 |
| 718 // Animate! |
| 719 resize_animation_->Reset(); |
| 720 resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); |
| 721 resize_animation_->Show(); |
| 722 return; |
| 723 } |
| 724 } |
| 725 } |
| 726 |
| 740 int BrowserActionsContainer::WidthOfNonIconArea() const { | 727 int BrowserActionsContainer::WidthOfNonIconArea() const { |
| 741 int chevron_size = (chevron_->IsVisible()) ? | 728 int chevron_size = (chevron_->IsVisible()) ? |
| 742 chevron_->GetPreferredSize().width() : 0; | 729 chevron_->GetPreferredSize().width() : 0; |
| 743 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + | 730 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + |
| 744 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; | 731 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; |
| 745 } | 732 } |
| 746 | 733 |
| 747 int BrowserActionsContainer::IconCountToWidth(int icons) const { | 734 int BrowserActionsContainer::IconCountToWidth(int icons) const { |
| 748 DCHECK(icons >= 0); | 735 DCHECK(icons >= 0); |
| 749 if (icons == 0) | 736 if (icons == 0) |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { | 784 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { |
| 798 container_size_.set_width(animation_target_size_); | 785 container_size_.set_width(animation_target_size_); |
| 799 animation_target_size_ = 0; | 786 animation_target_size_ = 0; |
| 800 resize_amount_ = 0; | 787 resize_amount_ = 0; |
| 801 OnBrowserActionVisibilityChanged(); | 788 OnBrowserActionVisibilityChanged(); |
| 802 suppress_chevron_ = false; | 789 suppress_chevron_ = false; |
| 803 | 790 |
| 804 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, | 791 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, |
| 805 container_size_.width()); | 792 container_size_.width()); |
| 806 } | 793 } |
| OLD | NEW |