OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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/website_settings/chooser_bubble_ui_cocoa.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cmath> | |
9 #include <vector> | |
10 | |
11 #include "base/mac/scoped_nsobject.h" | |
12 #include "base/strings/sys_string_conversions.h" | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/browser/ui/browser_finder.h" | |
16 #include "chrome/browser/ui/browser_window.h" | |
17 #import "chrome/browser/ui/chrome_style.h" | |
18 #import "chrome/browser/ui/cocoa/base_bubble_controller.h" | |
19 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
20 #import "chrome/browser/ui/cocoa/browser_window_utils.h" | |
21 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" | |
22 #import "chrome/browser/ui/cocoa/hover_close_button.h" | |
23 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | |
24 #import "chrome/browser/ui/cocoa/info_bubble_window.h" | |
25 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" | |
26 #include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" | |
27 #include "chrome/grit/generated_resources.h" | |
28 #include "content/public/browser/native_web_keyboard_event.h" | |
29 #include "ui/base/cocoa/window_size_constants.h" | |
30 #include "ui/base/l10n/l10n_util_mac.h" | |
31 | |
32 namespace { | |
33 | |
34 // Chooser bubble width. | |
35 const CGFloat kChooserBubbleWidth = 320.0f; | |
36 | |
37 // Chooser bubble height. | |
38 const CGFloat kChooserBubbleHeight = 220.0f; | |
39 | |
40 // Distance between the bubble border and the view that is closest to the | |
41 // border. | |
42 const CGFloat kMarginX = 20.0f; | |
43 const CGFloat kMarginY = 20.0f; | |
44 | |
45 // Distance between two views inside the bubble. | |
46 const CGFloat kHorizontalPadding = 10.0f; | |
47 const CGFloat kVerticalPadding = 10.0f; | |
48 | |
49 const CGFloat kTitlePaddingX = 50.0f; | |
50 } | |
51 | |
52 scoped_ptr<BubbleUi> ChooserBubbleDelegate::BuildBubbleUi() { | |
53 return make_scoped_ptr(new ChooserBubbleUiCocoa(browser_, this)); | |
54 } | |
55 | |
56 @interface ChooserBubbleUiController | |
57 : BaseBubbleController<NSTableViewDataSource, NSTableViewDelegate> { | |
58 @private | |
59 // Bridge to the C++ class that created this object. | |
60 ChooserBubbleUiCocoa* bridge_; | |
61 | |
62 base::scoped_nsobject<NSTextField> titleView_; | |
63 base::scoped_nsobject<NSButton> closeButton_; | |
64 base::scoped_nsobject<NSScrollView> scrollView_; | |
65 base::scoped_nsobject<NSTableColumn> tableColumn_; | |
66 base::scoped_nsobject<NSTableView> tableView_; | |
67 base::scoped_nsobject<NSButton> connectButton_; | |
68 base::scoped_nsobject<NSButton> cancelButton_; | |
69 | |
70 Browser* browser_; // Weak. | |
71 ChooserBubbleDelegate* chooser_bubble_delegate_; // Weak. | |
72 } | |
73 | |
74 // Designated initializer. |browser| and |bridge| must both be non-nil. | |
75 - (id)initWithBrowser:(Browser*)browser | |
76 initWithChooserBubbleDelegate: | |
77 (ChooserBubbleDelegate*)chooser_bubble_delegate | |
78 bridge:(ChooserBubbleUiCocoa*)bridge; | |
79 | |
80 // Makes the bubble visible. | |
81 - (void)show; | |
82 | |
83 // Will reposition the bubble based in case the anchor or parent should change. | |
84 - (void)updateAnchorPosition; | |
85 | |
86 // Will calculate the expected anchor point for this bubble. | |
87 // Should only be used outside this class for tests. | |
88 - (NSPoint)getExpectedAnchorPoint; | |
89 | |
90 // Returns true of the browser has support for the location bar. | |
palmer
2015/12/10 23:26:10
Typo: "true if"
juncai
2015/12/11 20:39:46
Done.
| |
91 // Should only be used outside this class for tests. | |
92 - (bool)hasLocationBar; | |
93 | |
94 // Update table view when chooser options were initialized. | |
palmer
2015/12/10 23:26:10
Nit: This one and those below: "Updates |tableView
juncai
2015/12/11 20:39:46
Done.
| |
95 - (void)onOptionsInitialized; | |
96 | |
97 // Update table view when chooser option was added. | |
98 - (void)onOptionAdded:(NSInteger)index; | |
99 | |
100 // Update table view when chooser option was removed. | |
101 - (void)onOptionRemoved:(NSInteger)index; | |
102 | |
103 // Update table view when chooser options changed. | |
104 - (void)updateTableView; | |
105 | |
106 // Determines if the bubble has an anchor in a corner or no anchor at all. | |
107 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation; | |
108 | |
109 // Returns the expected parent for this bubble. | |
110 - (NSWindow*)getExpectedParentWindow; | |
111 | |
112 // Creates the title for the bubble. | |
113 - (base::scoped_nsobject<NSTextField>)bubbleTitle; | |
114 | |
115 // Creates the "close" button. | |
116 - (base::scoped_nsobject<NSButton>)closeButton; | |
117 | |
118 // Creates a button with |title| and |action|. | |
119 - (base::scoped_nsobject<NSButton>)buttonWithTitle:(NSString*)title | |
120 action:(SEL)action; | |
121 | |
122 // Creates the "Connect" button. | |
123 - (base::scoped_nsobject<NSButton>)connectButton; | |
124 | |
125 // Creates the "Cancel" button. | |
126 - (base::scoped_nsobject<NSButton>)cancelButton; | |
127 | |
128 // Called when the 'Connect' button is pressed. | |
palmer
2015/12/10 23:26:10
Nit: Consistently use either double or single quot
juncai
2015/12/11 20:39:46
Done.
| |
129 - (void)onConnect:(id)sender; | |
130 | |
131 // Called when the 'Cancel' button is pressed. | |
132 - (void)onCancel:(id)sender; | |
133 | |
134 // Called when the 'close' button is pressed. | |
135 - (void)onClose:(id)sender; | |
136 | |
137 @end | |
138 | |
139 @implementation ChooserBubbleUiController | |
140 | |
141 - (id)initWithBrowser:(Browser*)browser | |
142 initWithChooserBubbleDelegate: | |
143 (ChooserBubbleDelegate*)chooser_bubble_delegate | |
144 bridge:(ChooserBubbleUiCocoa*)bridge { | |
145 DCHECK(browser); | |
palmer
2015/12/10 23:26:10
According to the documentation, |browser| and |bri
juncai
2015/12/11 20:39:46
Done.
| |
146 DCHECK(chooser_bubble_delegate); | |
147 DCHECK(bridge); | |
148 browser_ = browser; | |
149 chooser_bubble_delegate_ = chooser_bubble_delegate; | |
150 | |
151 base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc] | |
152 initWithContentRect:ui::kWindowSizeDeterminedLater | |
153 styleMask:NSBorderlessWindowMask | |
154 backing:NSBackingStoreBuffered | |
155 defer:NO]); | |
156 [window setAllowedAnimations:info_bubble::kAnimateNone]; | |
157 [window setReleasedWhenClosed:NO]; | |
158 if ((self = [super initWithWindow:window | |
159 parentWindow:[self getExpectedParentWindow] | |
160 anchoredAt:NSZeroPoint])) { | |
161 [self setShouldCloseOnResignKey:NO]; | |
162 [self setShouldOpenAsKeyWindow:YES]; | |
163 [[self bubble] setArrowLocation:[self getExpectedArrowLocation]]; | |
164 bridge_ = bridge; | |
165 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
166 [center addObserver:self | |
167 selector:@selector(parentWindowDidMove:) | |
168 name:NSWindowDidMoveNotification | |
169 object:[self getExpectedParentWindow]]; | |
170 } | |
171 return self; | |
172 } | |
173 | |
174 - (void)windowWillClose:(NSNotification*)notification { | |
175 bridge_->OnBubbleClosing(); | |
176 [super windowWillClose:notification]; | |
177 } | |
178 | |
179 - (void)parentWindowWillToggleFullScreen:(NSNotification*)notification { | |
180 // Override the base class implementation, which would have closed the bubble. | |
181 } | |
182 | |
183 - (void)parentWindowDidResize:(NSNotification*)notification { | |
184 DCHECK(bridge_); | |
palmer
2015/12/10 23:26:10
Are these DCHECKs redundant, given the checks in t
juncai
2015/12/11 20:39:46
Done.
| |
185 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
186 } | |
187 | |
188 - (void)parentWindowDidMove:(NSNotification*)notification { | |
189 DCHECK(bridge_); | |
190 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
191 } | |
192 | |
193 - (void)show { | |
194 NSView* view = [[self window] contentView]; | |
195 [view setSubviews:@[]]; | |
196 | |
197 // ------------------------------------ | |
198 // | Chooser bubble title x | | |
199 // | -------------------------------- | | |
200 // | | option 0 | | | |
201 // | | option 1 | | | |
202 // | | option 2 | | | |
203 // | | | | | |
204 // | | | | | |
205 // | | | | | |
206 // | -------------------------------- | | |
207 // | [ Connect] [ Cancel ] | | |
208 // ------------------------------------ | |
209 | |
210 // Determine the dimensions of the bubble. | |
211 // Once the height and width are set, the buttons and permission menus can | |
212 // be laid out correctly. | |
213 NSRect bubbleFrame = | |
214 NSMakeRect(0, 0, kChooserBubbleWidth, kChooserBubbleHeight); | |
215 | |
216 // Create the views. | |
217 // Title. | |
218 titleView_ = [self bubbleTitle]; | |
219 CGFloat titleOriginX = kMarginX; | |
220 CGFloat titleHeight = NSHeight([titleView_ frame]); | |
221 CGFloat titleOriginY = kChooserBubbleHeight - kMarginY - titleHeight; | |
222 [titleView_ setFrameOrigin:NSMakePoint(titleOriginX, titleOriginY)]; | |
223 [view addSubview:titleView_]; | |
224 | |
225 // Close button. | |
226 // 'x' button in the upper-right-hand corner. | |
palmer
2015/12/10 23:26:10
Do we need an X button, given that we also have Ca
juncai
2015/12/11 20:39:46
Done.
| |
227 closeButton_ = [self closeButton]; | |
228 CGFloat closeButtonOriginX = | |
229 kChooserBubbleWidth - kMarginX - NSWidth([closeButton_ frame]); | |
230 CGFloat closeButtonOriginY = | |
231 kChooserBubbleHeight - kMarginY - NSHeight([closeButton_ frame]); | |
232 [closeButton_ | |
233 setFrameOrigin:NSMakePoint(closeButtonOriginX, closeButtonOriginY)]; | |
234 [view addSubview:closeButton_]; | |
235 | |
236 // Connect button. | |
237 connectButton_ = [self connectButton]; | |
238 // Cancel button. | |
239 cancelButton_ = [self cancelButton]; | |
240 CGFloat connectButtonWidth = NSWidth([connectButton_ frame]); | |
241 CGFloat connectButtonHeight = NSHeight([connectButton_ frame]); | |
242 CGFloat cancelButtonWidth = NSWidth([cancelButton_ frame]); | |
243 | |
244 // ScollView embedding with TableView. | |
245 CGFloat scrollViewWidth = kChooserBubbleWidth - 2 * kMarginX; | |
246 CGFloat scrollViewHeight = kChooserBubbleHeight - 2 * kMarginY - | |
247 2 * kVerticalPadding - titleHeight - | |
248 connectButtonHeight; | |
249 NSRect scrollFrame = | |
250 NSMakeRect(kMarginX, kMarginY + connectButtonHeight + kVerticalPadding, | |
251 scrollViewWidth, scrollViewHeight); | |
252 scrollView_.reset([[NSScrollView alloc] initWithFrame:scrollFrame]); | |
253 [scrollView_ setBorderType:NSBezelBorder]; | |
254 [scrollView_ setHasVerticalScroller:YES]; | |
255 [scrollView_ setHasHorizontalScroller:YES]; | |
256 [scrollView_ setAutohidesScrollers:YES]; | |
257 | |
258 // TableView. | |
259 tableView_.reset([[NSTableView alloc] initWithFrame:NSZeroRect]); | |
260 tableColumn_.reset([[NSTableColumn alloc] initWithIdentifier:@""]); | |
261 [tableView_ addTableColumn:tableColumn_]; | |
262 [tableView_ setDelegate:self]; | |
263 [tableView_ setDataSource:self]; | |
264 // Make the column title invisible. | |
265 [tableView_ setHeaderView:nil]; | |
266 [tableView_ setFocusRingType:NSFocusRingTypeNone]; | |
267 | |
268 [scrollView_ setDocumentView:tableView_]; | |
269 [view addSubview:scrollView_]; | |
270 | |
271 // Set connect button and cancel button to the right place. | |
272 CGFloat connectButtonOriginX = kChooserBubbleWidth - kMarginX - | |
273 kHorizontalPadding - connectButtonWidth - | |
274 cancelButtonWidth; | |
275 CGFloat connectButtonOriginY = kMarginY; | |
276 [connectButton_ | |
277 setFrameOrigin:NSMakePoint(connectButtonOriginX, connectButtonOriginY)]; | |
278 [connectButton_ setEnabled:NO]; | |
279 [view addSubview:connectButton_]; | |
280 | |
281 CGFloat cancelButtonOriginX = | |
282 kChooserBubbleWidth - kMarginX - cancelButtonWidth; | |
283 CGFloat cancelButtonOriginY = kMarginY; | |
284 [cancelButton_ | |
285 setFrameOrigin:NSMakePoint(cancelButtonOriginX, cancelButtonOriginY)]; | |
286 [view addSubview:cancelButton_]; | |
287 | |
288 bubbleFrame = [[self window] frameRectForContentRect:bubbleFrame]; | |
289 if ([[self window] isVisible]) { | |
290 // Unfortunately, calling -setFrame followed by -setFrameOrigin (called | |
291 // within -setAnchorPoint) causes flickering. Avoid the flickering by | |
292 // manually adjusting the new frame's origin so that the top left stays the | |
293 // same, and only calling -setFrame. | |
294 NSRect currentWindowFrame = [[self window] frame]; | |
295 bubbleFrame.origin = currentWindowFrame.origin; | |
296 bubbleFrame.origin.y = bubbleFrame.origin.y + | |
297 currentWindowFrame.size.height - | |
298 bubbleFrame.size.height; | |
299 [[self window] setFrame:bubbleFrame display:YES]; | |
300 } else { | |
301 [[self window] setFrame:bubbleFrame display:NO]; | |
302 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
303 [self showWindow:nil]; | |
304 [[self window] makeFirstResponder:nil]; | |
305 [[self window] setInitialFirstResponder:connectButton_.get()]; | |
306 } | |
307 } | |
308 | |
309 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { | |
310 const std::vector<base::string16>& device_names = | |
311 chooser_bubble_delegate_->GetOptions(); | |
312 if (device_names.empty()) { | |
313 return 1; | |
314 } else { | |
315 return static_cast<NSInteger>(device_names.size()); | |
316 } | |
317 } | |
318 | |
319 - (id)tableView:(NSTableView*)tableView | |
320 objectValueForTableColumn:(NSTableColumn*)tableColumn | |
321 row:(NSInteger)rowIndex { | |
322 const std::vector<base::string16>& device_names = | |
323 chooser_bubble_delegate_->GetOptions(); | |
324 if (device_names.empty()) { | |
325 DCHECK(rowIndex == 0); | |
326 return l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); | |
327 } else { | |
328 if (rowIndex >= 0 && rowIndex < static_cast<int>(device_names.size())) { | |
palmer
2015/12/10 23:26:10
int nit: should be static_cast<NSInteger>.
juncai
2015/12/11 20:39:46
Done.
| |
329 return base::SysUTF16ToNSString(device_names[rowIndex]); | |
330 } else { | |
331 return @""; | |
332 } | |
333 } | |
334 } | |
335 | |
336 - (BOOL)tableView:(NSTableView*)aTableView | |
337 shouldEditTableColumn:(NSTableColumn*)aTableColumn | |
338 row:(NSInteger)rowIndex { | |
339 return NO; | |
340 } | |
341 | |
342 - (void)onOptionsInitialized { | |
343 [self updateTableView]; | |
344 } | |
345 | |
346 - (void)onOptionAdded:(NSInteger)index { | |
347 [self updateTableView]; | |
348 } | |
349 | |
350 - (void)onOptionRemoved:(NSInteger)index { | |
351 // Table view will automatically selects the next item if the current | |
352 // item is removed, so here it tracks if the removed item is the item | |
353 // that was previously selected, if so, deselect it. | |
354 if ([tableView_ selectedRow] == index) | |
355 [tableView_ deselectRow:index]; | |
356 | |
357 [self updateTableView]; | |
358 } | |
359 | |
360 - (void)updateTableView { | |
361 const std::vector<base::string16>& device_names = | |
362 chooser_bubble_delegate_->GetOptions(); | |
363 [tableView_ setEnabled:!device_names.empty()]; | |
364 | |
365 CGFloat tableColumnWidth = 0.0f; | |
366 if (device_names.empty()) { | |
367 [tableView_ setEnabled:NO]; | |
368 NSString* text = | |
369 l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); | |
370 CGSize textSize = [text sizeWithAttributes:@{ | |
371 NSFontAttributeName : [NSFont systemFontOfSize:[NSFont systemFontSize]] | |
372 }]; | |
373 tableColumnWidth = textSize.width; | |
374 } else { | |
375 [tableView_ setEnabled:YES]; | |
376 for (const auto& device_name : device_names) { | |
377 NSString* text = base::SysUTF16ToNSString(device_name); | |
378 CGSize textSize = [text sizeWithAttributes:@{ | |
379 NSFontAttributeName : [NSFont systemFontOfSize:[NSFont systemFontSize]] | |
380 }]; | |
381 tableColumnWidth = std::max(tableColumnWidth, textSize.width); | |
382 } | |
383 } | |
384 [tableColumn_ setWidth:tableColumnWidth]; | |
385 | |
386 [tableView_ reloadData]; | |
387 } | |
388 | |
389 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification { | |
390 [connectButton_ setEnabled:[tableView_ numberOfSelectedRows] > 0]; | |
391 } | |
392 | |
393 - (void)updateAnchorPosition { | |
394 [self setParentWindow:[self getExpectedParentWindow]]; | |
395 [self setAnchorPoint:[self getExpectedAnchorPoint]]; | |
396 } | |
397 | |
398 - (NSPoint)getExpectedAnchorPoint { | |
399 NSPoint anchor; | |
400 if ([self hasLocationBar]) { | |
401 LocationBarViewMac* location_bar = | |
402 [[[self getExpectedParentWindow] windowController] locationBarBridge]; | |
403 anchor = location_bar->GetPageInfoBubblePoint(); | |
404 } else { | |
405 // Center the bubble if there's no location bar. | |
406 NSRect contentFrame = [[[self getExpectedParentWindow] contentView] frame]; | |
407 anchor = NSMakePoint(NSMidX(contentFrame), NSMaxY(contentFrame)); | |
408 } | |
409 | |
410 return [[self getExpectedParentWindow] convertBaseToScreen:anchor]; | |
411 } | |
412 | |
413 - (bool)hasLocationBar { | |
414 return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); | |
415 } | |
416 | |
417 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation { | |
418 return [self hasLocationBar] ? info_bubble::kTopLeft : info_bubble::kNoArrow; | |
419 } | |
420 | |
421 - (NSWindow*)getExpectedParentWindow { | |
422 DCHECK(browser_->window()); | |
423 return browser_->window()->GetNativeWindow(); | |
424 } | |
425 | |
426 - (base::scoped_nsobject<NSTextField>)bubbleTitle { | |
427 base::scoped_nsobject<NSTextField> titleView( | |
428 [[NSTextField alloc] initWithFrame:NSZeroRect]); | |
429 [titleView setDrawsBackground:NO]; | |
430 [titleView setBezeled:NO]; | |
431 [titleView setEditable:NO]; | |
432 [titleView setSelectable:NO]; | |
433 [titleView setStringValue:l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_PROMPT)]; | |
434 [titleView setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; | |
435 [titleView sizeToFit]; | |
436 NSRect titleFrame = [titleView frame]; | |
437 [titleView setFrameSize:NSMakeSize(NSWidth(titleFrame) + kTitlePaddingX, | |
438 NSHeight(titleFrame))]; | |
439 return titleView; | |
440 } | |
441 | |
442 - (base::scoped_nsobject<NSButton>)closeButton { | |
443 int dimension = chrome_style::GetCloseButtonSize(); | |
444 NSRect frame = NSMakeRect(0, 0, dimension, dimension); | |
445 base::scoped_nsobject<NSButton> button( | |
446 [[WebUIHoverCloseButton alloc] initWithFrame:frame]); | |
447 [button setAction:@selector(onClose:)]; | |
448 [button setTarget:self]; | |
449 return button; | |
450 } | |
451 | |
452 - (base::scoped_nsobject<NSButton>)buttonWithTitle:(NSString*)title | |
453 action:(SEL)action { | |
454 base::scoped_nsobject<NSButton> button( | |
455 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | |
456 [button setButtonType:NSMomentaryPushInButton]; | |
457 [button setTitle:title]; | |
458 [button setTarget:self]; | |
459 [button setAction:action]; | |
460 [button sizeToFit]; | |
461 return button; | |
462 } | |
463 | |
464 - (base::scoped_nsobject<NSButton>)connectButton { | |
465 NSString* connectTitle = | |
466 l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_CONNECT_BUTTON_TEXT); | |
467 return [self buttonWithTitle:connectTitle action:@selector(onConnect:)]; | |
468 } | |
469 | |
470 - (base::scoped_nsobject<NSButton>)cancelButton { | |
471 NSString* cancelTitle = | |
472 l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_CANCEL_BUTTON_TEXT); | |
473 return [self buttonWithTitle:cancelTitle action:@selector(onCancel:)]; | |
474 } | |
475 | |
476 + (CGFloat)matchWidthsOf:(NSView*)viewA andOf:(NSView*)viewB { | |
477 NSRect frameA = [viewA frame]; | |
478 NSRect frameB = [viewB frame]; | |
479 CGFloat width = std::max(NSWidth(frameA), NSWidth(frameB)); | |
480 [viewA setFrameSize:NSMakeSize(width, NSHeight(frameA))]; | |
481 [viewB setFrameSize:NSMakeSize(width, NSHeight(frameB))]; | |
482 return width; | |
483 } | |
484 | |
485 + (void)alignCenterOf:(NSView*)viewA verticallyToCenterOf:(NSView*)viewB { | |
486 NSRect frameA = [viewA frame]; | |
487 NSRect frameB = [viewB frame]; | |
488 frameA.origin.y = | |
489 NSMinY(frameB) + std::floor((NSHeight(frameB) - NSHeight(frameA)) / 2); | |
490 [viewA setFrameOrigin:frameA.origin]; | |
491 } | |
492 | |
493 - (void)onConnect:(id)sender { | |
494 NSInteger row = [tableView_ selectedRow]; | |
495 chooser_bubble_delegate_->Select(row); | |
496 [self close]; | |
497 } | |
498 | |
499 - (void)onCancel:(id)sender { | |
500 chooser_bubble_delegate_->Cancel(); | |
501 [self close]; | |
502 } | |
503 | |
504 - (void)onClose:(id)sender { | |
505 chooser_bubble_delegate_->Close(); | |
506 [self close]; | |
507 } | |
508 | |
509 @end | |
510 | |
511 ChooserBubbleUiCocoa::ChooserBubbleUiCocoa( | |
512 Browser* browser, | |
513 ChooserBubbleDelegate* chooser_bubble_delegate) | |
514 : browser_(browser), | |
515 chooser_bubble_delegate_(chooser_bubble_delegate), | |
516 chooser_bubble_ui_controller_(nil) { | |
517 DCHECK(browser); | |
518 DCHECK(chooser_bubble_delegate); | |
519 chooser_bubble_delegate_->set_observer(this); | |
520 } | |
521 | |
522 ChooserBubbleUiCocoa::~ChooserBubbleUiCocoa() { | |
523 chooser_bubble_delegate_->set_observer(nullptr); | |
524 if (chooser_bubble_ui_controller_) { | |
525 [chooser_bubble_ui_controller_ close]; | |
526 chooser_bubble_ui_controller_ = nil; | |
527 } | |
528 } | |
529 | |
530 void ChooserBubbleUiCocoa::Show(BubbleReference bubble_reference) { | |
531 if (!chooser_bubble_ui_controller_) { | |
532 chooser_bubble_ui_controller_ = [[ChooserBubbleUiController alloc] | |
533 initWithBrowser:browser_ | |
534 initWithChooserBubbleDelegate:chooser_bubble_delegate_ | |
535 bridge:this]; | |
536 } | |
537 | |
538 [chooser_bubble_ui_controller_ show]; | |
539 [chooser_bubble_ui_controller_ updateTableView]; | |
540 } | |
541 | |
542 void ChooserBubbleUiCocoa::Close() { | |
543 if (chooser_bubble_ui_controller_) { | |
544 [chooser_bubble_ui_controller_ close]; | |
545 chooser_bubble_ui_controller_ = nil; | |
546 } | |
547 } | |
548 | |
549 void ChooserBubbleUiCocoa::UpdateAnchorPosition() { | |
550 [chooser_bubble_ui_controller_ updateAnchorPosition]; | |
551 } | |
552 | |
553 void ChooserBubbleUiCocoa::OnOptionsInitialized() { | |
554 [chooser_bubble_ui_controller_ onOptionsInitialized]; | |
555 } | |
556 | |
557 void ChooserBubbleUiCocoa::OnOptionAdded(int index) { | |
558 [chooser_bubble_ui_controller_ onOptionAdded:index]; | |
559 } | |
560 | |
561 void ChooserBubbleUiCocoa::OnOptionRemoved(int index) { | |
562 [chooser_bubble_ui_controller_ onOptionRemoved:index]; | |
563 } | |
564 | |
565 void ChooserBubbleUiCocoa::OnBubbleClosing() { | |
566 chooser_bubble_ui_controller_ = nil; | |
567 } | |
OLD | NEW |