3176b3b7e589fe7c0727f869039d3160469ac503
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / autofill / generated_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/generated_credit_card_bubble_cocoa.h"
6
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"
21
22 using autofill::GeneratedCreditCardBubbleCocoa;
23
24 namespace {
25
26 const CGFloat kTitlePadding = 20.0;
27 const CGFloat kInset = 20.0;
28
29 }  // namespace
30
31 // The Cocoa side of the bubble controller.
32 @interface GeneratedCreditCardBubbleControllerCocoa :
33     BaseBubbleController<NSTextViewDelegate> {
34
35   // Bridge to C++ side.
36   scoped_ptr<GeneratedCreditCardBubbleCocoa> bridge_;
37 }
38
39 - (id)initWithParentWindow:(NSWindow*)parentWindow
40                     bridge:(GeneratedCreditCardBubbleCocoa*)bridge;
41
42 // Show the bubble at the given |anchor| point. Coordinates are in screen space.
43 - (void)showAtAnchor:(NSPoint)anchor;
44
45 // Return true if the bubble is in the process of hiding.
46 - (BOOL)isHiding;
47
48 // Build the window contents and lay them out.
49 - (void)performLayoutWithController:
50       (autofill::GeneratedCreditCardBubbleController*)controller;
51
52 @end
53
54
55 @implementation GeneratedCreditCardBubbleControllerCocoa
56
57 - (id)initWithParentWindow:(NSWindow*)parentWindow
58                     bridge:(GeneratedCreditCardBubbleCocoa*)bridge {
59   DCHECK(bridge);
60   base::scoped_nsobject<InfoBubbleWindow> window(
61       [[InfoBubbleWindow alloc]
62           initWithContentRect:ui::kWindowSizeDeterminedLater
63                     styleMask:NSBorderlessWindowMask
64                       backing:NSBackingStoreBuffered
65                         defer:NO]);
66   if ((self = [super initWithWindow:window
67                        parentWindow:parentWindow
68                          anchoredAt:NSZeroPoint])) {
69     [window setCanBecomeKeyWindow:NO];
70     bridge_.reset(bridge);
71
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()];
79   }
80   return self;
81 }
82
83 - (void)windowWillClose:(NSNotification*)notification {
84   bridge_->OnBubbleClosing();
85   [super windowWillClose:notification];
86 }
87
88 // Called when embedded links are clicked.
89 - (BOOL)textView:(NSTextView*)textView
90    clickedOnLink:(id)link
91          atIndex:(NSUInteger)charIndex {
92   bridge_->OnLinkClicked();
93   return YES;
94 }
95
96 - (void)showAtAnchor:(NSPoint)anchorPoint {
97   [self setAnchorPoint:anchorPoint];
98   [self showWindow:nil];
99 }
100
101 - (BOOL)isHiding {
102   InfoBubbleWindow* window =
103       base::mac::ObjCCastStrict<InfoBubbleWindow>([self window]);
104   return [window isClosing];
105 }
106
107
108 - (void)performLayoutWithController:
109     (autofill::GeneratedCreditCardBubbleController*)controller {
110   CGFloat bubbleWidth = autofill::GeneratedCreditCardBubbleView::kContentsWidth;
111
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];
124
125   bubbleWidth = std::max(bubbleWidth, NSWidth([titleView frame]) + 2 * kInset);
126
127   // Build the contents view.
128   base::scoped_nsobject<HyperlinkTextView> contentsView(
129       [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
130
131   [contentsView setEditable:NO];
132   [contentsView setDelegate:self];
133
134   NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
135   NSFont* boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
136   [contentsView setMessage:base::SysUTF16ToNSString(controller->ContentsText())
137                   withFont:font
138               messageColor:[NSColor blackColor]];
139
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
146                         withName:@(i)
147                        linkColor:[NSColor blueColor]];
148     } else {
149        [[contentsView textStorage]
150            addAttributes:@{ NSFontAttributeName : boldFont }
151                    range:range];
152     }
153   }
154
155   [contentsView setVerticallyResizable:YES];
156   [contentsView setFrameSize:NSMakeSize(bubbleWidth - 2 * kInset, CGFLOAT_MAX)];
157   [contentsView sizeToFit];
158
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 ]];
164
165   // Update window frame.
166   NSRect windowFrame = [[self window] frame];
167   windowFrame.size =
168       NSMakeSize(bubbleWidth, NSMaxY([titleView frame]) + kInset);
169   [[self window] setFrame:windowFrame display:YES];
170 }
171
172 @end
173
174
175 namespace autofill {
176
177 // static
178 base::WeakPtr<GeneratedCreditCardBubbleView>
179     GeneratedCreditCardBubbleView::Create(
180         const base::WeakPtr<GeneratedCreditCardBubbleController>& controller) {
181   return (new GeneratedCreditCardBubbleCocoa(controller))->weak_ptr_factory_.
182       GetWeakPtr();
183 }
184
185 GeneratedCreditCardBubbleCocoa::GeneratedCreditCardBubbleCocoa(
186     const base::WeakPtr<GeneratedCreditCardBubbleController>& controller)
187     : bubbleController_(nil),
188       controller_(controller),
189       weak_ptr_factory_(this) {
190 }
191
192 GeneratedCreditCardBubbleCocoa::~GeneratedCreditCardBubbleCocoa() {}
193
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];
201
202   // |location_bar| can be NULL during initialization stages.
203   if (!location_bar) {
204     // Technically, Show() should never be called during initialization.
205     NOTREACHED();
206
207     delete this;
208     return;
209   }
210
211   if (!bubbleController_) {
212     bubbleController_ = [[GeneratedCreditCardBubbleControllerCocoa alloc]
213         initWithParentWindow:parent_window
214                       bridge:this];
215   }
216
217   // |bubbleController_| is supposed to take ownership of |this|. If it can't be
218   // constructed, clean up and abort showing.
219   if (!bubbleController_) {
220     delete this;
221     return;
222   }
223
224   NSPoint anchor = location_bar->GetGeneratedCreditCardBubblePoint();
225   [bubbleController_ showAtAnchor:[parent_window convertBaseToScreen:anchor]];
226 }
227
228 void GeneratedCreditCardBubbleCocoa::Hide() {
229   [bubbleController_ close];
230 }
231
232 bool GeneratedCreditCardBubbleCocoa::IsHiding() const {
233   return [bubbleController_ isHiding];
234 }
235
236 void GeneratedCreditCardBubbleCocoa::OnBubbleClosing() {
237   bubbleController_ = nil;
238 }
239
240 void GeneratedCreditCardBubbleCocoa::OnLinkClicked() {
241   if (controller_)
242     controller_->OnLinkClicked();
243 }
244
245 }  // autofill