OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #import "browser_actions_controller.h" | 5 #import "browser_actions_controller.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/sys_string_conversions.h" | 10 #include "base/sys_string_conversions.h" |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 - (void)containerDragStart:(NSNotification*)notification; | 114 - (void)containerDragStart:(NSNotification*)notification; |
115 | 115 |
116 // Sends a notification for the toolbar to reposition surrounding UI elements. | 116 // Sends a notification for the toolbar to reposition surrounding UI elements. |
117 - (void)containerDragging:(NSNotification*)notification; | 117 - (void)containerDragging:(NSNotification*)notification; |
118 | 118 |
119 // Determines which buttons need to be hidden based on the new size, hides them | 119 // Determines which buttons need to be hidden based on the new size, hides them |
120 // and updates the chevron overflow menu. Also fires a notification to let the | 120 // and updates the chevron overflow menu. Also fires a notification to let the |
121 // toolbar know that the drag has finished. | 121 // toolbar know that the drag has finished. |
122 - (void)containerDragFinished:(NSNotification*)notification; | 122 - (void)containerDragFinished:(NSNotification*)notification; |
123 | 123 |
124 // Updates the image associated with the button should it be within the chevron | |
125 // menu. | |
126 - (void)actionButtonUpdated:(NSNotification*)notification; | |
127 | |
128 // Adjusts the position of the surrounding action buttons depending on where the | 124 // Adjusts the position of the surrounding action buttons depending on where the |
129 // button is within the container. | 125 // button is within the container. |
130 - (void)actionButtonDragging:(NSNotification*)notification; | 126 - (void)actionButtonDragging:(NSNotification*)notification; |
131 | 127 |
132 // Updates the position of the Browser Actions within the container. This fires | 128 // Updates the position of the Browser Actions within the container. This fires |
133 // when _any_ Browser Action button is done dragging to keep all open windows in | 129 // when _any_ Browser Action button is done dragging to keep all open windows in |
134 // sync visually. | 130 // sync visually. |
135 - (void)actionButtonDragFinished:(NSNotification*)notification; | 131 - (void)actionButtonDragFinished:(NSNotification*)notification; |
136 | 132 |
137 // Moves the given button both visually and within the toolbar model to the | 133 // Moves the given button both visually and within the toolbar model to the |
(...skipping 22 matching lines...) Expand all Loading... |
160 - (void)updateChevronPositionInFrame:(NSRect)frame; | 156 - (void)updateChevronPositionInFrame:(NSRect)frame; |
161 | 157 |
162 // Shows or hides the chevron, animating as specified by |animate|. | 158 // Shows or hides the chevron, animating as specified by |animate|. |
163 - (void)setChevronHidden:(BOOL)hidden | 159 - (void)setChevronHidden:(BOOL)hidden |
164 inFrame:(NSRect)frame | 160 inFrame:(NSRect)frame |
165 animate:(BOOL)animate; | 161 animate:(BOOL)animate; |
166 | 162 |
167 // Handles when a menu item within the chevron overflow menu is selected. | 163 // Handles when a menu item within the chevron overflow menu is selected. |
168 - (void)chevronItemSelected:(id)menuItem; | 164 - (void)chevronItemSelected:(id)menuItem; |
169 | 165 |
170 // Clears and then populates the overflow menu based on the contents of | |
171 // |hiddenButtons_|. | |
172 - (void)updateOverflowMenu; | |
173 | |
174 // Updates the container's grippy cursor based on the number of hidden buttons. | 166 // Updates the container's grippy cursor based on the number of hidden buttons. |
175 - (void)updateGrippyCursors; | 167 - (void)updateGrippyCursors; |
176 | 168 |
177 // Returns the ID of the currently selected tab or -1 if none exists. | 169 // Returns the ID of the currently selected tab or -1 if none exists. |
178 - (int)currentTabId; | 170 - (int)currentTabId; |
179 @end | 171 @end |
180 | 172 |
181 // A helper class to proxy extension notifications to the view controller's | 173 // A helper class to proxy extension notifications to the view controller's |
182 // appropriate methods. | 174 // appropriate methods. |
183 class ExtensionServiceObserverBridge : public content::NotificationObserver, | 175 class ExtensionServiceObserverBridge : public content::NotificationObserver, |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 return YES; | 408 return YES; |
417 } | 409 } |
418 | 410 |
419 + (void)registerUserPrefs:(PrefService*)prefs { | 411 + (void)registerUserPrefs:(PrefService*)prefs { |
420 prefs->RegisterDoublePref(prefs::kBrowserActionContainerWidth, | 412 prefs->RegisterDoublePref(prefs::kBrowserActionContainerWidth, |
421 0, | 413 0, |
422 PrefService::UNSYNCABLE_PREF); | 414 PrefService::UNSYNCABLE_PREF); |
423 } | 415 } |
424 | 416 |
425 #pragma mark - | 417 #pragma mark - |
| 418 #pragma mark NSMenuDelegate |
| 419 |
| 420 - (void)menuNeedsUpdate:(NSMenu*)menu { |
| 421 [menu removeAllItems]; |
| 422 |
| 423 // See menu_button.h for documentation on why this is needed. |
| 424 [menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; |
| 425 |
| 426 for (BrowserActionButton* button in hiddenButtons_.get()) { |
| 427 NSString* name = base::SysUTF8ToNSString([button extension]->name()); |
| 428 NSMenuItem* item = |
| 429 [menu addItemWithTitle:name |
| 430 action:@selector(chevronItemSelected:) |
| 431 keyEquivalent:@""]; |
| 432 [item setRepresentedObject:button]; |
| 433 [item setImage:[button compositedImage]]; |
| 434 [item setTarget:self]; |
| 435 [item setEnabled:[button isEnabled]]; |
| 436 } |
| 437 } |
| 438 |
| 439 #pragma mark - |
426 #pragma mark Private Methods | 440 #pragma mark Private Methods |
427 | 441 |
428 - (void)createButtons { | 442 - (void)createButtons { |
429 if (!toolbarModel_) | 443 if (!toolbarModel_) |
430 return; | 444 return; |
431 | 445 |
432 NSUInteger i = 0; | 446 NSUInteger i = 0; |
433 for (ExtensionList::iterator iter = toolbarModel_->begin(); | 447 for (ExtensionList::iterator iter = toolbarModel_->begin(); |
434 iter != toolbarModel_->end(); ++iter) { | 448 iter != toolbarModel_->end(); ++iter) { |
435 if (![self shouldDisplayBrowserAction:*iter]) | 449 if (![self shouldDisplayBrowserAction:*iter]) |
436 continue; | 450 continue; |
437 | 451 |
438 [self createActionButtonForExtension:*iter withIndex:i++]; | 452 [self createActionButtonForExtension:*iter withIndex:i++]; |
439 } | 453 } |
440 | 454 |
441 [[NSNotificationCenter defaultCenter] | |
442 addObserver:self | |
443 selector:@selector(actionButtonUpdated:) | |
444 name:kBrowserActionButtonUpdatedNotification | |
445 object:nil]; | |
446 | |
447 CGFloat width = [self savedWidth]; | 455 CGFloat width = [self savedWidth]; |
448 [containerView_ resizeToWidth:width animate:NO]; | 456 [containerView_ resizeToWidth:width animate:NO]; |
449 } | 457 } |
450 | 458 |
451 - (void)createActionButtonForExtension:(const Extension*)extension | 459 - (void)createActionButtonForExtension:(const Extension*)extension |
452 withIndex:(NSUInteger)index { | 460 withIndex:(NSUInteger)index { |
453 if (!extension->browser_action()) | 461 if (!extension->browser_action()) |
454 return; | 462 return; |
455 | 463 |
456 if (![self shouldDisplayBrowserAction:extension]) | 464 if (![self shouldDisplayBrowserAction:extension]) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 BrowserActionButton* button = [buttons_ objectForKey:buttonKey]; | 512 BrowserActionButton* button = [buttons_ objectForKey:buttonKey]; |
505 // This could be the case in incognito, where only a subset of extensions are | 513 // This could be the case in incognito, where only a subset of extensions are |
506 // shown. | 514 // shown. |
507 if (!button) | 515 if (!button) |
508 return; | 516 return; |
509 | 517 |
510 [button removeFromSuperview]; | 518 [button removeFromSuperview]; |
511 // It may or may not be hidden, but it won't matter to NSMutableArray either | 519 // It may or may not be hidden, but it won't matter to NSMutableArray either |
512 // way. | 520 // way. |
513 [hiddenButtons_ removeObject:button]; | 521 [hiddenButtons_ removeObject:button]; |
514 [self updateOverflowMenu]; | |
515 | 522 |
516 [buttons_ removeObjectForKey:buttonKey]; | 523 [buttons_ removeObjectForKey:buttonKey]; |
517 if ([self buttonCount] == 0) { | 524 if ([self buttonCount] == 0) { |
518 // No more buttons? Hide the container. | 525 // No more buttons? Hide the container. |
519 [containerView_ setHidden:YES]; | 526 [containerView_ setHidden:YES]; |
520 } else { | 527 } else { |
521 [self positionActionButtonsAndAnimate:NO]; | 528 [self positionActionButtonsAndAnimate:NO]; |
522 } | 529 } |
523 [containerView_ setMaxWidth: | 530 [containerView_ setMaxWidth: |
524 [self containerWidthWithButtonCount:[self buttonCount]]]; | 531 [self containerWidthWithButtonCount:[self buttonCount]]]; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame)); | 636 NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame)); |
630 // Pad the threshold by 5 pixels in order to have the buttons hide more | 637 // Pad the threshold by 5 pixels in order to have the buttons hide more |
631 // easily. | 638 // easily. |
632 if (([containerView_ grippyPinned] && intersectionWidth > 0) || | 639 if (([containerView_ grippyPinned] && intersectionWidth > 0) || |
633 (intersectionWidth <= (NSWidth(buttonFrame) / 2) + 5.0)) { | 640 (intersectionWidth <= (NSWidth(buttonFrame) / 2) + 5.0)) { |
634 [button setAlphaValue:0.0]; | 641 [button setAlphaValue:0.0]; |
635 [button removeFromSuperview]; | 642 [button removeFromSuperview]; |
636 [hiddenButtons_ addObject:button]; | 643 [hiddenButtons_ addObject:button]; |
637 } | 644 } |
638 } | 645 } |
639 [self updateOverflowMenu]; | |
640 [self updateGrippyCursors]; | 646 [self updateGrippyCursors]; |
641 | 647 |
642 if (!profile_->IsOffTheRecord()) | 648 if (!profile_->IsOffTheRecord()) |
643 toolbarModel_->SetVisibleIconCount([self visibleButtonCount]); | 649 toolbarModel_->SetVisibleIconCount([self visibleButtonCount]); |
644 | 650 |
645 [[NSNotificationCenter defaultCenter] | 651 [[NSNotificationCenter defaultCenter] |
646 postNotificationName:kBrowserActionGrippyDragFinishedNotification | 652 postNotificationName:kBrowserActionGrippyDragFinishedNotification |
647 object:self]; | 653 object:self]; |
648 } | 654 } |
649 | 655 |
650 - (void)actionButtonUpdated:(NSNotification*)notification { | |
651 BrowserActionButton* button = [notification object]; | |
652 if (![hiddenButtons_ containsObject:button]) | |
653 return; | |
654 | |
655 // +1 item because of the title placeholder. See |updateOverflowMenu|. | |
656 NSUInteger menuIndex = [hiddenButtons_ indexOfObject:button] + 1; | |
657 NSMenuItem* item = [[chevronMenuButton_ attachedMenu] itemAtIndex:menuIndex]; | |
658 DCHECK(button == [item representedObject]); | |
659 [item setImage:[button compositedImage]]; | |
660 } | |
661 | |
662 - (void)actionButtonDragging:(NSNotification*)notification { | 656 - (void)actionButtonDragging:(NSNotification*)notification { |
663 if (![self chevronIsHidden]) | 657 if (![self chevronIsHidden]) |
664 [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES]; | 658 [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES]; |
665 | 659 |
666 // Determine what index the dragged button should lie in, alter the model and | 660 // Determine what index the dragged button should lie in, alter the model and |
667 // reposition the buttons. | 661 // reposition the buttons. |
668 CGFloat dragThreshold = std::floor(kBrowserActionWidth / 2); | 662 CGFloat dragThreshold = std::floor(kBrowserActionWidth / 2); |
669 BrowserActionButton* draggedButton = [notification object]; | 663 BrowserActionButton* draggedButton = [notification object]; |
670 NSRect draggedButtonFrame = [draggedButton frame]; | 664 NSRect draggedButtonFrame = [draggedButton frame]; |
671 | 665 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 // Make sure the button is within the visible container. | 698 // Make sure the button is within the visible container. |
705 if ([button superview] != containerView_) { | 699 if ([button superview] != containerView_) { |
706 [containerView_ addSubview:button]; | 700 [containerView_ addSubview:button]; |
707 [button setAlphaValue:1.0]; | 701 [button setAlphaValue:1.0]; |
708 [hiddenButtons_ removeObjectIdenticalTo:button]; | 702 [hiddenButtons_ removeObjectIdenticalTo:button]; |
709 } | 703 } |
710 } else if (![hiddenButtons_ containsObject:button]) { | 704 } else if (![hiddenButtons_ containsObject:button]) { |
711 [hiddenButtons_ addObject:button]; | 705 [hiddenButtons_ addObject:button]; |
712 [button removeFromSuperview]; | 706 [button removeFromSuperview]; |
713 [button setAlphaValue:0.0]; | 707 [button setAlphaValue:0.0]; |
714 [self updateOverflowMenu]; | |
715 } | 708 } |
716 } | 709 } |
717 | 710 |
718 - (void)browserActionClicked:(BrowserActionButton*)button { | 711 - (void)browserActionClicked:(BrowserActionButton*)button { |
719 const Extension* extension = [button extension]; | 712 const Extension* extension = [button extension]; |
720 GURL popupUrl; | 713 GURL popupUrl; |
721 switch (toolbarModel_->ExecuteBrowserAction(extension, browser_, &popupUrl)) { | 714 switch (toolbarModel_->ExecuteBrowserAction(extension, browser_, &popupUrl)) { |
722 case ExtensionToolbarModel::ACTION_NONE: | 715 case ExtensionToolbarModel::ACTION_NONE: |
723 break; | 716 break; |
724 case ExtensionToolbarModel::ACTION_SHOW_POPUP: { | 717 case ExtensionToolbarModel::ACTION_SHOW_POPUP: { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 [chevronMenuButton_ setBordered:NO]; | 760 [chevronMenuButton_ setBordered:NO]; |
768 [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES]; | 761 [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES]; |
769 | 762 |
770 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW | 763 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW |
771 forButtonState:image_button_cell::kDefaultState]; | 764 forButtonState:image_button_cell::kDefaultState]; |
772 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW_H | 765 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW_H |
773 forButtonState:image_button_cell::kHoverState]; | 766 forButtonState:image_button_cell::kHoverState]; |
774 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW_P | 767 [[chevronMenuButton_ cell] setImageID:IDR_BROWSER_ACTIONS_OVERFLOW_P |
775 forButtonState:image_button_cell::kPressedState]; | 768 forButtonState:image_button_cell::kPressedState]; |
776 | 769 |
| 770 overflowMenu_.reset([[NSMenu alloc] initWithTitle:@""]); |
| 771 [overflowMenu_ setAutoenablesItems:NO]; |
| 772 [overflowMenu_ setDelegate:self]; |
| 773 [chevronMenuButton_ setAttachedMenu:overflowMenu_]; |
| 774 |
777 [containerView_ addSubview:chevronMenuButton_]; | 775 [containerView_ addSubview:chevronMenuButton_]; |
778 } | 776 } |
779 | 777 |
780 if (!hidden) | |
781 [self updateOverflowMenu]; | |
782 | |
783 [self updateChevronPositionInFrame:frame]; | 778 [self updateChevronPositionInFrame:frame]; |
784 | 779 |
785 // Stop any running animation. | 780 // Stop any running animation. |
786 [chevronAnimation_ stopAnimation]; | 781 [chevronAnimation_ stopAnimation]; |
787 | 782 |
788 if (!animate) { | 783 if (!animate) { |
789 [chevronMenuButton_ setHidden:hidden]; | 784 [chevronMenuButton_ setHidden:hidden]; |
790 return; | 785 return; |
791 } | 786 } |
792 | 787 |
(...skipping 12 matching lines...) Expand all Loading... |
805 } | 800 } |
806 [chevronAnimation_ setViewAnimations: | 801 [chevronAnimation_ setViewAnimations: |
807 [NSArray arrayWithObject:animationDictionary]]; | 802 [NSArray arrayWithObject:animationDictionary]]; |
808 [chevronAnimation_ startAnimation]; | 803 [chevronAnimation_ startAnimation]; |
809 } | 804 } |
810 | 805 |
811 - (void)chevronItemSelected:(id)menuItem { | 806 - (void)chevronItemSelected:(id)menuItem { |
812 [self browserActionClicked:[menuItem representedObject]]; | 807 [self browserActionClicked:[menuItem representedObject]]; |
813 } | 808 } |
814 | 809 |
815 // TODO(yoz): This only gets called when the set of actions in the overflow | |
816 // menu changes (not for things that would update page actions). | |
817 // It should instead be called each time the menu is opened. | |
818 - (void)updateOverflowMenu { | |
819 overflowMenu_.reset([[NSMenu alloc] initWithTitle:@""]); | |
820 // See menu_button.h for documentation on why this is needed. | |
821 [overflowMenu_ addItemWithTitle:@"" action:nil keyEquivalent:@""]; | |
822 [overflowMenu_ setAutoenablesItems:NO]; | |
823 | |
824 for (BrowserActionButton* button in hiddenButtons_.get()) { | |
825 NSString* name = base::SysUTF8ToNSString([button extension]->name()); | |
826 NSMenuItem* item = | |
827 [overflowMenu_ addItemWithTitle:name | |
828 action:@selector(chevronItemSelected:) | |
829 keyEquivalent:@""]; | |
830 [item setRepresentedObject:button]; | |
831 [item setImage:[button compositedImage]]; | |
832 [item setTarget:self]; | |
833 [item setEnabled:[button isEnabled]]; | |
834 } | |
835 [chevronMenuButton_ setAttachedMenu:overflowMenu_]; | |
836 } | |
837 | |
838 - (void)updateGrippyCursors { | 810 - (void)updateGrippyCursors { |
839 [containerView_ setCanDragLeft:[hiddenButtons_ count] > 0]; | 811 [containerView_ setCanDragLeft:[hiddenButtons_ count] > 0]; |
840 [containerView_ setCanDragRight:[self visibleButtonCount] > 0]; | 812 [containerView_ setCanDragRight:[self visibleButtonCount] > 0]; |
841 [[containerView_ window] invalidateCursorRectsForView:containerView_]; | 813 [[containerView_ window] invalidateCursorRectsForView:containerView_]; |
842 } | 814 } |
843 | 815 |
844 - (int)currentTabId { | 816 - (int)currentTabId { |
845 TabContents* selected_tab = chrome::GetActiveTabContents(browser_); | 817 TabContents* selected_tab = chrome::GetActiveTabContents(browser_); |
846 if (!selected_tab) | 818 if (!selected_tab) |
847 return -1; | 819 return -1; |
848 | 820 |
849 return selected_tab->restore_tab_helper()->session_id().id(); | 821 return selected_tab->restore_tab_helper()->session_id().id(); |
850 } | 822 } |
851 | 823 |
852 #pragma mark - | 824 #pragma mark - |
853 #pragma mark Testing Methods | 825 #pragma mark Testing Methods |
854 | 826 |
855 - (NSButton*)buttonWithIndex:(NSUInteger)index { | 827 - (NSButton*)buttonWithIndex:(NSUInteger)index { |
856 if (profile_->IsOffTheRecord()) | 828 if (profile_->IsOffTheRecord()) |
857 index = toolbarModel_->IncognitoIndexToOriginal(index); | 829 index = toolbarModel_->IncognitoIndexToOriginal(index); |
858 if (index < toolbarModel_->size()) { | 830 if (index < toolbarModel_->size()) { |
859 const Extension* extension = toolbarModel_->GetExtensionByIndex(index); | 831 const Extension* extension = toolbarModel_->GetExtensionByIndex(index); |
860 return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())]; | 832 return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())]; |
861 } | 833 } |
862 return nil; | 834 return nil; |
863 } | 835 } |
864 | 836 |
865 @end | 837 @end |
OLD | NEW |