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 |