| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/cocoa/notifications/balloon_controller.h" | |
| 6 | |
| 7 #include "base/mac/bundle_locations.h" | |
| 8 #include "base/mac/mac_util.h" | |
| 9 #include "base/strings/utf_string_conversions.h" | |
| 10 #include "chrome/browser/notifications/balloon.h" | |
| 11 #include "chrome/browser/notifications/desktop_notification_service.h" | |
| 12 #include "chrome/browser/notifications/desktop_notification_service_factory.h" | |
| 13 #include "chrome/browser/notifications/notification.h" | |
| 14 #include "chrome/browser/notifications/notification_options_menu_model.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #import "chrome/browser/ui/cocoa/notifications/balloon_view.h" | |
| 17 #include "chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h" | |
| 18 #include "content/public/browser/render_view_host.h" | |
| 19 #include "content/public/browser/web_contents.h" | |
| 20 #include "grit/generated_resources.h" | |
| 21 #include "grit/theme_resources.h" | |
| 22 #import "ui/base/cocoa/hover_image_button.h" | |
| 23 #import "ui/base/cocoa/menu_controller.h" | |
| 24 #include "ui/base/l10n/l10n_util.h" | |
| 25 #include "ui/base/resource/resource_bundle.h" | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 // Margin, in pixels, between the notification frame and the contents | |
| 30 // of the notification. | |
| 31 const int kTopMargin = 1; | |
| 32 const int kBottomMargin = 2; | |
| 33 const int kLeftMargin = 2; | |
| 34 const int kRightMargin = 2; | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 @interface BalloonController (Private) | |
| 39 - (void)updateTrackingRect; | |
| 40 @end | |
| 41 | |
| 42 @implementation BalloonController | |
| 43 | |
| 44 - (id)initWithBalloon:(Balloon*)balloon { | |
| 45 NSString* nibpath = | |
| 46 [base::mac::FrameworkBundle() pathForResource:@"Notification" | |
| 47 ofType:@"nib"]; | |
| 48 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | |
| 49 balloon_ = balloon; | |
| 50 [self initializeHost]; | |
| 51 menuModel_.reset(new NotificationOptionsMenuModel(balloon)); | |
| 52 menuController_.reset([[MenuController alloc] initWithModel:menuModel_.get() | |
| 53 useWithPopUpButtonCell:NO]); | |
| 54 } | |
| 55 return self; | |
| 56 } | |
| 57 | |
| 58 - (void)awakeFromNib { | |
| 59 DCHECK([self window]); | |
| 60 DCHECK_EQ(self, [[self window] delegate]); | |
| 61 | |
| 62 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 63 [optionsButton_ setDefaultImage: | |
| 64 rb.GetNativeImageNamed(IDR_BALLOON_WRENCH).ToNSImage()]; | |
| 65 [optionsButton_ setHoverImage: | |
| 66 rb.GetNativeImageNamed(IDR_BALLOON_WRENCH_H).ToNSImage()]; | |
| 67 [optionsButton_ setPressedImage: | |
| 68 rb.GetNativeImageNamed(IDR_BALLOON_WRENCH_P).ToNSImage()]; | |
| 69 [[optionsButton_ cell] setHighlightsBy:NSNoCellMask]; | |
| 70 | |
| 71 NSString* sourceLabelText = l10n_util::GetNSStringF( | |
| 72 IDS_NOTIFICATION_BALLOON_SOURCE_LABEL, | |
| 73 balloon_->notification().display_source()); | |
| 74 [originLabel_ setStringValue:sourceLabelText]; | |
| 75 | |
| 76 // This condition is false in unit tests which have no RVH. | |
| 77 if (htmlContents_.get()) { | |
| 78 gfx::NativeView contents = htmlContents_->native_view(); | |
| 79 [contents setFrame:NSMakeRect(kLeftMargin, kTopMargin, 0, 0)]; | |
| 80 [[htmlContainer_ superview] addSubview:contents | |
| 81 positioned:NSWindowBelow | |
| 82 relativeTo:nil]; | |
| 83 } | |
| 84 | |
| 85 // Use the standard close button for a utility window. | |
| 86 closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton | |
| 87 forStyleMask:NSUtilityWindowMask]; | |
| 88 NSRect frame = [closeButton_ frame]; | |
| 89 [closeButton_ setFrame:NSMakeRect(6, 1, frame.size.width, frame.size.height)]; | |
| 90 [closeButton_ setTarget:self]; | |
| 91 [closeButton_ setAction:@selector(closeButtonPressed:)]; | |
| 92 [shelf_ addSubview:closeButton_]; | |
| 93 [self updateTrackingRect]; | |
| 94 | |
| 95 // Set the initial position without animating (the balloon should not | |
| 96 // yet be visible). | |
| 97 DCHECK(![[self window] isVisible]); | |
| 98 NSRect balloon_frame = NSMakeRect(balloon_->GetPosition().x(), | |
| 99 balloon_->GetPosition().y(), | |
| 100 [self desiredTotalWidth], | |
| 101 [self desiredTotalHeight]); | |
| 102 [[self window] setFrame:balloon_frame | |
| 103 display:NO]; | |
| 104 } | |
| 105 | |
| 106 - (void)updateTrackingRect { | |
| 107 if (closeButtonTrackingTag_) | |
| 108 [shelf_ removeTrackingRect:closeButtonTrackingTag_]; | |
| 109 | |
| 110 closeButtonTrackingTag_ = [shelf_ addTrackingRect:[closeButton_ frame] | |
| 111 owner:self | |
| 112 userData:nil | |
| 113 assumeInside:NO]; | |
| 114 } | |
| 115 | |
| 116 - (void) mouseEntered:(NSEvent*)event { | |
| 117 [[closeButton_ cell] setHighlighted:YES]; | |
| 118 } | |
| 119 | |
| 120 - (void) mouseExited:(NSEvent*)event { | |
| 121 [[closeButton_ cell] setHighlighted:NO]; | |
| 122 } | |
| 123 | |
| 124 - (void)closeBalloonNow:(bool)byUser { | |
| 125 if (!balloon_) | |
| 126 return; | |
| 127 [self close]; | |
| 128 if (htmlContents_.get()) | |
| 129 htmlContents_->Shutdown(); | |
| 130 if (balloon_) | |
| 131 balloon_->OnClose(byUser); | |
| 132 balloon_ = NULL; | |
| 133 } | |
| 134 | |
| 135 - (IBAction)optionsButtonPressed:(id)sender { | |
| 136 optionMenuIsActive_ = YES; | |
| 137 [NSMenu popUpContextMenu:[menuController_ menu] | |
| 138 withEvent:[NSApp currentEvent] | |
| 139 forView:optionsButton_]; | |
| 140 optionMenuIsActive_ = NO; | |
| 141 if (delayedClose_) | |
| 142 [self closeBalloonNow: false]; // always by script. | |
| 143 } | |
| 144 | |
| 145 - (IBAction)permissionRevoked:(id)sender { | |
| 146 DesktopNotificationService* service = | |
| 147 DesktopNotificationServiceFactory::GetForProfile(balloon_->profile()); | |
| 148 service->DenyPermission(balloon_->notification().origin_url()); | |
| 149 } | |
| 150 | |
| 151 - (IBAction)closeButtonPressed:(id)sender { | |
| 152 [self closeBalloon:YES]; | |
| 153 [self close]; | |
| 154 } | |
| 155 | |
| 156 - (void)close { | |
| 157 if (closeButtonTrackingTag_) | |
| 158 [shelf_ removeTrackingRect:closeButtonTrackingTag_]; | |
| 159 | |
| 160 [super close]; | |
| 161 } | |
| 162 | |
| 163 - (void)closeBalloon:(bool)byUser { | |
| 164 // Keep alive while user is interacting with popup menu. | |
| 165 // Otherwise the script can close the notification and underlying balloon | |
| 166 // will be destroyed while user select a menu command. | |
| 167 if (!byUser && optionMenuIsActive_) { | |
| 168 delayedClose_ = YES; | |
| 169 return; | |
| 170 } | |
| 171 [self closeBalloonNow: byUser]; | |
| 172 } | |
| 173 | |
| 174 - (void)updateContents { | |
| 175 DCHECK(htmlContents_.get()) << "BalloonView::Update called before Show"; | |
| 176 if (htmlContents_->web_contents()) { | |
| 177 htmlContents_->web_contents()->GetController().LoadURL( | |
| 178 balloon_->notification().content_url(), content::Referrer(), | |
| 179 content::PAGE_TRANSITION_LINK, std::string()); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 - (void)repositionToBalloon { | |
| 184 DCHECK(balloon_); | |
| 185 int x = balloon_->GetPosition().x(); | |
| 186 int y = balloon_->GetPosition().y(); | |
| 187 int w = [self desiredTotalWidth]; | |
| 188 int h = [self desiredTotalHeight]; | |
| 189 | |
| 190 [[self window] setFrame:NSMakeRect(x, y, w, h) | |
| 191 display:YES]; | |
| 192 if (htmlContents_.get()) | |
| 193 htmlContents_->UpdateActualSize(balloon_->content_size()); | |
| 194 } | |
| 195 | |
| 196 // Returns the total width the view should be to accommodate the balloon. | |
| 197 - (int)desiredTotalWidth { | |
| 198 return (balloon_ ? balloon_->content_size().width() : 0) + | |
| 199 kLeftMargin + kRightMargin; | |
| 200 } | |
| 201 | |
| 202 // Returns the total height the view should be to accommodate the balloon. | |
| 203 - (int)desiredTotalHeight { | |
| 204 return (balloon_ ? balloon_->content_size().height() : 0) + | |
| 205 kTopMargin + kBottomMargin + [shelf_ frame].size.height; | |
| 206 } | |
| 207 | |
| 208 // Returns the BalloonHost { | |
| 209 - (BalloonViewHost*) getHost { | |
| 210 return htmlContents_.get(); | |
| 211 } | |
| 212 | |
| 213 // Initializes the renderer host showing the HTML contents. | |
| 214 - (void)initializeHost { | |
| 215 htmlContents_.reset(new BalloonViewHost(balloon_)); | |
| 216 htmlContents_->Init(); | |
| 217 } | |
| 218 | |
| 219 // NSWindowDelegate notification. | |
| 220 - (void)windowWillClose:(NSNotification*)notif { | |
| 221 [self autorelease]; | |
| 222 } | |
| 223 | |
| 224 @end | |
| OLD | NEW |