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 |