Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: chrome/browser/ui/cocoa/toolbar_controller.mm

Issue 6326006: [Mac] Organize some files into chrome/browser/ui/cocoa/toolbar/.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/toolbar_controller.h"
6
7 #include <algorithm>
8
9 #include "app/l10n_util.h"
10 #include "app/l10n_util_mac.h"
11 #include "app/mac/nsimage_cache.h"
12 #include "app/resource_bundle.h"
13 #include "base/mac/mac_util.h"
14 #include "base/singleton.h"
15 #include "base/sys_string_conversions.h"
16 #include "chrome/app/chrome_command_ids.h"
17 #include "chrome/browser/autocomplete/autocomplete.h"
18 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
19 #include "chrome/browser/autocomplete/autocomplete_edit_view.h"
20 #include "chrome/browser/autocomplete/autocomplete_match.h"
21 #include "chrome/browser/background_page_tracker.h"
22 #include "chrome/browser/net/url_fixer_upper.h"
23 #include "chrome/browser/prefs/pref_service.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/search_engines/template_url_model.h"
26 #include "chrome/browser/tab_contents/tab_contents.h"
27 #include "chrome/browser/themes/browser_theme_provider.h"
28 #include "chrome/browser/upgrade_detector.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
32 #import "chrome/browser/ui/cocoa/back_forward_menu_controller.h"
33 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
34 #import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
35 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
36 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
37 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
38 #import "chrome/browser/ui/cocoa/gradient_button_cell.h"
39 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
40 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
41 #import "chrome/browser/ui/cocoa/menu_button.h"
42 #import "chrome/browser/ui/cocoa/menu_controller.h"
43 #import "chrome/browser/ui/cocoa/reload_button.h"
44 #import "chrome/browser/ui/cocoa/toolbar_view.h"
45 #import "chrome/browser/ui/cocoa/view_id_util.h"
46 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h"
47 #include "chrome/browser/ui/toolbar/toolbar_model.h"
48 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
49 #include "chrome/common/notification_details.h"
50 #include "chrome/common/notification_observer.h"
51 #include "chrome/common/notification_service.h"
52 #include "chrome/common/notification_type.h"
53 #include "chrome/common/pref_names.h"
54 #include "gfx/rect.h"
55 #include "grit/chromium_strings.h"
56 #include "grit/generated_resources.h"
57 #include "grit/theme_resources.h"
58 #include "ui/base/models/accelerator_cocoa.h"
59 #include "ui/base/models/menu_model.h"
60
61 namespace {
62
63 // Names of images in the bundle for buttons.
64 NSString* const kBackButtonImageName = @"back_Template.pdf";
65 NSString* const kForwardButtonImageName = @"forward_Template.pdf";
66 NSString* const kReloadButtonReloadImageName = @"reload_Template.pdf";
67 NSString* const kReloadButtonStopImageName = @"stop_Template.pdf";
68 NSString* const kHomeButtonImageName = @"home_Template.pdf";
69 NSString* const kWrenchButtonImageName = @"tools_Template.pdf";
70
71 // Height of the toolbar in pixels when the bookmark bar is closed.
72 const CGFloat kBaseToolbarHeight = 35.0;
73
74 // The minimum width of the location bar in pixels.
75 const CGFloat kMinimumLocationBarWidth = 100.0;
76
77 // The duration of any animation that occurs within the toolbar in seconds.
78 const CGFloat kAnimationDuration = 0.2;
79
80 // The amount of left padding that the wrench menu should have.
81 const CGFloat kWrenchMenuLeftPadding = 3.0;
82
83 } // namespace
84
85 @interface ToolbarController(Private)
86 - (void)addAccessibilityDescriptions;
87 - (void)initCommandStatus:(CommandUpdater*)commands;
88 - (void)prefChanged:(std::string*)prefName;
89 - (BackgroundGradientView*)backgroundGradientView;
90 - (void)toolbarFrameChanged;
91 - (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate;
92 - (void)maintainMinimumLocationBarWidth;
93 - (void)adjustBrowserActionsContainerForNewWindow:(NSNotification*)notification;
94 - (void)browserActionsContainerDragged:(NSNotification*)notification;
95 - (void)browserActionsContainerDragFinished:(NSNotification*)notification;
96 - (void)browserActionsVisibilityChanged:(NSNotification*)notification;
97 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate;
98 - (void)badgeWrenchMenuIfNeeded;
99 @end
100
101 namespace ToolbarControllerInternal {
102
103 // A C++ delegate that handles the accelerators in the wrench menu.
104 class WrenchAcceleratorDelegate : public ui::AcceleratorProvider {
105 public:
106 virtual bool GetAcceleratorForCommandId(int command_id,
107 ui::Accelerator* accelerator_generic) {
108 // Downcast so that when the copy constructor is invoked below, the key
109 // string gets copied, too.
110 ui::AcceleratorCocoa* out_accelerator =
111 static_cast<ui::AcceleratorCocoa*>(accelerator_generic);
112 AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
113 const ui::AcceleratorCocoa* accelerator =
114 keymap->GetAcceleratorForCommand(command_id);
115 if (accelerator) {
116 *out_accelerator = *accelerator;
117 return true;
118 }
119 return false;
120 }
121 };
122
123 // A class registered for C++ notifications. This is used to detect changes in
124 // preferences and upgrade available notifications. Bridges the notification
125 // back to the ToolbarController.
126 class NotificationBridge : public NotificationObserver {
127 public:
128 explicit NotificationBridge(ToolbarController* controller)
129 : controller_(controller) {
130 registrar_.Add(this, NotificationType::UPGRADE_RECOMMENDED,
131 NotificationService::AllSources());
132 registrar_.Add(this,
133 NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED,
134 NotificationService::AllSources());
135 }
136
137 // Overridden from NotificationObserver:
138 virtual void Observe(NotificationType type,
139 const NotificationSource& source,
140 const NotificationDetails& details) {
141 switch (type.value) {
142 case NotificationType::PREF_CHANGED:
143 [controller_ prefChanged:Details<std::string>(details).ptr()];
144 break;
145 case NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED:
146 // fall-through
147 case NotificationType::UPGRADE_RECOMMENDED:
148 [controller_ badgeWrenchMenuIfNeeded];
149 break;
150 default:
151 NOTREACHED();
152 }
153 }
154
155 private:
156 ToolbarController* controller_; // weak, owns us
157
158 NotificationRegistrar registrar_;
159 };
160
161 } // namespace ToolbarControllerInternal
162
163 @implementation ToolbarController
164
165 - (id)initWithModel:(ToolbarModel*)model
166 commands:(CommandUpdater*)commands
167 profile:(Profile*)profile
168 browser:(Browser*)browser
169 resizeDelegate:(id<ViewResizer>)resizeDelegate
170 nibFileNamed:(NSString*)nibName {
171 DCHECK(model && commands && profile && [nibName length]);
172 if ((self = [super initWithNibName:nibName
173 bundle:base::mac::MainAppBundle()])) {
174 toolbarModel_ = model;
175 commands_ = commands;
176 profile_ = profile;
177 browser_ = browser;
178 resizeDelegate_ = resizeDelegate;
179 hasToolbar_ = YES;
180 hasLocationBar_ = YES;
181
182 // Register for notifications about state changes for the toolbar buttons
183 commandObserver_.reset(new CommandObserverBridge(self, commands));
184 commandObserver_->ObserveCommand(IDC_BACK);
185 commandObserver_->ObserveCommand(IDC_FORWARD);
186 commandObserver_->ObserveCommand(IDC_RELOAD);
187 commandObserver_->ObserveCommand(IDC_HOME);
188 commandObserver_->ObserveCommand(IDC_BOOKMARK_PAGE);
189 }
190 return self;
191 }
192
193 - (id)initWithModel:(ToolbarModel*)model
194 commands:(CommandUpdater*)commands
195 profile:(Profile*)profile
196 browser:(Browser*)browser
197 resizeDelegate:(id<ViewResizer>)resizeDelegate {
198 if ((self = [self initWithModel:model
199 commands:commands
200 profile:profile
201 browser:browser
202 resizeDelegate:resizeDelegate
203 nibFileNamed:@"Toolbar"])) {
204 }
205 return self;
206 }
207
208
209 - (void)dealloc {
210 // Unset ViewIDs of toolbar elements.
211 // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
212 // |browserActionsContainerView_| are handled by themselves.
213 view_id_util::UnsetID(backButton_);
214 view_id_util::UnsetID(forwardButton_);
215 view_id_util::UnsetID(homeButton_);
216 view_id_util::UnsetID(wrenchButton_);
217
218 // Make sure any code in the base class which assumes [self view] is
219 // the "parent" view continues to work.
220 hasToolbar_ = YES;
221 hasLocationBar_ = YES;
222
223 [[NSNotificationCenter defaultCenter] removeObserver:self];
224
225 if (trackingArea_.get())
226 [[self view] removeTrackingArea:trackingArea_.get()];
227 [super dealloc];
228 }
229
230 // Called after the view is done loading and the outlets have been hooked up.
231 // Now we can hook up bridges that rely on UI objects such as the location
232 // bar and button state.
233 - (void)awakeFromNib {
234 // A bug in AppKit (<rdar://7298597>, <http://openradar.me/7298597>) causes
235 // images loaded directly from nibs in a framework to not get their "template"
236 // flags set properly. Thus, despite the images being set on the buttons in
237 // the xib, we must set them in code.
238 [backButton_ setImage:app::mac::GetCachedImageWithName(kBackButtonImageName)];
239 [forwardButton_ setImage:
240 app::mac::GetCachedImageWithName(kForwardButtonImageName)];
241 [reloadButton_ setImage:
242 app::mac::GetCachedImageWithName(kReloadButtonReloadImageName)];
243 [homeButton_ setImage:
244 app::mac::GetCachedImageWithName(kHomeButtonImageName)];
245 [wrenchButton_ setImage:
246 app::mac::GetCachedImageWithName(kWrenchButtonImageName)];
247 [self badgeWrenchMenuIfNeeded];
248
249 [wrenchButton_ setOpenMenuOnClick:YES];
250
251 [backButton_ setShowsBorderOnlyWhileMouseInside:YES];
252 [forwardButton_ setShowsBorderOnlyWhileMouseInside:YES];
253 [reloadButton_ setShowsBorderOnlyWhileMouseInside:YES];
254 [homeButton_ setShowsBorderOnlyWhileMouseInside:YES];
255 [wrenchButton_ setShowsBorderOnlyWhileMouseInside:YES];
256
257 [self initCommandStatus:commands_];
258 locationBarView_.reset(new LocationBarViewMac(locationBar_,
259 commands_, toolbarModel_,
260 profile_, browser_));
261 [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
262 // Register pref observers for the optional home and page/options buttons
263 // and then add them to the toolbar based on those prefs.
264 notificationBridge_.reset(
265 new ToolbarControllerInternal::NotificationBridge(self));
266 PrefService* prefs = profile_->GetPrefs();
267 showHomeButton_.Init(prefs::kShowHomeButton, prefs,
268 notificationBridge_.get());
269 showPageOptionButtons_.Init(prefs::kShowPageOptionsButtons, prefs,
270 notificationBridge_.get());
271 [self showOptionalHomeButton];
272 [self installWrenchMenu];
273
274 // Create the controllers for the back/forward menus.
275 backMenuController_.reset([[BackForwardMenuController alloc]
276 initWithBrowser:browser_
277 modelType:BACK_FORWARD_MENU_TYPE_BACK
278 button:backButton_]);
279 forwardMenuController_.reset([[BackForwardMenuController alloc]
280 initWithBrowser:browser_
281 modelType:BACK_FORWARD_MENU_TYPE_FORWARD
282 button:forwardButton_]);
283
284 // For a popup window, the toolbar is really just a location bar
285 // (see override for [ToolbarController view], below). When going
286 // fullscreen, we remove the toolbar controller's view from the view
287 // hierarchy. Calling [locationBar_ removeFromSuperview] when going
288 // fullscreen causes it to get released, making us unhappy
289 // (http://crbug.com/18551). We avoid the problem by incrementing
290 // the retain count of the location bar; use of the scoped object
291 // helps us remember to release it.
292 locationBarRetainer_.reset([locationBar_ retain]);
293 trackingArea_.reset(
294 [[NSTrackingArea alloc] initWithRect:NSZeroRect // Ignored
295 options:NSTrackingMouseMoved |
296 NSTrackingInVisibleRect |
297 NSTrackingMouseEnteredAndExited |
298 NSTrackingActiveAlways
299 owner:self
300 userInfo:nil]);
301 NSView* toolbarView = [self view];
302 [toolbarView addTrackingArea:trackingArea_.get()];
303
304 // If the user has any Browser Actions installed, the container view for them
305 // may have to be resized depending on the width of the toolbar frame.
306 [toolbarView setPostsFrameChangedNotifications:YES];
307 [[NSNotificationCenter defaultCenter]
308 addObserver:self
309 selector:@selector(toolbarFrameChanged)
310 name:NSViewFrameDidChangeNotification
311 object:toolbarView];
312
313 // Set ViewIDs for toolbar elements which don't have their dedicated class.
314 // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
315 // |browserActionsContainerView_| are handled by themselves.
316 view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON);
317 view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON);
318 view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON);
319 view_id_util::SetID(wrenchButton_, VIEW_ID_APP_MENU);
320
321 [self addAccessibilityDescriptions];
322 }
323
324 - (void)addAccessibilityDescriptions {
325 // Set accessibility descriptions. http://openradar.appspot.com/7496255
326 NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK);
327 [[backButton_ cell]
328 accessibilitySetOverrideValue:description
329 forAttribute:NSAccessibilityDescriptionAttribute];
330 description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD);
331 [[forwardButton_ cell]
332 accessibilitySetOverrideValue:description
333 forAttribute:NSAccessibilityDescriptionAttribute];
334 description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD);
335 [[reloadButton_ cell]
336 accessibilitySetOverrideValue:description
337 forAttribute:NSAccessibilityDescriptionAttribute];
338 description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME);
339 [[homeButton_ cell]
340 accessibilitySetOverrideValue:description
341 forAttribute:NSAccessibilityDescriptionAttribute];
342 description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION);
343 [[locationBar_ cell]
344 accessibilitySetOverrideValue:description
345 forAttribute:NSAccessibilityDescriptionAttribute];
346 description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP);
347 [[wrenchButton_ cell]
348 accessibilitySetOverrideValue:description
349 forAttribute:NSAccessibilityDescriptionAttribute];
350 }
351
352 - (void)mouseExited:(NSEvent*)theEvent {
353 [[hoveredButton_ cell] setMouseInside:NO animate:YES];
354 [hoveredButton_ release];
355 hoveredButton_ = nil;
356 }
357
358 - (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent {
359 NSButton* targetView = (NSButton*)[[self view]
360 hitTest:[theEvent locationInWindow]];
361
362 // Only interpret the view as a hoverButton_ if it's both button and has a
363 // button cell that cares. GradientButtonCell derived cells care.
364 if (([targetView isKindOfClass:[NSButton class]]) &&
365 ([[targetView cell]
366 respondsToSelector:@selector(setMouseInside:animate:)]))
367 return targetView;
368 return nil;
369 }
370
371 - (void)mouseMoved:(NSEvent*)theEvent {
372 NSButton* targetView = [self hoverButtonForEvent:theEvent];
373 if (hoveredButton_ != targetView) {
374 [[hoveredButton_ cell] setMouseInside:NO animate:YES];
375 [[targetView cell] setMouseInside:YES animate:YES];
376 [hoveredButton_ release];
377 hoveredButton_ = [targetView retain];
378 }
379 }
380
381 - (void)mouseEntered:(NSEvent*)event {
382 [self mouseMoved:event];
383 }
384
385 - (LocationBarViewMac*)locationBarBridge {
386 return locationBarView_.get();
387 }
388
389 - (void)focusLocationBar:(BOOL)selectAll {
390 if (locationBarView_.get())
391 locationBarView_->FocusLocation(selectAll ? true : false);
392 }
393
394 // Called when the state for a command changes to |enabled|. Update the
395 // corresponding UI element.
396 - (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
397 NSButton* button = nil;
398 switch (command) {
399 case IDC_BACK:
400 button = backButton_;
401 break;
402 case IDC_FORWARD:
403 button = forwardButton_;
404 break;
405 case IDC_HOME:
406 button = homeButton_;
407 break;
408 }
409 [button setEnabled:enabled];
410 }
411
412 // Init the enabled state of the buttons on the toolbar to match the state in
413 // the controller.
414 - (void)initCommandStatus:(CommandUpdater*)commands {
415 [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
416 [forwardButton_
417 setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
418 [reloadButton_ setEnabled:YES];
419 [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
420 }
421
422 - (void)updateToolbarWithContents:(TabContents*)tab
423 shouldRestoreState:(BOOL)shouldRestore {
424 locationBarView_->Update(tab, shouldRestore ? true : false);
425
426 [locationBar_ updateCursorAndToolTipRects];
427
428 if (browserActionsController_.get()) {
429 [browserActionsController_ update];
430 }
431 }
432
433 - (void)setStarredState:(BOOL)isStarred {
434 locationBarView_->SetStarred(isStarred ? true : false);
435 }
436
437 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
438 [reloadButton_ setIsLoading:isLoading force:force];
439 }
440
441 - (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar {
442 [self view]; // Force nib loading.
443
444 hasToolbar_ = toolbar;
445
446 // If there's a toolbar, there must be a location bar.
447 DCHECK((toolbar && locBar) || !toolbar);
448 hasLocationBar_ = toolbar ? YES : locBar;
449
450 // Decide whether to hide/show based on whether there's a location bar.
451 [[self view] setHidden:!hasLocationBar_];
452
453 // Make location bar not editable when in a pop-up.
454 locationBarView_->SetEditable(toolbar);
455 }
456
457 - (NSView*)view {
458 if (hasToolbar_)
459 return [super view];
460 return locationBar_;
461 }
462
463 // (Private) Returns the backdrop to the toolbar.
464 - (BackgroundGradientView*)backgroundGradientView {
465 // We really do mean |[super view]|; see our override of |-view|.
466 DCHECK([[super view] isKindOfClass:[BackgroundGradientView class]]);
467 return (BackgroundGradientView*)[super view];
468 }
469
470 - (id)customFieldEditorForObject:(id)obj {
471 if (obj == locationBar_) {
472 // Lazilly construct Field editor, Cocoa UI code always runs on the
473 // same thread, so there shoudn't be a race condition here.
474 if (autocompleteTextFieldEditor_.get() == nil) {
475 autocompleteTextFieldEditor_.reset(
476 [[AutocompleteTextFieldEditor alloc] init]);
477 }
478
479 // This needs to be called every time, otherwise notifications
480 // aren't sent correctly.
481 DCHECK(autocompleteTextFieldEditor_.get());
482 [autocompleteTextFieldEditor_.get() setFieldEditor:YES];
483 return autocompleteTextFieldEditor_.get();
484 }
485 return nil;
486 }
487
488 // Returns an array of views in the order of the outlets above.
489 - (NSArray*)toolbarViews {
490 return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_,
491 homeButton_, wrenchButton_, locationBar_,
492 browserActionsContainerView_, nil];
493 }
494
495 // Moves |rect| to the right by |delta|, keeping the right side fixed by
496 // shrinking the width to compensate. Passing a negative value for |deltaX|
497 // moves to the left and increases the width.
498 - (NSRect)adjustRect:(NSRect)rect byAmount:(CGFloat)deltaX {
499 NSRect frame = NSOffsetRect(rect, deltaX, 0);
500 frame.size.width -= deltaX;
501 return frame;
502 }
503
504 // Show or hide the home button based on the pref.
505 - (void)showOptionalHomeButton {
506 // Ignore this message if only showing the URL bar.
507 if (!hasToolbar_)
508 return;
509 BOOL hide = showHomeButton_.GetValue() ? NO : YES;
510 if (hide == [homeButton_ isHidden])
511 return; // Nothing to do, view state matches pref state.
512
513 // Always shift the text field by the width of the home button minus one pixel
514 // since the frame edges of each button are right on top of each other. When
515 // hiding the button, reverse the direction of the movement (to the left).
516 CGFloat moveX = [homeButton_ frame].size.width - 1.0;
517 if (hide)
518 moveX *= -1; // Reverse the direction of the move.
519
520 [locationBar_ setFrame:[self adjustRect:[locationBar_ frame]
521 byAmount:moveX]];
522 [homeButton_ setHidden:hide];
523 }
524
525 // Install the menu wrench buttons. Calling this repeatedly is inexpensive so it
526 // can be done every time the buttons are shown.
527 - (void)installWrenchMenu {
528 if (wrenchMenuModel_.get())
529 return;
530 acceleratorDelegate_.reset(
531 new ToolbarControllerInternal::WrenchAcceleratorDelegate());
532
533 wrenchMenuModel_.reset(new WrenchMenuModel(
534 acceleratorDelegate_.get(), browser_));
535 [wrenchMenuController_ setModel:wrenchMenuModel_.get()];
536 [wrenchMenuController_ setUseWithPopUpButtonCell:YES];
537 [wrenchButton_ setAttachedMenu:[wrenchMenuController_ menu]];
538 }
539
540 - (WrenchMenuController*)wrenchMenuController {
541 return wrenchMenuController_;
542 }
543
544 - (void)badgeWrenchMenuIfNeeded {
545
546 int badgeResource = 0;
547 if (UpgradeDetector::GetInstance()->notify_upgrade()) {
548 badgeResource = IDR_UPDATE_BADGE;
549 } else if (BackgroundPageTracker::GetInstance()->
550 GetUnacknowledgedBackgroundPageCount() > 0) {
551 badgeResource = IDR_BACKGROUND_BADGE;
552 } else {
553 // No badge - clear the badge if one is already set.
554 if ([[wrenchButton_ cell] overlayImage])
555 [[wrenchButton_ cell] setOverlayImage:nil];
556 return;
557 }
558
559 NSImage* badge =
560 ResourceBundle::GetSharedInstance().GetNativeImageNamed(badgeResource);
561 NSImage* wrenchImage =
562 app::mac::GetCachedImageWithName(kWrenchButtonImageName);
563 NSSize wrenchImageSize = [wrenchImage size];
564 NSSize badgeSize = [badge size];
565
566 scoped_nsobject<NSImage> overlayImage(
567 [[NSImage alloc] initWithSize:wrenchImageSize]);
568
569 // Draw badge in the upper right corner of the button.
570 NSPoint overlayPosition =
571 NSMakePoint(wrenchImageSize.width - badgeSize.width,
572 wrenchImageSize.height - badgeSize.height);
573
574 [overlayImage lockFocus];
575 [badge drawAtPoint:overlayPosition
576 fromRect:NSZeroRect
577 operation:NSCompositeSourceOver
578 fraction:1.0];
579 [overlayImage unlockFocus];
580
581 [[wrenchButton_ cell] setOverlayImage:overlayImage];
582 }
583
584 - (void)prefChanged:(std::string*)prefName {
585 if (!prefName) return;
586 if (*prefName == prefs::kShowHomeButton) {
587 [self showOptionalHomeButton];
588 }
589 }
590
591 - (void)createBrowserActionButtons {
592 if (!browserActionsController_.get()) {
593 browserActionsController_.reset([[BrowserActionsController alloc]
594 initWithBrowser:browser_
595 containerView:browserActionsContainerView_]);
596 [[NSNotificationCenter defaultCenter]
597 addObserver:self
598 selector:@selector(browserActionsContainerDragged:)
599 name:kBrowserActionGrippyDraggingNotification
600 object:browserActionsController_];
601 [[NSNotificationCenter defaultCenter]
602 addObserver:self
603 selector:@selector(browserActionsContainerDragFinished:)
604 name:kBrowserActionGrippyDragFinishedNotification
605 object:browserActionsController_];
606 [[NSNotificationCenter defaultCenter]
607 addObserver:self
608 selector:@selector(browserActionsVisibilityChanged:)
609 name:kBrowserActionVisibilityChangedNotification
610 object:browserActionsController_];
611 [[NSNotificationCenter defaultCenter]
612 addObserver:self
613 selector:@selector(adjustBrowserActionsContainerForNewWindow:)
614 name:NSWindowDidBecomeKeyNotification
615 object:[[self view] window]];
616 }
617 CGFloat containerWidth = [browserActionsContainerView_ isHidden] ? 0.0 :
618 NSWidth([browserActionsContainerView_ frame]);
619 if (containerWidth > 0.0)
620 [self adjustLocationSizeBy:(containerWidth * -1) animate:NO];
621 }
622
623 - (void)adjustBrowserActionsContainerForNewWindow:
624 (NSNotification*)notification {
625 [self toolbarFrameChanged];
626 [[NSNotificationCenter defaultCenter]
627 removeObserver:self
628 name:NSWindowDidBecomeKeyNotification
629 object:[[self view] window]];
630 }
631
632 - (void)browserActionsContainerDragged:(NSNotification*)notification {
633 CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
634 locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
635 [browserActionsContainerView_ setCanDragLeft:!locationBarAtMinSize_];
636 [browserActionsContainerView_ setGrippyPinned:locationBarAtMinSize_];
637 [self adjustLocationSizeBy:
638 [browserActionsContainerView_ resizeDeltaX] animate:NO];
639 }
640
641 - (void)browserActionsContainerDragFinished:(NSNotification*)notification {
642 [browserActionsController_ resizeContainerAndAnimate:YES];
643 [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:YES];
644 }
645
646 - (void)browserActionsVisibilityChanged:(NSNotification*)notification {
647 [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
648 }
649
650 - (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate {
651 CGFloat locationBarXPos = NSMaxX([locationBar_ frame]);
652 CGFloat leftDistance;
653
654 if ([browserActionsContainerView_ isHidden]) {
655 CGFloat edgeXPos = [wrenchButton_ frame].origin.x;
656 leftDistance = edgeXPos - locationBarXPos - kWrenchMenuLeftPadding;
657 } else {
658 NSRect containerFrame = animate ?
659 [browserActionsContainerView_ animationEndFrame] :
660 [browserActionsContainerView_ frame];
661
662 leftDistance = containerFrame.origin.x - locationBarXPos;
663 }
664 if (leftDistance != 0.0)
665 [self adjustLocationSizeBy:leftDistance animate:animate];
666 }
667
668 - (void)maintainMinimumLocationBarWidth {
669 CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
670 locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
671 if (locationBarAtMinSize_) {
672 CGFloat dX = kMinimumLocationBarWidth - locationBarWidth;
673 [self adjustLocationSizeBy:dX animate:NO];
674 }
675 }
676
677 - (void)toolbarFrameChanged {
678 // Do nothing if the frame changes but no Browser Action Controller is
679 // present.
680 if (!browserActionsController_.get())
681 return;
682
683 [self maintainMinimumLocationBarWidth];
684
685 if (locationBarAtMinSize_) {
686 // Once the grippy is pinned, leave it until it is explicity un-pinned.
687 [browserActionsContainerView_ setGrippyPinned:YES];
688 NSRect containerFrame = [browserActionsContainerView_ frame];
689 // Determine how much the container needs to move in case it's overlapping
690 // with the location bar.
691 CGFloat dX = NSMaxX([locationBar_ frame]) - containerFrame.origin.x;
692 containerFrame = NSOffsetRect(containerFrame, dX, 0);
693 containerFrame.size.width -= dX;
694 [browserActionsContainerView_ setFrame:containerFrame];
695 } else if (!locationBarAtMinSize_ &&
696 [browserActionsContainerView_ grippyPinned]) {
697 // Expand out the container until it hits the saved size, then unpin the
698 // grippy.
699 // Add 0.1 pixel so that it doesn't hit the minimum width codepath above.
700 CGFloat dX = NSWidth([locationBar_ frame]) -
701 (kMinimumLocationBarWidth + 0.1);
702 NSRect containerFrame = [browserActionsContainerView_ frame];
703 containerFrame = NSOffsetRect(containerFrame, -dX, 0);
704 containerFrame.size.width += dX;
705 CGFloat savedContainerWidth = [browserActionsController_ savedWidth];
706 if (NSWidth(containerFrame) >= savedContainerWidth) {
707 containerFrame = NSOffsetRect(containerFrame,
708 NSWidth(containerFrame) - savedContainerWidth, 0);
709 containerFrame.size.width = savedContainerWidth;
710 [browserActionsContainerView_ setGrippyPinned:NO];
711 }
712 [browserActionsContainerView_ setFrame:containerFrame];
713 [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
714 }
715 }
716
717 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
718 // Ensure that the location bar is in its proper place.
719 NSRect locationFrame = [locationBar_ frame];
720 locationFrame.size.width += dX;
721
722 if (!animate) {
723 [locationBar_ setFrame:locationFrame];
724 return;
725 }
726
727 [NSAnimationContext beginGrouping];
728 [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
729 [[locationBar_ animator] setFrame:locationFrame];
730 [NSAnimationContext endGrouping];
731 }
732
733 - (NSPoint)bookmarkBubblePoint {
734 return locationBarView_->GetBookmarkBubblePoint();
735 }
736
737 - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight {
738 // With no toolbar, just ignore the compression.
739 return hasToolbar_ ? kBaseToolbarHeight - compressByHeight :
740 NSHeight([locationBar_ frame]);
741 }
742
743 - (void)setDividerOpacity:(CGFloat)opacity {
744 BackgroundGradientView* view = [self backgroundGradientView];
745 [view setShowsDivider:(opacity > 0 ? YES : NO)];
746
747 // We may not have a toolbar view (e.g., popup windows only have a location
748 // bar).
749 if ([view isKindOfClass:[ToolbarView class]]) {
750 ToolbarView* toolbarView = (ToolbarView*)view;
751 [toolbarView setDividerOpacity:opacity];
752 }
753 }
754
755 - (BrowserActionsController*)browserActionsController {
756 return browserActionsController_.get();
757 }
758
759 // (URLDropTargetController protocol)
760 - (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
761 // TODO(viettrungluu): This code is more or less copied from the code in
762 // |TabStripController|. I'll refactor this soon to make it common and expand
763 // its capabilities (e.g., allow text DnD).
764 if ([urls count] < 1) {
765 NOTREACHED();
766 return;
767 }
768
769 // TODO(viettrungluu): dropping multiple URLs?
770 if ([urls count] > 1)
771 NOTIMPLEMENTED();
772
773 // Get the first URL and fix it up.
774 GURL url(URLFixerUpper::FixupURL(
775 base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
776
777 browser_->GetSelectedTabContents()->OpenURL(url, GURL(), CURRENT_TAB,
778 PageTransition::TYPED);
779 }
780
781 // (URLDropTargetController protocol)
782 - (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point {
783 // TODO(viettrungluu): This code is more or less copied from the code in
784 // |TabStripController|. I'll refactor this soon to make it common and expand
785 // its capabilities (e.g., allow text DnD).
786
787 // If the input is plain text, classify the input and make the URL.
788 AutocompleteMatch match;
789 browser_->profile()->GetAutocompleteClassifier()->Classify(
790 base::SysNSStringToWide(text),
791 std::wstring(), false, &match, NULL);
792 GURL url(match.destination_url);
793
794 browser_->GetSelectedTabContents()->OpenURL(url, GURL(), CURRENT_TAB,
795 PageTransition::TYPED);
796 }
797
798 // (URLDropTargetController protocol)
799 - (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
800 // Do nothing.
801 }
802
803 // (URLDropTargetController protocol)
804 - (void)hideDropURLsIndicatorInView:(NSView*)view {
805 // Do nothing.
806 }
807
808 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/toolbar_controller.h ('k') | chrome/browser/ui/cocoa/toolbar_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698