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 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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) { |
618 if (is_add && child == this) { | 525 if (is_add && child == this) { |
| 526 // Initial toolbar button creation + packing. |
619 // We do this here instead of in the constructor because AddBrowserAction | 527 // We do this here instead of in the constructor because AddBrowserAction |
620 // calls Layout on the Toolbar, which needs this object to be constructed | 528 // calls Layout on the Toolbar, which needs this object to be constructed |
621 // before its Layout function is called. | 529 // before its Layout function is called. |
622 ExtensionsService* extension_service = profile_->GetExtensionsService(); | 530 for (ExtensionList::iterator iter = model_->begin(); |
623 if (!extension_service) | 531 iter != model_->end(); ++iter) { |
624 return; // The |extension_service| can be NULL in Incognito. | 532 BrowserActionView* view = new BrowserActionView(*iter, this); |
625 for (size_t i = 0; i < extension_service->extensions()->size(); ++i) | 533 browser_action_views_.push_back(view); |
626 AddBrowserAction(extension_service->extensions()->at(i)); | 534 AddChildView(view); |
| 535 } |
627 } | 536 } |
628 } | 537 } |
629 | 538 |
630 void BrowserActionsContainer::Observe(NotificationType type, | 539 void BrowserActionsContainer::Observe(NotificationType type, |
631 const NotificationSource& source, | 540 const NotificationSource& source, |
632 const NotificationDetails& details) { | 541 const NotificationDetails& details) { |
633 switch (type.value) { | 542 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: | 543 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: |
646 // If we aren't the host of the popup, then disregard the notification. | 544 // If we aren't the host of the popup, then disregard the notification. |
647 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) | 545 if (!popup_ || Details<ExtensionHost>(popup_->host()) != details) |
648 return; | 546 return; |
649 | 547 |
650 HidePopup(); | 548 HidePopup(); |
651 break; | 549 break; |
652 | 550 |
653 default: | 551 default: |
654 NOTREACHED() << "Unexpected notification"; | 552 NOTREACHED() << "Unexpected notification"; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
730 } else { | 628 } else { |
731 // A negative |pixels| count indicates caller wants to know the max width | 629 // A negative |pixels| count indicates caller wants to know the max width |
732 // that fits all icons; | 630 // that fits all icons; |
733 icon_count = browser_action_views_.size(); | 631 icon_count = browser_action_views_.size(); |
734 } | 632 } |
735 | 633 |
736 int returning = extras + (icon_count * icon_width); | 634 int returning = extras + (icon_count * icon_width); |
737 return returning; | 635 return returning; |
738 } | 636 } |
739 | 637 |
| 638 void BrowserActionsContainer::BrowserActionAdded(Extension* extension, |
| 639 int index) { |
| 640 #if defined(DEBUG) |
| 641 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 642 DCHECK(browser_action_views_[i]->button()->extension() != extension) << |
| 643 "Asked to add a browser action view for an extension that already " |
| 644 "exists."; |
| 645 } |
| 646 #endif |
| 647 |
| 648 // Before we change anything, determine the number of visible browser actions. |
| 649 size_t visible_actions = 0; |
| 650 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 651 if (browser_action_views_[i]->IsVisible()) |
| 652 ++visible_actions; |
| 653 } |
| 654 |
| 655 // Add the new browser action to the vector and the view hierarchy. |
| 656 BrowserActionView* view = new BrowserActionView(extension, this); |
| 657 browser_action_views_.push_back(view); |
| 658 AddChildView(index, view); |
| 659 |
| 660 // For details on why we do the following see the class comments in the |
| 661 // header. |
| 662 |
| 663 // Determine if we need to increase (we only do that if the container was |
| 664 // showing all icons before the addition of this icon). We use -1 because |
| 665 // we don't want to count the view that we just added. |
| 666 if (visible_actions < browser_action_views_.size() - 1) { |
| 667 // Some icons were hidden, don't increase the size of the container. |
| 668 OnBrowserActionVisibilityChanged(); |
| 669 } else { |
| 670 // Container was at max, increase the size of it by one icon. |
| 671 animation_target_size_ = IconCountToWidth(visible_actions + 1); |
| 672 |
| 673 // We don't want the chevron to appear while we animate. See documentation |
| 674 // in the header for why we do this. |
| 675 suppress_chevron_ = !chevron_->IsVisible(); |
| 676 |
| 677 // Animate! |
| 678 resize_animation_->Reset(); |
| 679 resize_animation_->SetTweenType(SlideAnimation::NONE); |
| 680 resize_animation_->Show(); |
| 681 } |
| 682 } |
| 683 |
| 684 void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { |
| 685 if (popup_ && popup_->host()->extension() == extension) |
| 686 HidePopup(); |
| 687 |
| 688 // Before we change anything, determine the number of visible browser actions. |
| 689 int visible_actions = 0; |
| 690 for (size_t i = 0; i < browser_action_views_.size(); ++i) { |
| 691 if (browser_action_views_[i]->IsVisible()) |
| 692 ++visible_actions; |
| 693 } |
| 694 |
| 695 for (std::vector<BrowserActionView*>::iterator iter = |
| 696 browser_action_views_.begin(); iter != browser_action_views_.end(); |
| 697 ++iter) { |
| 698 if ((*iter)->button()->extension() == extension) { |
| 699 RemoveChildView(*iter); |
| 700 delete *iter; |
| 701 browser_action_views_.erase(iter); |
| 702 |
| 703 // For details on why we do the following see the class comments in the |
| 704 // header. |
| 705 |
| 706 // Calculate the target size we'll animate to (end state). This might be |
| 707 // the same size (if the icon we are removing is in the overflow bucket |
| 708 // and there are other icons there). We don't decrement visible_actions |
| 709 // because we want the container to stay the same size (clamping will take |
| 710 // care of shrinking the container if there aren't enough icons to show). |
| 711 animation_target_size_ = |
| 712 ClampToNearestIconCount(IconCountToWidth(visible_actions)); |
| 713 |
| 714 // Animate! |
| 715 resize_animation_->Reset(); |
| 716 resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); |
| 717 resize_animation_->Show(); |
| 718 return; |
| 719 } |
| 720 } |
| 721 } |
| 722 |
740 int BrowserActionsContainer::WidthOfNonIconArea() const { | 723 int BrowserActionsContainer::WidthOfNonIconArea() const { |
741 int chevron_size = (chevron_->IsVisible()) ? | 724 int chevron_size = (chevron_->IsVisible()) ? |
742 chevron_->GetPreferredSize().width() : 0; | 725 chevron_->GetPreferredSize().width() : 0; |
743 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + | 726 return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + |
744 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; | 727 chevron_size + kChevronRightMargin + kDividerHorizontalMargin; |
745 } | 728 } |
746 | 729 |
747 int BrowserActionsContainer::IconCountToWidth(int icons) const { | 730 int BrowserActionsContainer::IconCountToWidth(int icons) const { |
748 DCHECK(icons >= 0); | 731 DCHECK(icons >= 0); |
749 if (icons == 0) | 732 if (icons == 0) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { | 780 void BrowserActionsContainer::AnimationEnded(const Animation* animation) { |
798 container_size_.set_width(animation_target_size_); | 781 container_size_.set_width(animation_target_size_); |
799 animation_target_size_ = 0; | 782 animation_target_size_ = 0; |
800 resize_amount_ = 0; | 783 resize_amount_ = 0; |
801 OnBrowserActionVisibilityChanged(); | 784 OnBrowserActionVisibilityChanged(); |
802 suppress_chevron_ = false; | 785 suppress_chevron_ = false; |
803 | 786 |
804 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, | 787 profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, |
805 container_size_.width()); | 788 container_size_.width()); |
806 } | 789 } |
OLD | NEW |