Chromium Code Reviews| Index: chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.mm |
| diff --git a/chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.mm b/chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..00f2af20372139d1c3c3abc0aa938c4c3eef04e1 |
| --- /dev/null |
| +++ b/chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.mm |
| @@ -0,0 +1,243 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.h" |
| + |
| +#include "base/mac/foundation_util.h" |
| +#include "base/mac/scoped_nsobject.h" |
| +#include "base/strings/sys_string_conversions.h" |
| +#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h" |
| +#include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h" |
| +#import "chrome/browser/ui/cocoa/base_bubble_controller.h" |
| +#import "chrome/browser/ui/cocoa/hyperlink_text_view.h" |
| +#import "chrome/browser/ui/cocoa/info_bubble_view.h" |
| +#import "chrome/browser/ui/cocoa/info_bubble_window.h" |
| +#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" |
| +#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" |
| +#include "content/public/browser/web_contents_view.h" |
| +#include "skia/ext/skia_utils_mac.h" |
| +#include "ui/base/cocoa/window_size_constants.h" |
| +#include "ui/native_theme/native_theme.h" |
| + |
| +using autofill::GeneratedCreditCardBubbleCocoa; |
| + |
| +namespace { |
| + |
| +const CGFloat kTitlePadding = 20.0; |
| +const CGFloat kInset = 20.0; |
| + |
| +} // namespace |
| + |
| +// The Cocoa side of the bubble controller. |
| +@interface GeneratedCreditCardBubbleControllerCocoa : |
| + BaseBubbleController<NSTextViewDelegate> { |
| + |
| + // Bridge to C++ side. Owned. |
|
Scott Hess - ex-Googler
2013/11/04 21:20:55
Owned is implicit in the scoped_ptr<>, I think.
groby-ooo-7-16
2013/11/04 22:02:06
Done.
|
| + scoped_ptr<GeneratedCreditCardBubbleCocoa> bridge_; |
| +} |
| + |
| +- (id)initWithParentWindow:(NSWindow*)parentWindow |
| + bridge:(GeneratedCreditCardBubbleCocoa*)bridge; |
| + |
| +// Show the bubble at the given |anchor| point. Coordinates are in screen space. |
| +- (void)showAtAnchor:(NSPoint)anchor; |
| + |
| +// Return true if the bubble is in the process of hiding. |
| +- (BOOL)isHiding; |
| + |
| +// Build the window contents and lay them out. |
| +- (void)performLayoutWithController: |
| + (autofill::GeneratedCreditCardBubbleController*)controller; |
| + |
| +@end |
| + |
| + |
| +@implementation GeneratedCreditCardBubbleControllerCocoa |
| + |
| +- (id)initWithParentWindow:(NSWindow*)parentWindow |
| + bridge:(GeneratedCreditCardBubbleCocoa*)bridge { |
| + DCHECK(bridge); |
| + base::scoped_nsobject<InfoBubbleWindow> window( |
| + [[InfoBubbleWindow alloc] |
| + initWithContentRect:ui::kWindowSizeDeterminedLater |
| + styleMask:NSBorderlessWindowMask |
| + backing:NSBackingStoreBuffered |
| + defer:NO]); |
| + if ((self = [super initWithWindow:window |
| + parentWindow:parentWindow |
| + anchoredAt:NSZeroPoint])) { |
| + [window setCanBecomeKeyWindow:NO]; |
| + bridge_.reset(bridge); |
| + |
| + ui::NativeTheme* nativeTheme = ui::NativeTheme::instance(); |
| + [[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; |
| + [[self bubble] setArrowLocation:info_bubble::kTopRight]; |
| + [[self bubble] setBackgroundColor: |
| + gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor( |
| + ui::NativeTheme::kColorId_DialogBackground))]; |
| + [self performLayoutWithController:bridge->controller().get()]; |
| + } |
| + return self; |
| +} |
| + |
| +- (void)windowWillClose:(NSNotification*)notification { |
| + bridge_->OnBubbleClosing(); |
| + [super windowWillClose:notification]; |
| +} |
| + |
| +// Called when embedded links are clicked. |
| +- (BOOL)textView:(NSTextView*)textView |
| + clickedOnLink:(id)link |
| + atIndex:(NSUInteger)charIndex { |
| + bridge_->OnLinkClicked(); |
| + return YES; |
| +} |
| + |
| +- (void)showAtAnchor:(NSPoint)anchorPoint { |
| + [self setAnchorPoint:anchorPoint]; |
| + [self showWindow:nil]; |
| +} |
| + |
| +- (BOOL)isHiding { |
| + InfoBubbleWindow* window = |
| + base::mac::ObjCCastStrict<InfoBubbleWindow>([self window]); |
| + return [window isClosing]; |
| +} |
| + |
| + |
| +- (void)performLayoutWithController: |
| + (autofill::GeneratedCreditCardBubbleController*)controller { |
| + CGFloat bubbleWidth = autofill::GeneratedCreditCardBubbleView::kContentsWidth; |
| + |
| + // Build the bubble title. |
| + NSFont* titleFont = [NSFont systemFontOfSize:15.0]; |
| + NSString* title = base::SysUTF16ToNSString(controller->TitleText()); |
| + base::scoped_nsobject<NSTextField> titleView( |
| + [[NSTextField alloc] initWithFrame:NSZeroRect]); |
| + [titleView setDrawsBackground:NO]; |
| + [titleView setBezeled:NO]; |
| + [titleView setEditable:NO]; |
| + [titleView setSelectable:NO]; |
| + [titleView setStringValue:title]; |
| + [titleView setFont:titleFont]; |
| + [titleView sizeToFit]; |
| + |
| + bubbleWidth = std::max(bubbleWidth, NSWidth([titleView frame]) + 2 * kInset); |
| + |
| + // Build the contents view. |
| + base::scoped_nsobject<HyperlinkTextView> contentsView( |
| + [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]); |
| + |
| + [contentsView setEditable:NO]; |
| + [contentsView setDelegate:self]; |
| + |
| + NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSize]]; |
| + NSFont* boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]; |
| + [contentsView setMessage:base::SysUTF16ToNSString(controller->ContentsText()) |
| + withFont:font |
| + messageColor:[NSColor blackColor]]; |
| + |
| + const std::vector<autofill::TextRange>& text_ranges = |
| + controller->ContentsTextRanges(); |
| + for (size_t i = 0; i < text_ranges.size(); ++i) { |
| + NSRange range = text_ranges[i].range.ToNSRange(); |
| + if (text_ranges[i].is_link) { |
| + [contentsView addLinkRange:range |
| + withName:@(i) |
| + linkColor:[NSColor blueColor]]; |
| + } else { |
| + [[contentsView textStorage] |
| + addAttributes:@{ NSFontAttributeName : boldFont } |
| + range:range]; |
| + } |
| + } |
| + |
| + [contentsView setVerticallyResizable:YES]; |
| + [contentsView setFrameSize:NSMakeSize(bubbleWidth - 2 * kInset, CGFLOAT_MAX)]; |
| + [contentsView sizeToFit]; |
|
Scott Hess - ex-Googler
2013/11/04 21:20:55
Looks much more sensible.
|
| + |
| + // Sizes are computed, now lay out the individual parts. |
| + [contentsView setFrameOrigin:NSMakePoint(kInset, kInset)]; |
| + [titleView setFrameOrigin: |
| + NSMakePoint(kInset, NSMaxY([contentsView frame]) + kTitlePadding)]; |
| + [[[self window] contentView] setSubviews:@[ contentsView, titleView ]]; |
| + |
| + // Update window frame. |
| + NSRect windowFrame = [[self window] frame]; |
| + windowFrame.size = |
| + NSMakeSize(bubbleWidth, NSMaxY([titleView frame]) + kInset); |
| + [[self window] setFrame:windowFrame display:YES]; |
| +} |
| + |
| +@end |
| + |
| + |
| +namespace autofill { |
| + |
| +// static |
| +base::WeakPtr<GeneratedCreditCardBubbleView> |
| + GeneratedCreditCardBubbleView::Create( |
| + const base::WeakPtr<GeneratedCreditCardBubbleController>& controller) { |
| + return (new GeneratedCreditCardBubbleCocoa(controller))->weak_ptr_factory_. |
| + GetWeakPtr(); |
| +} |
| + |
| +GeneratedCreditCardBubbleCocoa::GeneratedCreditCardBubbleCocoa( |
| + const base::WeakPtr<GeneratedCreditCardBubbleController>& controller) |
| + : bubbleController_(nil), |
| + controller_(controller), |
| + weak_ptr_factory_(this) { |
| +} |
| + |
| +GeneratedCreditCardBubbleCocoa::~GeneratedCreditCardBubbleCocoa() {} |
| + |
| +void GeneratedCreditCardBubbleCocoa::Show() { |
| + DCHECK(controller_.get()); |
| + NSView* browser_view = |
| + controller_->web_contents()->GetView()->GetNativeView(); |
| + NSWindow* parent_window = [browser_view window]; |
| + LocationBarViewMac* location_bar = |
| + [[parent_window windowController] locationBarBridge]; |
| + |
| + // |location_bar| can be NULL during initialization stages. |
| + if (!location_bar) |
| + return; |
|
Scott Hess - ex-Googler
2013/11/04 21:20:55
Does this case just leak?
groby-ooo-7-16
2013/11/04 22:02:06
Crap. It probably does. It should never happen (Sh
|
| + |
| + if (!bubbleController_) { |
| + bubbleController_ = [[GeneratedCreditCardBubbleControllerCocoa alloc] |
| + initWithParentWindow:parent_window |
| + bridge:this]; |
| + } |
| + |
| + // |bubbleController_| is supposed to take ownership of |this|. If it can't be |
| + // constructed, clean up and abort showing. |
| + if (!bubbleController_) { |
| + delete this; |
| + return; |
| + } |
| + |
| + NSRect frame = NSZeroRect; |
| + frame.origin = location_bar->GetGeneratedCreditCardBubblePoint(); |
| + NSPoint anchor = [parent_window convertRectToScreen:frame].origin; |
| + [bubbleController_ showAtAnchor:anchor]; |
| +} |
| + |
| +void GeneratedCreditCardBubbleCocoa::Hide() { |
| + [bubbleController_ close]; |
| +} |
| + |
| +bool GeneratedCreditCardBubbleCocoa::IsHiding() const { |
| + return [bubbleController_ isHiding]; |
| +} |
| + |
| +void GeneratedCreditCardBubbleCocoa::OnBubbleClosing() { |
| + bubbleController_ = nil; |
| +} |
| + |
| +void GeneratedCreditCardBubbleCocoa::OnLinkClicked() { |
| + if (controller_) |
| + controller_->OnLinkClicked(); |
| +} |
| + |
| +} // autofill |