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