1 // Copyright 2013 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.
5 #include "chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.h"
7 #include "base/mac/foundation_util.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
11 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h"
12 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
13 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
14 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
15 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
16 #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
17 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
18 #include "skia/ext/skia_utils_mac.h"
19 #include "ui/base/cocoa/window_size_constants.h"
20 #include "ui/native_theme/native_theme.h"
22 using autofill::GeneratedCreditCardBubbleCocoa;
26 const CGFloat kTitlePadding = 20.0;
27 const CGFloat kInset = 20.0;
31 // The Cocoa side of the bubble controller.
32 @interface GeneratedCreditCardBubbleControllerCocoa :
33 BaseBubbleController<NSTextViewDelegate> {
35 // Bridge to C++ side.
36 scoped_ptr<GeneratedCreditCardBubbleCocoa> bridge_;
39 - (id)initWithParentWindow:(NSWindow*)parentWindow
40 bridge:(GeneratedCreditCardBubbleCocoa*)bridge;
42 // Show the bubble at the given |anchor| point. Coordinates are in screen space.
43 - (void)showAtAnchor:(NSPoint)anchor;
45 // Return true if the bubble is in the process of hiding.
48 // Build the window contents and lay them out.
49 - (void)performLayoutWithController:
50 (autofill::GeneratedCreditCardBubbleController*)controller;
55 @implementation GeneratedCreditCardBubbleControllerCocoa
57 - (id)initWithParentWindow:(NSWindow*)parentWindow
58 bridge:(GeneratedCreditCardBubbleCocoa*)bridge {
60 base::scoped_nsobject<InfoBubbleWindow> window(
61 [[InfoBubbleWindow alloc]
62 initWithContentRect:ui::kWindowSizeDeterminedLater
63 styleMask:NSBorderlessWindowMask
64 backing:NSBackingStoreBuffered
66 if ((self = [super initWithWindow:window
67 parentWindow:parentWindow
68 anchoredAt:NSZeroPoint])) {
69 [window setCanBecomeKeyWindow:NO];
70 bridge_.reset(bridge);
72 ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
73 [[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
74 [[self bubble] setArrowLocation:info_bubble::kTopRight];
75 [[self bubble] setBackgroundColor:
76 gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
77 ui::NativeTheme::kColorId_DialogBackground))];
78 [self performLayoutWithController:bridge->controller().get()];
83 - (void)windowWillClose:(NSNotification*)notification {
84 bridge_->OnBubbleClosing();
85 [super windowWillClose:notification];
88 // Called when embedded links are clicked.
89 - (BOOL)textView:(NSTextView*)textView
90 clickedOnLink:(id)link
91 atIndex:(NSUInteger)charIndex {
92 bridge_->OnLinkClicked();
96 - (void)showAtAnchor:(NSPoint)anchorPoint {
97 [self setAnchorPoint:anchorPoint];
98 [self showWindow:nil];
102 InfoBubbleWindow* window =
103 base::mac::ObjCCastStrict<InfoBubbleWindow>([self window]);
104 return [window isClosing];
108 - (void)performLayoutWithController:
109 (autofill::GeneratedCreditCardBubbleController*)controller {
110 CGFloat bubbleWidth = autofill::GeneratedCreditCardBubbleView::kContentsWidth;
112 // Build the bubble title.
113 NSFont* titleFont = [NSFont systemFontOfSize:15.0];
114 NSString* title = base::SysUTF16ToNSString(controller->TitleText());
115 base::scoped_nsobject<NSTextField> titleView(
116 [[NSTextField alloc] initWithFrame:NSZeroRect]);
117 [titleView setDrawsBackground:NO];
118 [titleView setBezeled:NO];
119 [titleView setEditable:NO];
120 [titleView setSelectable:NO];
121 [titleView setStringValue:title];
122 [titleView setFont:titleFont];
123 [titleView sizeToFit];
125 bubbleWidth = std::max(bubbleWidth, NSWidth([titleView frame]) + 2 * kInset);
127 // Build the contents view.
128 base::scoped_nsobject<HyperlinkTextView> contentsView(
129 [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
131 [contentsView setEditable:NO];
132 [contentsView setDelegate:self];
134 NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
135 NSFont* boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
136 [contentsView setMessage:base::SysUTF16ToNSString(controller->ContentsText())
138 messageColor:[NSColor blackColor]];
140 const std::vector<autofill::TextRange>& text_ranges =
141 controller->ContentsTextRanges();
142 for (size_t i = 0; i < text_ranges.size(); ++i) {
143 NSRange range = text_ranges[i].range.ToNSRange();
144 if (text_ranges[i].is_link) {
145 [contentsView addLinkRange:range
147 linkColor:[NSColor blueColor]];
149 [[contentsView textStorage]
150 addAttributes:@{ NSFontAttributeName : boldFont }
155 [contentsView setVerticallyResizable:YES];
156 [contentsView setFrameSize:NSMakeSize(bubbleWidth - 2 * kInset, CGFLOAT_MAX)];
157 [contentsView sizeToFit];
159 // Sizes are computed, now lay out the individual parts.
160 [contentsView setFrameOrigin:NSMakePoint(kInset, kInset)];
161 [titleView setFrameOrigin:
162 NSMakePoint(kInset, NSMaxY([contentsView frame]) + kTitlePadding)];
163 [[[self window] contentView] setSubviews:@[ contentsView, titleView ]];
165 // Update window frame.
166 NSRect windowFrame = [[self window] frame];
168 NSMakeSize(bubbleWidth, NSMaxY([titleView frame]) + kInset);
169 [[self window] setFrame:windowFrame display:YES];
178 base::WeakPtr<GeneratedCreditCardBubbleView>
179 GeneratedCreditCardBubbleView::Create(
180 const base::WeakPtr<GeneratedCreditCardBubbleController>& controller) {
181 return (new GeneratedCreditCardBubbleCocoa(controller))->weak_ptr_factory_.
185 GeneratedCreditCardBubbleCocoa::GeneratedCreditCardBubbleCocoa(
186 const base::WeakPtr<GeneratedCreditCardBubbleController>& controller)
187 : bubbleController_(nil),
188 controller_(controller),
189 weak_ptr_factory_(this) {
192 GeneratedCreditCardBubbleCocoa::~GeneratedCreditCardBubbleCocoa() {}
194 void GeneratedCreditCardBubbleCocoa::Show() {
195 DCHECK(controller_.get());
196 NSView* browser_view =
197 controller_->web_contents()->GetNativeView();
198 NSWindow* parent_window = [browser_view window];
199 LocationBarViewMac* location_bar =
200 [[parent_window windowController] locationBarBridge];
202 // |location_bar| can be NULL during initialization stages.
204 // Technically, Show() should never be called during initialization.
211 if (!bubbleController_) {
212 bubbleController_ = [[GeneratedCreditCardBubbleControllerCocoa alloc]
213 initWithParentWindow:parent_window
217 // |bubbleController_| is supposed to take ownership of |this|. If it can't be
218 // constructed, clean up and abort showing.
219 if (!bubbleController_) {
224 NSPoint anchor = location_bar->GetGeneratedCreditCardBubblePoint();
225 [bubbleController_ showAtAnchor:[parent_window convertBaseToScreen:anchor]];
228 void GeneratedCreditCardBubbleCocoa::Hide() {
229 [bubbleController_ close];
232 bool GeneratedCreditCardBubbleCocoa::IsHiding() const {
233 return [bubbleController_ isHiding];
236 void GeneratedCreditCardBubbleCocoa::OnBubbleClosing() {
237 bubbleController_ = nil;
240 void GeneratedCreditCardBubbleCocoa::OnLinkClicked() {
242 controller_->OnLinkClicked();