Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / autofill / new_credit_card_bubble_cocoa.mm
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.
4
5 #include "chrome/browser/ui/cocoa/autofill/new_credit_card_bubble_cocoa.h"
6
7 #include "base/i18n/rtl.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/ui/autofill/new_credit_card_bubble_controller.h"
11 #include "chrome/browser/ui/browser_finder.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
14 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
15 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
16 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
17 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
18 #include "content/public/browser/web_contents.h"
19 #include "skia/ext/skia_utils_mac.h"
20 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
21 #include "ui/base/cocoa/window_size_constants.h"
22 #include "ui/native_theme/native_theme.h"
23
24 namespace {
25
26 const CGFloat kWrenchBubblePointOffsetY = 6;
27 const CGFloat kVerticalSpacing = 8;
28 const CGFloat kHorizontalSpacing = 4;
29 const CGFloat kInset = 20.0;
30 const CGFloat kTitleSpacing = 15;
31 const CGFloat kAnchorlessEndPadding = 20;
32 const CGFloat kAnchorlessTopPadding = 10;
33
34 }  // namespace
35
36 @interface NewCreditCardBubbleControllerCocoa : BaseBubbleController {
37  @private
38   // Controller that drives this bubble. Never NULL; outlives this class.
39   autofill::NewCreditCardBubbleController* controller_;
40
41   // Objective-C/C++ bridge. Owned by this class.
42   scoped_ptr<autofill::NewCreditCardBubbleCocoa> bridge_;
43 }
44
45 // Designated initializer.
46 - (id)initWithParentWindow:(NSWindow*)parentWindow
47                 controller:
48                     (autofill::NewCreditCardBubbleController*)controller
49                     bridge:(autofill::NewCreditCardBubbleCocoa*)bridge;
50
51 // Displays the bubble anchored at the specified |anchorPoint|.
52 - (void)showAtAnchor:(NSPoint)anchorPoint;
53
54 // Helper function to create an uneditable text field.
55 - (base::scoped_nsobject<NSTextField>)makeTextField;
56
57 // Helper function to set the appropriately styled details string.
58 - (void)setDetailsStringForField:(NSTextField*)details;
59
60 // Create and lay out all control elements inside the bubble.
61 - (void)performLayout;
62
63 // Delegate interface for clicks on "Learn more".
64 - (void)onLinkClicked:(id)sender;
65
66 @end
67
68
69 @implementation NewCreditCardBubbleControllerCocoa
70
71 - (id)initWithParentWindow:(NSWindow*)parentWindow
72                 controller:
73                     (autofill::NewCreditCardBubbleController*)controller
74                     bridge:(autofill::NewCreditCardBubbleCocoa*)bridge {
75   base::scoped_nsobject<InfoBubbleWindow> window(
76       [[InfoBubbleWindow alloc]
77           initWithContentRect:ui::kWindowSizeDeterminedLater
78                     styleMask:NSBorderlessWindowMask
79                       backing:NSBackingStoreBuffered
80                         defer:NO]);
81   bridge_.reset(bridge);
82   if ((self = [super initWithWindow:window
83                        parentWindow:parentWindow
84                          anchoredAt:NSZeroPoint])) {
85     controller_ = controller;
86     [window setCanBecomeKeyWindow:NO];
87
88     ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
89     [[self bubble] setBackgroundColor:
90         gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
91             ui::NativeTheme::kColorId_DialogBackground))];
92     [self performLayout];
93   }
94   return self;
95 }
96
97 - (void)showAtAnchor:(NSPoint)anchorPoint {
98   [self setAnchorPoint:anchorPoint];
99   [[self bubble] setNeedsDisplay:YES];
100   [self showWindow:nil];
101 }
102
103 - (base::scoped_nsobject<NSTextField>)makeTextField {
104   base::scoped_nsobject<NSTextField> textField(
105       [[NSTextField alloc] initWithFrame:NSZeroRect]);
106   [textField setEditable:NO];
107   [textField setSelectable:NO];
108   [textField setDrawsBackground:NO];
109   [textField setBezeled:NO];
110
111   return textField;
112 }
113
114 - (void)setDetailsStringForField:(NSTextField*)details {
115   // Set linespacing for |details| to match line spacing used in the dialog.
116   base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
117       [[NSMutableParagraphStyle alloc] init]);
118   [paragraphStyle setLineSpacing:0.5 * [[details font] pointSize]];
119
120   NSString* description =
121       base::SysUTF16ToNSString(controller_->CardDescription().description);
122   base::scoped_nsobject<NSAttributedString> detailsString(
123       [[NSAttributedString alloc]
124            initWithString:description
125                attributes:@{ NSParagraphStyleAttributeName : paragraphStyle }]);
126
127   [details setAttributedStringValue:detailsString];
128 }
129
130 - (void)performLayout {
131   base::scoped_nsobject<NSTextField> title([self makeTextField]);
132   base::scoped_nsobject<NSImageView> icon([[NSImageView alloc]
133       initWithFrame:NSZeroRect]);
134   base::scoped_nsobject<NSTextField> name([self makeTextField]);
135   base::scoped_nsobject<NSTextField> details([self makeTextField]);
136   base::scoped_nsobject<NSButton> link([[HyperlinkButtonCell buttonWithString:
137           base::SysUTF16ToNSString(controller_->LinkText())] retain]);
138
139   [link setTarget:self];
140   [link setAction:@selector(onLinkClicked:)];
141
142   // Use uniform font across all controls (except title).
143   [details setFont:[link font]];
144   [name setFont:[link font]];
145   [title setFont:[NSFont systemFontOfSize:15.0]];
146
147   // Populate fields.
148   const autofill::CreditCardDescription& card_desc =
149       controller_->CardDescription();
150   [title setStringValue:base::SysUTF16ToNSString(controller_->TitleText())];
151   [icon setImage:card_desc.icon.AsNSImage()];
152   [name setStringValue:base::SysUTF16ToNSString(card_desc.name)];
153   [self setDetailsStringForField:details];
154
155   // Size fields.
156   CGFloat bubbleWidth = autofill::NewCreditCardBubbleView::kContentsWidth;
157   [title sizeToFit];
158   bubbleWidth = std::max(bubbleWidth, NSWidth([title frame]) + 2 * kInset);
159   [icon setFrameSize:[[icon image] size]];
160   [name sizeToFit];
161   [details setFrameSize:[[details cell] cellSizeForBounds:
162       NSMakeRect(0, 0, bubbleWidth - 2 * kInset, CGFLOAT_MAX)]];
163   [link sizeToFit];
164
165   // Layout fields.
166   [link setFrameOrigin:NSMakePoint(kInset, kInset)];
167   [details setFrameOrigin:NSMakePoint(
168       kInset, NSMaxY([link frame]) + kVerticalSpacing)];
169   [icon setFrameOrigin:NSMakePoint(
170       kInset, NSMaxY([details frame]) + kVerticalSpacing)];
171   [name setFrameOrigin:NSMakePoint(
172       NSMaxX([icon frame]) + kHorizontalSpacing,
173       NSMidY([icon frame]) - (NSHeight([name frame]) / 2.0))];
174   [title setFrameOrigin:
175       NSMakePoint(kInset, NSMaxY([icon frame]) + kTitleSpacing)];
176
177   [[[self window] contentView] setSubviews:
178       @[ title, icon, name, details, link ]];
179
180   // Update window frame.
181   NSRect windowFrame = [[self window] frame];
182   windowFrame.size.height = NSMaxY([title frame]) + kInset;
183   windowFrame.size.width = bubbleWidth;
184   [[self window] setFrame:windowFrame display:NO];
185 }
186
187 - (void)onLinkClicked:(id)sender {
188   controller_->OnLinkClicked();
189 }
190
191 @end
192
193
194 namespace autofill {
195
196 NewCreditCardBubbleCocoa::~NewCreditCardBubbleCocoa() {
197   controller_->OnBubbleDestroyed();
198 }
199
200 void NewCreditCardBubbleCocoa::Show() {
201   NSView* browser_view = controller_->web_contents()->GetNativeView();
202   NSWindow* parent_window = [browser_view window];
203   BrowserWindowController* bwc = [BrowserWindowController
204       browserWindowControllerForWindow:parent_window];
205
206   if (!bubbleController_)
207     CreateCocoaController(parent_window);
208
209   NSPoint anchor_point;
210   NSView* anchor_view;
211   if ([bwc isTabbedWindow]) {
212     anchor_view = [[bwc toolbarController] wrenchButton];
213     anchor_point = NSMakePoint(
214         NSMidX([anchor_view bounds]),
215         NSMinY([anchor_view bounds]) + kWrenchBubblePointOffsetY);
216     [[bubbleController_ bubble] setArrowLocation:info_bubble::kTopRight];
217     [[bubbleController_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
218   } else {
219     anchor_view = browser_view;
220     anchor_point = NSMakePoint(
221         NSMaxX([browser_view bounds]) - kAnchorlessEndPadding,
222         NSMaxY([browser_view bounds]) - kAnchorlessTopPadding);
223     [[bubbleController_ bubble] setArrowLocation:info_bubble::kNoArrow];
224     if (base::i18n::IsRTL()) {
225       anchor_point.x = NSMaxX([anchor_view bounds]) - anchor_point.x;
226       [[bubbleController_ bubble] setAlignment:
227           info_bubble::kAlignLeftEdgeToAnchorEdge];
228     } else {
229       [[bubbleController_ bubble] setAlignment:
230           info_bubble::kAlignRightEdgeToAnchorEdge];
231     }
232   }
233   if ([anchor_view isFlipped])
234     anchor_point.y = NSMaxY([anchor_view bounds]) - anchor_point.y;
235   anchor_point = [anchor_view convertPoint:anchor_point toView:nil];
236
237   NSRect frame = NSZeroRect;
238   frame.origin = anchor_point;
239   anchor_point = [parent_window convertBaseToScreen:anchor_point];
240   [bubbleController_ showAtAnchor:anchor_point];
241 }
242
243 void NewCreditCardBubbleCocoa::Hide() {
244   [bubbleController_ close];
245 }
246
247 // static
248 base::WeakPtr<NewCreditCardBubbleView> NewCreditCardBubbleView::Create(
249     NewCreditCardBubbleController* controller) {
250   NewCreditCardBubbleCocoa* bubble = new NewCreditCardBubbleCocoa(controller);
251   return bubble->weak_ptr_factory_.GetWeakPtr();
252 }
253
254 NewCreditCardBubbleCocoa::NewCreditCardBubbleCocoa(
255     NewCreditCardBubbleController* controller)
256     : bubbleController_(NULL),
257       controller_(controller),
258       weak_ptr_factory_(this) {
259 }
260
261 void NewCreditCardBubbleCocoa::CreateCocoaController(NSWindow* parent) {
262   DCHECK(!bubbleController_);
263   bubbleController_ = [[NewCreditCardBubbleControllerCocoa alloc]
264       initWithParentWindow:parent
265                 controller:controller_
266                     bridge:this];
267 }
268
269 InfoBubbleWindow* NewCreditCardBubbleCocoa::GetInfoBubbleWindow() {
270   return base::mac::ObjCCastStrict<InfoBubbleWindow>(
271       [bubbleController_ window]);
272 }
273
274 }  // namespace autofill