| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" |
| |
| #include <algorithm> |
| |
| #include "base/mac/bundle_locations.h" |
| #include "base/mac/foundation_util.h" |
| #include "base/mac/mac_util.h" |
| #include "base/mac/sdk_forward_declarations.h" |
| #include "base/macros.h" |
| #include "base/memory/singleton.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/command_observer.h" |
| #include "chrome/browser/command_updater.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/search.h" |
| #include "chrome/browser/sync/sync_global_error_factory.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h" |
| #import "chrome/browser/ui/cocoa/background_gradient_view.h" |
| #include "chrome/browser/ui/cocoa/drag_util.h" |
| #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h" |
| #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" |
| #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" |
| #import "chrome/browser/ui/cocoa/gradient_button_cell.h" |
| #import "chrome/browser/ui/cocoa/image_button_cell.h" |
| #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h" |
| #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" |
| #import "chrome/browser/ui/cocoa/menu_button.h" |
| #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" |
| #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h" |
| #import "chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h" |
| #import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h" |
| #import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" |
| #import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h" |
| #import "chrome/browser/ui/cocoa/view_id_util.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h" |
| #include "chrome/browser/ui/toolbar/app_menu_model.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chrome/grit/theme_resources.h" |
| #include "components/metrics/proto/omnibox_event.pb.h" |
| #include "components/omnibox/browser/autocomplete_classifier.h" |
| #include "components/omnibox/browser/autocomplete_match.h" |
| #include "components/omnibox/browser/omnibox_edit_model.h" |
| #include "components/omnibox/browser/omnibox_view.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/search_engines/template_url_service.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/url_formatter/url_fixer.h" |
| #include "content/public/browser/web_contents.h" |
| #import "ui/base/cocoa/menu_controller.h" |
| #import "ui/base/cocoa/nsview_additions.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/l10n/l10n_util_mac.h" |
| #include "ui/base/material_design/material_design_controller.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/image/image.h" |
| |
| using content::OpenURLParams; |
| using content::Referrer; |
| using content::WebContents; |
| |
| namespace { |
| |
| // Duration of the toolbar animation. |
| const NSTimeInterval kToolBarAnimationDuration = 0.12; |
| |
| // The height of the location bar in Material Design. |
| const CGFloat kMaterialDesignLocationBarHeight = 28; |
| |
| // The padding between the top of the toolbar and the top of the |
| // location bar. |
| const CGFloat kMaterialDesignLocationBarPadding = 2; |
| |
| // The padding between Material Design elements and the edges of the toolbar. |
| const CGFloat kMaterialDesignElementPadding = 4; |
| |
| // Toolbar buttons are 24x24 and centered in a 28x28 space, so there is a 2pt- |
| // wide inset. |
| const CGFloat kMaterialDesignButtonInset = 2; |
| |
| // The y-offset of the browser actions container from the location bar. |
| const CGFloat kMaterialDesignContainerYOffset = 2; |
| |
| // The minimum width of the location bar in pixels. |
| const CGFloat kMinimumLocationBarWidth = 100.0; |
| |
| class BrowserActionsContainerDelegate : |
| public BrowserActionsContainerViewSizeDelegate { |
| public: |
| BrowserActionsContainerDelegate( |
| AutocompleteTextField* location_bar, |
| BrowserActionsContainerView* browser_actions_container_view); |
| ~BrowserActionsContainerDelegate() override; |
| |
| private: |
| // BrowserActionsContainerSizeDelegate: |
| CGFloat GetMaxAllowedWidth() override; |
| |
| AutocompleteTextField* location_bar_; |
| BrowserActionsContainerView* browser_actions_container_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerDelegate); |
| }; |
| |
| BrowserActionsContainerDelegate::BrowserActionsContainerDelegate( |
| AutocompleteTextField* location_bar, |
| BrowserActionsContainerView* browser_actions_container_view) |
| : location_bar_(location_bar), |
| browser_actions_container_(browser_actions_container_view) { |
| [browser_actions_container_ setDelegate:this]; |
| } |
| |
| BrowserActionsContainerDelegate::~BrowserActionsContainerDelegate() { |
| [browser_actions_container_ setDelegate:nil]; |
| } |
| |
| CGFloat BrowserActionsContainerDelegate::GetMaxAllowedWidth() { |
| CGFloat location_bar_flex = |
| NSWidth([location_bar_ frame]) - kMinimumLocationBarWidth; |
| return NSWidth([browser_actions_container_ frame]) + location_bar_flex; |
| } |
| |
| } // namespace |
| |
| @interface ToolbarController() |
| @property(assign, nonatomic) Browser* browser; |
| // Height of the location bar. Used for animating the toolbar in and out when |
| // the location bar is displayed stand-alone for bookmark apps. |
| + (CGFloat)locationBarHeight; |
| // Return the amount of left padding that the app menu should have. |
| + (CGFloat)appMenuLeftPadding; |
| - (void)cleanUp; |
| - (void)addAccessibilityDescriptions; |
| - (void)initCommandStatus:(CommandUpdater*)commands; |
| - (void)prefChanged:(const std::string&)prefName; |
| - (ToolbarView*)toolbarView; |
| // Height of the toolbar in pixels when the bookmark bar is closed. |
| - (CGFloat)baseToolbarHeight; |
| - (void)toolbarFrameChanged; |
| - (void)showLocationBarOnly; |
| - (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate; |
| - (void)maintainMinimumLocationBarWidth; |
| - (void)adjustBrowserActionsContainerForNewWindow:(NSNotification*)notification; |
| - (void)browserActionsContainerDragged:(NSNotification*)notification; |
| - (void)browserActionsVisibilityChanged:(NSNotification*)notification; |
| - (void)browserActionsContainerWillAnimate:(NSNotification*)notification; |
| - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate; |
| - (void)updateAppMenuButtonSeverity:(AppMenuIconPainter::Severity)severity |
| iconType:(AppMenuIconController::IconType)iconType |
| animate:(BOOL)animate; |
| @end |
| |
| namespace ToolbarControllerInternal { |
| |
| // A C++ bridge class that handles listening for updates to commands and |
| // passing them back to ToolbarController. ToolbarController will create one of |
| // these bridges, pass them to CommandUpdater::AddCommandObserver, and then wait |
| // for update notifications, delivered via |
| // -enabledStateChangedForCommand:enabled:. |
| class CommandObserverBridge : public CommandObserver { |
| public: |
| explicit CommandObserverBridge(ToolbarController* observer) |
| : observer_(observer) { |
| DCHECK(observer_); |
| } |
| |
| protected: |
| // Overridden from CommandObserver |
| void EnabledStateChangedForCommand(int command, bool enabled) override { |
| [observer_ enabledStateChangedForCommand:command enabled:enabled]; |
| } |
| |
| private: |
| ToolbarController* observer_; // weak, owns me |
| |
| DISALLOW_COPY_AND_ASSIGN(CommandObserverBridge); |
| }; |
| |
| // A class registered for C++ notifications. This is used to detect changes in |
| // preferences and upgrade available notifications. Bridges the notification |
| // back to the ToolbarController. |
| class NotificationBridge : public AppMenuIconController::Delegate { |
| public: |
| explicit NotificationBridge(ToolbarController* controller) |
| : controller_(controller), |
| app_menu_icon_controller_([controller browser]->profile(), this) {} |
| ~NotificationBridge() override {} |
| |
| void UpdateSeverity() { app_menu_icon_controller_.UpdateDelegate(); } |
| |
| void UpdateSeverity(AppMenuIconController::IconType type, |
| AppMenuIconPainter::Severity severity, |
| bool animate) override { |
| [controller_ updateAppMenuButtonSeverity:severity |
| iconType:type |
| animate:animate]; |
| } |
| |
| void OnPreferenceChanged(const std::string& pref_name) { |
| [controller_ prefChanged:pref_name]; |
| } |
| |
| private: |
| ToolbarController* controller_; // weak, owns us |
| |
| AppMenuIconController app_menu_icon_controller_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NotificationBridge); |
| }; |
| |
| } // namespace ToolbarControllerInternal |
| |
| @implementation ToolbarController |
| |
| @synthesize browser = browser_; |
| |
| + (CGFloat)locationBarHeight { |
| if (!ui::MaterialDesignController::IsModeMaterial()) { |
| return 29; |
| } |
| |
| return kMaterialDesignLocationBarHeight; |
| } |
| |
| + (CGFloat)appMenuLeftPadding { |
| if (!ui::MaterialDesignController::IsModeMaterial()) { |
| return 3; |
| } |
| |
| return kMaterialDesignElementPadding; |
| } |
| |
| + (CGFloat)materialDesignButtonInset { |
| return kMaterialDesignButtonInset; |
| } |
| |
| - (id)initWithCommands:(CommandUpdater*)commands |
| profile:(Profile*)profile |
| browser:(Browser*)browser |
| resizeDelegate:(id<ViewResizer>)resizeDelegate { |
| DCHECK(commands && profile); |
| if ((self = [super initWithNibName:@"Toolbar" |
| bundle:base::mac::FrameworkBundle()])) { |
| commands_ = commands; |
| profile_ = profile; |
| browser_ = browser; |
| hasToolbar_ = YES; |
| hasLocationBar_ = YES; |
| |
| // Register for notifications about state changes for the toolbar buttons |
| commandObserver_.reset( |
| new ToolbarControllerInternal::CommandObserverBridge(self)); |
| |
| commands->AddCommandObserver(IDC_BACK, commandObserver_.get()); |
| commands->AddCommandObserver(IDC_FORWARD, commandObserver_.get()); |
| commands->AddCommandObserver(IDC_RELOAD, commandObserver_.get()); |
| commands->AddCommandObserver(IDC_HOME, commandObserver_.get()); |
| commands->AddCommandObserver(IDC_BOOKMARK_PAGE, commandObserver_.get()); |
| // NOTE: Don't remove the command observers. ToolbarController is |
| // autoreleased at about the same time as the CommandUpdater (owned by the |
| // Browser), so |commands_| may not be valid any more. |
| |
| [[self toolbarView] setResizeDelegate:resizeDelegate]; |
| |
| // Start global error services now so we badge the menu correctly. |
| SyncGlobalErrorFactory::GetForProfile(profile); |
| } |
| return self; |
| } |
| |
| // Called after the view is done loading and the outlets have been hooked up. |
| // Now we can hook up bridges that rely on UI objects such as the location bar |
| // and button state. -viewDidLoad is the recommended way to do this in 10.10 |
| // SDK. When running on 10.10 or above -awakeFromNib still works but for some |
| // reason is not guaranteed to be called (http://crbug.com/526276), so implement |
| // both. |
| - (void)awakeFromNib { |
| [self viewDidLoad]; |
| } |
| |
| - (void)viewDidLoad { |
| // When linking and running on 10.10+, both -awakeFromNib and -viewDidLoad may |
| // be called, don't initialize twice. |
| if (locationBarView_) { |
| DCHECK(base::mac::IsAtLeastOS10_10()); |
| return; |
| } |
| |
| // Make Material Design layout adjustments to the NIB items. |
| bool isModeMaterial = ui::MaterialDesignController::IsModeMaterial(); |
| if (isModeMaterial) { |
| ToolbarView* toolbarView = [self toolbarView]; |
| NSRect toolbarBounds = [toolbarView bounds]; |
| NSSize toolbarButtonSize = [ToolbarButton toolbarButtonSize]; |
| |
| // Set the toolbar height. |
| NSRect frame = [toolbarView frame]; |
| frame.size.height = [self baseToolbarHeight]; |
| [toolbarView setFrame:frame]; |
| |
| NSRect backButtonFrame = [backButton_ frame]; |
| backButtonFrame.origin.x = |
| kMaterialDesignElementPadding + kMaterialDesignButtonInset; |
| backButtonFrame.origin.y = NSMaxY(toolbarBounds) - |
| kMaterialDesignElementPadding - toolbarButtonSize.height; |
| backButtonFrame.size = toolbarButtonSize; |
| [backButton_ setFrame:backButtonFrame]; |
| |
| NSRect forwardButtonFrame = [forwardButton_ frame]; |
| forwardButtonFrame.origin.x = |
| NSMaxX(backButtonFrame) + 2 * kMaterialDesignButtonInset; |
| forwardButtonFrame.origin.y = backButtonFrame.origin.y; |
| forwardButtonFrame.size = toolbarButtonSize; |
| [forwardButton_ setFrame:forwardButtonFrame]; |
| |
| NSRect reloadButtonFrame = [reloadButton_ frame]; |
| reloadButtonFrame.origin.x = |
| NSMaxX(forwardButtonFrame) + 2 * kMaterialDesignButtonInset; |
| reloadButtonFrame.origin.y = forwardButtonFrame.origin.y; |
| reloadButtonFrame.size = toolbarButtonSize; |
| [reloadButton_ setFrame:reloadButtonFrame]; |
| |
| NSRect homeButtonFrame = [homeButton_ frame]; |
| homeButtonFrame.origin.x = |
| NSMaxX(reloadButtonFrame) + 2 * kMaterialDesignButtonInset; |
| homeButtonFrame.origin.y = reloadButtonFrame.origin.y; |
| homeButtonFrame.size = toolbarButtonSize; |
| [homeButton_ setFrame:homeButtonFrame]; |
| |
| // Replace the app button from the nib with an AppToolbarButton instance for |
| // Material Design. |
| AppToolbarButton* newMenuButton = |
| [[[AppToolbarButton alloc] initWithFrame:[appMenuButton_ frame]] |
| autorelease]; |
| [newMenuButton setAutoresizingMask:[appMenuButton_ autoresizingMask]]; |
| [[appMenuButton_ superview] addSubview:newMenuButton]; |
| [appMenuButton_ removeFromSuperview]; |
| appMenuButton_ = newMenuButton; |
| |
| // Adjust the menu button's position. |
| NSRect menuButtonFrame = [appMenuButton_ frame]; |
| CGFloat menuButtonFrameMaxX = |
| NSMaxX(toolbarBounds) - [ToolbarController appMenuLeftPadding]; |
| menuButtonFrame.origin.x = |
| menuButtonFrameMaxX - kMaterialDesignButtonInset - |
| toolbarButtonSize.width; |
| menuButtonFrame.origin.y = homeButtonFrame.origin.y; |
| menuButtonFrame.size = toolbarButtonSize; |
| [appMenuButton_ setFrame:menuButtonFrame]; |
| |
| // Adjust the size and location on the location bar to take up the |
| // space between the reload and menu buttons. |
| NSRect locationBarFrame = [locationBar_ frame]; |
| locationBarFrame.origin.x = NSMaxX(homeButtonFrame) + |
| kMaterialDesignButtonInset; |
| if (![homeButton_ isHidden]) { |
| // Ensure proper spacing between the home button and the location bar. |
| locationBarFrame.origin.x += kMaterialDesignElementPadding; |
| } |
| locationBarFrame.origin.y = NSMaxY(toolbarBounds) - |
| kMaterialDesignLocationBarPadding - kMaterialDesignLocationBarHeight; |
| locationBarFrame.size.width = |
| menuButtonFrame.origin.x - |
| locationBarFrame.origin.x; |
| locationBarFrame.size.height = kMaterialDesignLocationBarHeight; |
| [locationBar_ setFrame:locationBarFrame]; |
| |
| // Correctly position the extension buttons' container view. |
| NSRect containerFrame = [browserActionsContainerView_ frame]; |
| containerFrame.size.width += kMaterialDesignButtonInset; |
| containerFrame.origin.y = |
| locationBarFrame.origin.y + kMaterialDesignContainerYOffset; |
| containerFrame.size.height = toolbarButtonSize.height; |
| [browserActionsContainerView_ setFrame:containerFrame]; |
| } else { |
| [[backButton_ cell] setImageID:IDR_BACK |
| forButtonState:image_button_cell::kDefaultState]; |
| [[backButton_ cell] setImageID:IDR_BACK_H |
| forButtonState:image_button_cell::kHoverState]; |
| [[backButton_ cell] setImageID:IDR_BACK_P |
| forButtonState:image_button_cell::kPressedState]; |
| [[backButton_ cell] setImageID:IDR_BACK_D |
| forButtonState:image_button_cell::kDisabledState]; |
| |
| [[forwardButton_ cell] setImageID:IDR_FORWARD |
| forButtonState:image_button_cell::kDefaultState]; |
| [[forwardButton_ cell] setImageID:IDR_FORWARD_H |
| forButtonState:image_button_cell::kHoverState]; |
| [[forwardButton_ cell] setImageID:IDR_FORWARD_P |
| forButtonState:image_button_cell::kPressedState]; |
| [[forwardButton_ cell] setImageID:IDR_FORWARD_D |
| forButtonState:image_button_cell::kDisabledState]; |
| |
| [[reloadButton_ cell] setImageID:IDR_RELOAD |
| forButtonState:image_button_cell::kDefaultState]; |
| [[reloadButton_ cell] setImageID:IDR_RELOAD_H |
| forButtonState:image_button_cell::kHoverState]; |
| [[reloadButton_ cell] setImageID:IDR_RELOAD_P |
| forButtonState:image_button_cell::kPressedState]; |
| |
| [[homeButton_ cell] setImageID:IDR_HOME |
| forButtonState:image_button_cell::kDefaultState]; |
| [[homeButton_ cell] setImageID:IDR_HOME_H |
| forButtonState:image_button_cell::kHoverState]; |
| [[homeButton_ cell] setImageID:IDR_HOME_P |
| forButtonState:image_button_cell::kPressedState]; |
| |
| [[appMenuButton_ cell] setImageID:IDR_TOOLS |
| forButtonState:image_button_cell::kDefaultState]; |
| [[appMenuButton_ cell] setImageID:IDR_TOOLS_H |
| forButtonState:image_button_cell::kHoverState]; |
| [[appMenuButton_ cell] setImageID:IDR_TOOLS_P |
| forButtonState:image_button_cell::kPressedState]; |
| |
| // Adjust the toolbar height if running on Retina - see the comment in |
| // -baseToolbarHeight. |
| CGFloat toolbarHeight = [self baseToolbarHeight]; |
| ToolbarView* toolbarView = [self toolbarView]; |
| NSRect toolbarFrame = [toolbarView frame]; |
| if (toolbarFrame.size.height != toolbarHeight) { |
| toolbarFrame.size.height = toolbarHeight; |
| [toolbarView setFrame:toolbarFrame]; |
| } |
| } |
| |
| notificationBridge_.reset( |
| new ToolbarControllerInternal::NotificationBridge(self)); |
| notificationBridge_->UpdateSeverity(); |
| |
| [appMenuButton_ setOpenMenuOnClick:YES]; |
| |
| [backButton_ setOpenMenuOnRightClick:YES]; |
| [forwardButton_ setOpenMenuOnRightClick:YES]; |
| |
| [backButton_ setHandleMiddleClick:YES]; |
| [forwardButton_ setHandleMiddleClick:YES]; |
| [reloadButton_ setHandleMiddleClick:YES]; |
| [homeButton_ setHandleMiddleClick:YES]; |
| |
| [self initCommandStatus:commands_]; |
| [reloadButton_ setCommandUpdater:commands_]; |
| |
| locationBarView_.reset(new LocationBarViewMac(locationBar_, commands_, |
| profile_, browser_)); |
| [locationBar_ setFont:[NSFont systemFontOfSize:14]]; |
| |
| // Add the location bar's accessibility views as direct subviews of the |
| // toolbar. They are logical children of the location bar, but the location |
| // bar's actual Cocoa control is an NSCell, so it cannot have child views. |
| // The |locationBarView_| is responsible for positioning the accessibility |
| // views. |
| std::vector<NSView*> accessibility_views = |
| locationBarView_->GetDecorationAccessibilityViews(); |
| for (const auto& view : accessibility_views) { |
| [[self toolbarView] addSubview:view |
| positioned:NSWindowAbove |
| relativeTo:locationBar_]; |
| } |
| |
| if (!isModeMaterial) { |
| [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; |
| } |
| |
| // Register pref observers for the optional home and page/options buttons |
| // and then add them to the toolbar based on those prefs. |
| PrefService* prefs = profile_->GetPrefs(); |
| showHomeButton_.Init( |
| prefs::kShowHomeButton, prefs, |
| base::Bind( |
| &ToolbarControllerInternal::NotificationBridge::OnPreferenceChanged, |
| base::Unretained(notificationBridge_.get()))); |
| [self showOptionalHomeButton]; |
| [self installAppMenu]; |
| |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| |
| // Create the controllers for the back/forward menus. |
| backMenuController_.reset([[BackForwardMenuController alloc] |
| initWithBrowser:browser_ |
| modelType:BACK_FORWARD_MENU_TYPE_BACK |
| button:backButton_]); |
| forwardMenuController_.reset([[BackForwardMenuController alloc] |
| initWithBrowser:browser_ |
| modelType:BACK_FORWARD_MENU_TYPE_FORWARD |
| button:forwardButton_]); |
| |
| trackingArea_.reset( |
| [[CrTrackingArea alloc] initWithRect:NSZeroRect // Ignored |
| options:NSTrackingMouseMoved | |
| NSTrackingInVisibleRect | |
| NSTrackingMouseEnteredAndExited | |
| NSTrackingActiveAlways |
| owner:self |
| userInfo:nil]); |
| NSView* toolbarView = [self view]; |
| [toolbarView addTrackingArea:trackingArea_.get()]; |
| |
| // If the user has any Browser Actions installed, the container view for them |
| // may have to be resized depending on the width of the toolbar frame. |
| [toolbarView setPostsFrameChangedNotifications:YES]; |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(toolbarFrameChanged) |
| name:NSViewFrameDidChangeNotification |
| object:toolbarView]; |
| |
| // Set ViewIDs for toolbar elements which don't have their dedicated class. |
| // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and |
| // |browserActionsContainerView_| are handled by themselves. |
| view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON); |
| view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON); |
| view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON); |
| view_id_util::SetID(appMenuButton_, VIEW_ID_APP_MENU); |
| |
| [self addAccessibilityDescriptions]; |
| } |
| |
| - (void)dealloc { |
| [self cleanUp]; |
| [super dealloc]; |
| } |
| |
| - (void)browserWillBeDestroyed { |
| // Clear resize delegate so it doesn't get called during stopAnimation, and |
| // stop any in-flight animation. |
| [[self toolbarView] setResizeDelegate:nil]; |
| [[self toolbarView] stopAnimation]; |
| |
| // Pass this call onto other reference counted objects. |
| [backMenuController_ browserWillBeDestroyed]; |
| [forwardMenuController_ browserWillBeDestroyed]; |
| [browserActionsController_ browserWillBeDestroyed]; |
| [appMenuController_ browserWillBeDestroyed]; |
| |
| [self cleanUp]; |
| } |
| |
| - (void)cleanUp { |
| // Unset ViewIDs of toolbar elements. |
| // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and |
| // |browserActionsContainerView_| are handled by themselves. |
| view_id_util::UnsetID(backButton_); |
| view_id_util::UnsetID(forwardButton_); |
| view_id_util::UnsetID(homeButton_); |
| view_id_util::UnsetID(appMenuButton_); |
| |
| // Make sure any code in the base class which assumes [self view] is |
| // the "parent" view continues to work. |
| hasToolbar_ = YES; |
| hasLocationBar_ = YES; |
| |
| [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| |
| if (trackingArea_.get()) { |
| [[self view] removeTrackingArea:trackingArea_.get()]; |
| [trackingArea_.get() clearOwner]; |
| trackingArea_.reset(); |
| } |
| |
| // Destroy owned objects that hold a weak Browser*. |
| locationBarView_.reset(); |
| browserActionsContainerDelegate_.reset(); |
| browser_ = nullptr; |
| } |
| |
| - (void)addAccessibilityDescriptions { |
| // Set accessibility descriptions. http://openradar.appspot.com/7496255 |
| NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK); |
| [[backButton_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| NSString* helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TOOLTIP_BACK); |
| [[backButton_ cell] |
| accessibilitySetOverrideValue:helpTag |
| forAttribute:NSAccessibilityHelpAttribute]; |
| |
| description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD); |
| [[forwardButton_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TOOLTIP_FORWARD); |
| [[forwardButton_ cell] |
| accessibilitySetOverrideValue:helpTag |
| forAttribute:NSAccessibilityHelpAttribute]; |
| |
| description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD); |
| [[reloadButton_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME); |
| [[homeButton_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION); |
| [[locationBar_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP); |
| [[appMenuButton_ cell] |
| accessibilitySetOverrideValue:description |
| forAttribute:NSAccessibilityDescriptionAttribute]; |
| } |
| |
| - (void)mouseExited:(NSEvent*)theEvent { |
| [[hoveredButton_ cell] setIsMouseInside:NO]; |
| [hoveredButton_ release]; |
| hoveredButton_ = nil; |
| } |
| |
| - (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent { |
| NSButton* targetView = (NSButton*)[[self view] |
| hitTest:[theEvent locationInWindow]]; |
| |
| // Only interpret the view as a hoverButton_ if it's both button and has a |
| // button cell that cares. GradientButtonCell derived cells care. |
| if (([targetView isKindOfClass:[NSButton class]]) && |
| ([[targetView cell] |
| respondsToSelector:@selector(setIsMouseInside:)])) |
| return targetView; |
| return nil; |
| } |
| |
| - (void)mouseMoved:(NSEvent*)theEvent { |
| NSButton* targetView = [self hoverButtonForEvent:theEvent]; |
| if (hoveredButton_ != targetView) { |
| [[hoveredButton_ cell] setIsMouseInside:NO]; |
| [[targetView cell] setIsMouseInside:YES]; |
| [hoveredButton_ release]; |
| hoveredButton_ = [targetView retain]; |
| } |
| } |
| |
| - (void)mouseEntered:(NSEvent*)event { |
| [self mouseMoved:event]; |
| } |
| |
| - (LocationBarViewMac*)locationBarBridge { |
| return locationBarView_.get(); |
| } |
| |
| - (void)locationBarWasAddedToWindow { |
| // Allow the |locationBarView_| to update itself to match the browser window |
| // theme. |
| locationBarView_->OnAddedToWindow(); |
| } |
| |
| - (void)focusLocationBar:(BOOL)selectAll { |
| if (locationBarView_.get()) { |
| locationBarView_->FocusLocation(selectAll ? true : false); |
| } |
| } |
| |
| // Called when the state for a command changes to |enabled|. Update the |
| // corresponding UI element. |
| - (void)enabledStateChangedForCommand:(int)command enabled:(bool)enabled { |
| NSButton* button = nil; |
| switch (command) { |
| case IDC_BACK: |
| button = backButton_; |
| break; |
| case IDC_FORWARD: |
| button = forwardButton_; |
| break; |
| case IDC_HOME: |
| button = homeButton_; |
| break; |
| } |
| [button setEnabled:enabled]; |
| } |
| |
| // Init the enabled state of the buttons on the toolbar to match the state in |
| // the controller. |
| - (void)initCommandStatus:(CommandUpdater*)commands { |
| [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO]; |
| [forwardButton_ |
| setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO]; |
| [reloadButton_ setEnabled:YES]; |
| [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO]; |
| } |
| |
| - (void)updateToolbarWithContents:(WebContents*)tab { |
| locationBarView_->Update(tab); |
| |
| [locationBar_ updateMouseTracking]; |
| |
| if (browserActionsController_.get()) { |
| [browserActionsController_ update]; |
| } |
| |
| BOOL needReloadMenu = chrome::IsDebuggerAttachedToCurrentTab(browser_); |
| [reloadButton_ setMenuEnabled:needReloadMenu]; |
| } |
| |
| - (void)resetTabState:(WebContents*)tab { |
| locationBarView_->ResetTabState(tab); |
| } |
| |
| - (void)setStarredState:(BOOL)isStarred { |
| locationBarView_->SetStarred(isStarred); |
| } |
| |
| - (void)setTranslateIconLit:(BOOL)on { |
| locationBarView_->SetTranslateIconLit(on); |
| } |
| |
| - (void)zoomChangedForActiveTab:(BOOL)canShowBubble { |
| locationBarView_->ZoomChangedForActiveTab( |
| canShowBubble && ![appMenuController_ isMenuOpen]); |
| } |
| |
| - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { |
| [reloadButton_ setIsLoading:isLoading force:force]; |
| } |
| |
| - (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar { |
| [self view]; // Force nib loading. |
| |
| hasToolbar_ = toolbar; |
| |
| // If there's a toolbar, there must be a location bar. |
| DCHECK((toolbar && locBar) || !toolbar); |
| hasLocationBar_ = toolbar ? YES : locBar; |
| |
| // Decide whether to hide/show based on whether there's a location bar. |
| [[self view] setHidden:!hasLocationBar_]; |
| |
| // Make location bar not editable when in a pop-up or an app window. |
| locationBarView_->SetEditable(toolbar); |
| |
| // If necessary, resize the location bar and hide the toolbar icons to display |
| // the toolbar with only the location bar inside it. |
| if (!hasToolbar_ && hasLocationBar_) |
| [self showLocationBarOnly]; |
| } |
| |
| // (Private) Returns the backdrop to the toolbar as a ToolbarView. |
| - (ToolbarView*)toolbarView{ |
| return base::mac::ObjCCastStrict<ToolbarView>([self view]); |
| } |
| |
| - (id)customFieldEditorForObject:(id)obj { |
| if (obj == locationBar_) { |
| // Lazilly construct Field editor, Cocoa UI code always runs on the |
| // same thread, so there shoudn't be a race condition here. |
| if (autocompleteTextFieldEditor_.get() == nil) { |
| autocompleteTextFieldEditor_.reset( |
| [[AutocompleteTextFieldEditor alloc] init]); |
| } |
| |
| // This needs to be called every time, otherwise notifications |
| // aren't sent correctly. |
| DCHECK(autocompleteTextFieldEditor_.get()); |
| [autocompleteTextFieldEditor_.get() setFieldEditor:YES]; |
| return autocompleteTextFieldEditor_.get(); |
| } |
| return nil; |
| } |
| |
| // Returns an array of views in the order of the outlets above. |
| - (NSArray*)toolbarViews { |
| return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_, |
| homeButton_, appMenuButton_, locationBar_, |
| browserActionsContainerView_, nil]; |
| } |
| |
| // Moves |rect| to the right by |delta|, keeping the right side fixed by |
| // shrinking the width to compensate. Passing a negative value for |deltaX| |
| // moves to the left and increases the width. |
| - (NSRect)adjustRect:(NSRect)rect byAmount:(CGFloat)deltaX { |
| NSRect frame = NSOffsetRect(rect, deltaX, 0); |
| frame.size.width -= deltaX; |
| return frame; |
| } |
| |
| // Show or hide the home button based on the pref. |
| - (void)showOptionalHomeButton { |
| // Ignore this message if only showing the URL bar. |
| if (!hasToolbar_) |
| return; |
| BOOL hide = showHomeButton_.GetValue() ? NO : YES; |
| if (hide == [homeButton_ isHidden]) |
| return; // Nothing to do, view state matches pref state. |
| |
| // Always shift the text field by the width of the home button minus one pixel |
| // since the frame edges of each button are right on top of each other. When |
| // hiding the button, reverse the direction of the movement (to the left). |
| CGFloat moveX = [homeButton_ frame].size.width; |
| if (!ui::MaterialDesignController::IsModeMaterial()) { |
| moveX -= 1.0; |
| } else { |
| // Ensure proper spacing between the home button and the location bar. |
| moveX += kMaterialDesignElementPadding; |
| } |
| if (hide) |
| moveX *= -1; // Reverse the direction of the move. |
| |
| [locationBar_ setFrame:[self adjustRect:[locationBar_ frame] |
| byAmount:moveX]]; |
| [homeButton_ setHidden:hide]; |
| } |
| |
| // Install the app menu buttons. Calling this repeatedly is inexpensive so it |
| // can be done every time the buttons are shown. |
| - (void)installAppMenu { |
| if (appMenuController_.get()) |
| return; |
| |
| appMenuController_.reset( |
| [[AppMenuController alloc] initWithBrowser:browser_]); |
| [appMenuController_ setUseWithPopUpButtonCell:YES]; |
| [appMenuButton_ setAttachedMenu:[appMenuController_ menu]]; |
| } |
| |
| - (void)updateAppMenuButtonSeverity:(AppMenuIconPainter::Severity)severity |
| iconType:(AppMenuIconController::IconType)iconType |
| animate:(BOOL)animate { |
| if (!ui::MaterialDesignController::IsModeMaterial()) { |
| AppToolbarButtonCell* cell = |
| base::mac::ObjCCastStrict<AppToolbarButtonCell>([appMenuButton_ cell]); |
| [cell setSeverity:severity shouldAnimate:animate]; |
| return; |
| } |
| AppToolbarButton* appMenuButton = |
| base::mac::ObjCCastStrict<AppToolbarButton>(appMenuButton_); |
| [appMenuButton setSeverity:severity iconType:iconType shouldAnimate:animate]; |
| } |
| |
| - (void)prefChanged:(const std::string&)prefName { |
| if (prefName == prefs::kShowHomeButton) { |
| [self showOptionalHomeButton]; |
| } |
| } |
| |
| - (void)createBrowserActionButtons { |
| if (!browserActionsController_.get()) { |
| browserActionsContainerDelegate_.reset( |
| new BrowserActionsContainerDelegate(locationBar_, |
| browserActionsContainerView_)); |
| browserActionsController_.reset([[BrowserActionsController alloc] |
| initWithBrowser:browser_ |
| containerView:browserActionsContainerView_ |
| mainController:nil]); |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(browserActionsContainerDragged:) |
| name:kBrowserActionGrippyDraggingNotification |
| object:browserActionsContainerView_]; |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(browserActionsVisibilityChanged:) |
| name:kBrowserActionVisibilityChangedNotification |
| object:browserActionsController_]; |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(browserActionsContainerWillAnimate:) |
| name:kBrowserActionsContainerWillAnimate |
| object:browserActionsContainerView_]; |
| [[NSNotificationCenter defaultCenter] |
| addObserver:self |
| selector:@selector(adjustBrowserActionsContainerForNewWindow:) |
| name:NSWindowDidBecomeKeyNotification |
| object:[[self view] window]]; |
| } |
| if (![browserActionsContainerView_ isHidden]) |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| } |
| |
| - (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate { |
| CGFloat newHeight = visible ? [ToolbarController locationBarHeight] : 0; |
| |
| // Perform the animation, which will cause the BrowserWindowController to |
| // resize this view in the browser layout as required. |
| if (animate) { |
| [[self toolbarView] animateToNewHeight:newHeight |
| duration:kToolBarAnimationDuration]; |
| } else { |
| [[self toolbarView] setHeight:newHeight]; |
| } |
| } |
| |
| - (void)adjustBrowserActionsContainerForNewWindow: |
| (NSNotification*)notification { |
| [self toolbarFrameChanged]; |
| [[NSNotificationCenter defaultCenter] |
| removeObserver:self |
| name:NSWindowDidBecomeKeyNotification |
| object:[[self view] window]]; |
| } |
| |
| - (void)browserActionsContainerDragged:(NSNotification*)notification { |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| } |
| |
| - (void)browserActionsVisibilityChanged:(NSNotification*)notification { |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| } |
| |
| - (void)browserActionsContainerWillAnimate:(NSNotification*)notification { |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:YES]; |
| } |
| |
| - (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate { |
| CGFloat locationBarXPos = NSMaxX([locationBar_ frame]); |
| CGFloat leftDistance = 0.0; |
| |
| if ([browserActionsContainerView_ isHidden]) { |
| CGFloat edgeXPos = [appMenuButton_ frame].origin.x; |
| leftDistance = edgeXPos - locationBarXPos - |
| [ToolbarController appMenuLeftPadding]; |
| } else { |
| leftDistance = NSMinX([browserActionsContainerView_ animationEndFrame]) - |
| locationBarXPos; |
| // Equalize the distance between the location bar and the first extension |
| // button, and the distance between the location bar and home/reload button. |
| if (ui::MaterialDesignController::IsModeMaterial()) { |
| leftDistance -= kMaterialDesignButtonInset; |
| } |
| } |
| if (leftDistance != 0.0) |
| [self adjustLocationSizeBy:leftDistance animate:animate]; |
| else |
| [locationBar_ stopAnimation]; |
| } |
| |
| - (void)maintainMinimumLocationBarWidth { |
| CGFloat locationBarWidth = NSWidth([locationBar_ frame]); |
| locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth; |
| if (locationBarAtMinSize_) { |
| CGFloat dX = kMinimumLocationBarWidth - locationBarWidth; |
| [self adjustLocationSizeBy:dX animate:NO]; |
| } |
| } |
| |
| - (void)toolbarFrameChanged { |
| // Do nothing if the frame changes but no Browser Action Controller is |
| // present. |
| if (!browserActionsController_.get()) |
| return; |
| |
| if ([browserActionsContainerView_ isAnimating]) { |
| // If the browser actions container is animating, we need to stop it first, |
| // because the frame it's animating for could be incorrect with the new |
| // bounds (if, for instance, the bookmark bar was added). |
| // This will advance to the end of the animation, so we also need to adjust |
| // it afterwards. |
| [browserActionsContainerView_ stopAnimation]; |
| NSRect containerFrame = [browserActionsContainerView_ frame]; |
| if (!ui::MaterialDesignController::IsModeMaterial()) { |
| CGFloat elementTopPadding = |
| kMaterialDesignElementPadding + kMaterialDesignButtonInset; |
| // Pre-Material Design, this value is calculated from the values in |
| // Toolbar.xib: the height of the toolbar (35) minus the height of the |
| // child elements (29) minus the y-origin of the elements (4). |
| elementTopPadding = 2; |
| containerFrame.origin.y = |
| NSHeight([[self view] frame]) - NSHeight(containerFrame) - |
| elementTopPadding; |
| } else { |
| containerFrame.origin.y = |
| [locationBar_ frame].origin.y + kMaterialDesignContainerYOffset; |
| } |
| [browserActionsContainerView_ setFrame:containerFrame]; |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| } |
| |
| [self maintainMinimumLocationBarWidth]; |
| |
| if (locationBarAtMinSize_) { |
| // Once the grippy is pinned, leave it until it is explicity un-pinned. |
| [browserActionsContainerView_ setGrippyPinned:YES]; |
| NSRect containerFrame = [browserActionsContainerView_ frame]; |
| // Determine how much the container needs to move in case it's overlapping |
| // with the location bar. |
| CGFloat dX = NSMaxX([locationBar_ frame]) - containerFrame.origin.x; |
| containerFrame = NSOffsetRect(containerFrame, dX, 0); |
| containerFrame.size.width -= dX; |
| [browserActionsContainerView_ setFrame:containerFrame]; |
| } else if (!locationBarAtMinSize_ && |
| [browserActionsContainerView_ grippyPinned]) { |
| // Expand out the container until it hits the saved size, then unpin the |
| // grippy. |
| // Add 0.1 pixel so that it doesn't hit the minimum width codepath above. |
| CGFloat dX = NSWidth([locationBar_ frame]) - |
| (kMinimumLocationBarWidth + 0.1); |
| NSRect containerFrame = [browserActionsContainerView_ frame]; |
| containerFrame = NSOffsetRect(containerFrame, -dX, 0); |
| containerFrame.size.width += dX; |
| CGFloat savedContainerWidth = |
| [browserActionsController_ preferredSize].width(); |
| if (NSWidth(containerFrame) >= savedContainerWidth) { |
| containerFrame = NSOffsetRect(containerFrame, |
| NSWidth(containerFrame) - savedContainerWidth, 0); |
| containerFrame.size.width = savedContainerWidth; |
| [browserActionsContainerView_ setGrippyPinned:NO]; |
| } |
| [browserActionsContainerView_ setFrame:containerFrame]; |
| [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO]; |
| } |
| } |
| |
| // Hide the back, forward, reload, home, and app menu buttons of the toolbar. |
| // This allows the location bar to occupy the entire width. There is no way to |
| // undo this operation, and once it is called, no other programmatic changes |
| // to the toolbar or location bar width should be made. This message is |
| // invalid if the toolbar is shown or the location bar is hidden. |
| - (void)showLocationBarOnly { |
| // -showLocationBarOnly is only ever called once, shortly after |
| // initialization, so the regular buttons should all be visible. |
| DCHECK(!hasToolbar_ && hasLocationBar_); |
| DCHECK(![backButton_ isHidden]); |
| |
| // Ensure the location bar fills the toolbar. |
| NSRect toolbarFrame = [[self view] frame]; |
| toolbarFrame.size.height = [ToolbarController locationBarHeight]; |
| [[self view] setFrame:toolbarFrame]; |
| |
| [locationBar_ setFrame:NSMakeRect(0, 0, NSWidth([[self view] frame]), |
| [ToolbarController locationBarHeight])]; |
| |
| [backButton_ setHidden:YES]; |
| [forwardButton_ setHidden:YES]; |
| [reloadButton_ setHidden:YES]; |
| [appMenuButton_ setHidden:YES]; |
| [homeButton_ setHidden:YES]; |
| } |
| |
| - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate { |
| // Ensure that the location bar is in its proper place. |
| NSRect locationFrame = [locationBar_ frame]; |
| locationFrame.size.width += dX; |
| |
| [locationBar_ stopAnimation]; |
| |
| if (animate) |
| [locationBar_ animateToFrame:locationFrame]; |
| else |
| [locationBar_ setFrame:locationFrame]; |
| } |
| |
| - (NSPoint)bookmarkBubblePoint { |
| if (locationBarView_->IsStarEnabled()) |
| return locationBarView_->GetBookmarkBubblePoint(); |
| |
| // Grab bottom middle of hotdogs. |
| NSRect frame = appMenuButton_.frame; |
| NSPoint point = NSMakePoint(NSMidX(frame), NSMinY(frame)); |
| // Inset to account for the whitespace around the hotdogs. |
| point.y += app_menu_controller::kAppMenuBubblePointOffsetY; |
| return [self.view convertPoint:point toView:nil]; |
| } |
| |
| - (NSPoint)managePasswordsBubblePoint { |
| return locationBarView_->GetManagePasswordsBubblePoint(); |
| } |
| |
| - (NSPoint)saveCreditCardBubblePoint { |
| return locationBarView_->GetSaveCreditCardBubblePoint(); |
| } |
| |
| - (NSPoint)translateBubblePoint { |
| return locationBarView_->GetTranslateBubblePoint(); |
| } |
| |
| - (CGFloat)baseToolbarHeight { |
| // Height of the toolbar in pixels when the bookmark bar is closed. |
| const bool kIsModeMaterial = ui::MaterialDesignController::IsModeMaterial(); |
| const CGFloat kBaseToolbarHeightNormal = kIsModeMaterial ? 37 : 35; |
| |
| // Not all lines are drawn at 2x normal height when running on Retina, which |
| // causes the toolbar controls to be visually 1pt too high within the toolbar |
| // area. It's not possible to adjust the control y-positions by 0.5pt and have |
| // them appear 0.5pt lower (they are still drawn at their original locations), |
| // so instead shave off 1pt from the bottom of the toolbar. Note that there's |
| // an offsetting change in -[BookmarkBarController preferredHeight] to |
| // maintain the proper spacing between bookmark icons and toolbar items. See |
| // https://crbug.com/326245 . |
| const CGFloat kLineWidth = [[self view] cr_lineWidth]; |
| const BOOL kIsRetina = (kLineWidth < 1); |
| BOOL reduceHeight = NO; |
| |
| // Only adjust the height if Retina and not Material Design. |
| reduceHeight = kIsRetina && !kIsModeMaterial; |
| |
| return reduceHeight ? kBaseToolbarHeightNormal - 1 |
| : kBaseToolbarHeightNormal; |
| } |
| |
| - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight { |
| // With no toolbar, just ignore the compression. |
| if (!hasToolbar_) |
| return NSHeight([locationBar_ frame]); |
| |
| return [self baseToolbarHeight] - compressByHeight; |
| } |
| |
| - (void)setDividerOpacity:(CGFloat)opacity { |
| ToolbarView* toolbarView = [self toolbarView]; |
| [toolbarView setShowsDivider:(opacity > 0 ? YES : NO)]; |
| [toolbarView setDividerOpacity:opacity]; |
| [toolbarView setNeedsDisplay:YES]; |
| } |
| |
| - (BrowserActionsController*)browserActionsController { |
| return browserActionsController_.get(); |
| } |
| |
| - (NSView*)appMenuButton { |
| return appMenuButton_; |
| } |
| |
| - (AppMenuController*)appMenuController { |
| return appMenuController_.get(); |
| } |
| |
| - (BOOL)isLocationBarFocused { |
| OmniboxEditModel* model = locationBarView_->GetOmniboxView()->model(); |
| return model->has_focus(); |
| } |
| |
| // (URLDropTargetController protocol) |
| - (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point { |
| // TODO(viettrungluu): This code is more or less copied from the code in |
| // |TabStripController|. I'll refactor this soon to make it common and expand |
| // its capabilities (e.g., allow text DnD). |
| if ([urls count] < 1) { |
| NOTREACHED(); |
| return; |
| } |
| |
| // TODO(viettrungluu): dropping multiple URLs? |
| if ([urls count] > 1) |
| NOTIMPLEMENTED(); |
| |
| // Get the first URL and fix it up. |
| GURL url(url_formatter::FixupURL( |
| base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string())); |
| |
| // Security: Sanitize text to prevent self-XSS. |
| if (url.SchemeIs(url::kJavaScriptScheme)) { |
| browser_->window()->GetLocationBar()->GetOmniboxView()->SetUserText( |
| OmniboxView::StripJavascriptSchemas(base::UTF8ToUTF16(url.spec()))); |
| return; |
| } |
| |
| OpenURLParams params(url, Referrer(), WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false); |
| browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params); |
| } |
| |
| // (URLDropTargetController protocol) |
| - (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point { |
| // TODO(viettrungluu): This code is more or less copied from the code in |
| // |TabStripController|. I'll refactor this soon to make it common and expand |
| // its capabilities (e.g., allow text DnD). |
| |
| // If the input is plain text, classify the input and make the URL. |
| AutocompleteMatch match; |
| AutocompleteClassifierFactory::GetForProfile(browser_->profile())->Classify( |
| base::SysNSStringToUTF16(text), false, false, |
| metrics::OmniboxEventProto::BLANK, &match, NULL); |
| GURL url(match.destination_url); |
| |
| // Security: Block JavaScript to prevent self-XSS. |
| if (url.SchemeIs(url::kJavaScriptScheme)) |
| return; |
| |
| OpenURLParams params(url, Referrer(), WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false); |
| browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params); |
| } |
| |
| // (URLDropTargetController protocol) |
| - (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point { |
| // Do nothing. |
| } |
| |
| // (URLDropTargetController protocol) |
| - (void)hideDropURLsIndicatorInView:(NSView*)view { |
| // Do nothing. |
| } |
| |
| // (URLDropTargetController protocol) |
| - (BOOL)isUnsupportedDropData:(id<NSDraggingInfo>)info { |
| return drag_util::IsUnsupportedDropData(profile_, info); |
| } |
| |
| @end |