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 #import "chrome/browser/ui/cocoa/autofill/autofill_notification_controller.h"
9 #include "base/logging.h"
10 #include "base/mac/foundation_util.h"
11 #include "base/mac/scoped_nsobject.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
14 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
15 #include "chrome/browser/ui/chrome_style.h"
16 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
17 #import "chrome/browser/ui/cocoa/autofill/autofill_tooltip_controller.h"
18 #include "grit/theme_resources.h"
19 #include "skia/ext/skia_utils_mac.h"
20 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
22 @interface AutofillNotificationView : NSView {
24 base::scoped_nsobject<NSColor> backgroundColor_;
25 base::scoped_nsobject<NSColor> borderColor_;
28 @property (nonatomic, retain) NSColor* backgroundColor;
29 @property (nonatomic, retain) NSColor* borderColor;
33 @implementation AutofillNotificationView
35 - (void)drawRect:(NSRect)dirtyRect {
36 [super drawRect:dirtyRect];
39 NSRect bounds = [self bounds];
40 path = [NSBezierPath bezierPathWithRect:bounds];
42 [backgroundColor_ setFill];
44 [borderColor_ setStroke];
48 - (NSColor*)backgroundColor {
49 return backgroundColor_;
52 - (void)setBackgroundColor:(NSColor*)backgroundColor {
53 backgroundColor_.reset([backgroundColor retain]);
56 - (NSColor*)borderColor {
60 - (void)setBorderColor:(NSColor*)borderColor {
61 borderColor_.reset([borderColor retain]);
66 @implementation AutofillNotificationController
68 - (id)initWithNotification:(const autofill::DialogNotification*)notification
69 delegate:(autofill::AutofillDialogViewDelegate*)delegate {
70 if (self = [super init]) {
72 notificationType_ = notification->type();
74 base::scoped_nsobject<AutofillNotificationView> view(
75 [[AutofillNotificationView alloc] initWithFrame:NSZeroRect]);
76 [view setBackgroundColor:
77 gfx::SkColorToCalibratedNSColor(notification->GetBackgroundColor())];
79 gfx::SkColorToCalibratedNSColor(notification->GetBorderColor())];
82 textview_.reset([[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
84 gfx::SkColorToCalibratedNSColor(notification->GetTextColor());
85 [textview_ setMessage:base::SysUTF16ToNSString(notification->display_text())
86 withFont:[NSFont labelFontOfSize:[[textview_ font] pointSize]]
87 messageColor:textColor];
88 if (!notification->link_range().is_empty()) {
89 [textview_ setDelegate:self];
90 [textview_ addLinkRange:notification->link_range().ToNSRange()
92 linkColor:[NSColor blueColor]];
93 linkURL_ = notification->link_url();
96 tooltipController_.reset([[AutofillTooltipController alloc]
97 initWithArrowLocation:info_bubble::kTopRight]);
98 [tooltipController_ setImage:
99 ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
100 IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage()];
101 [tooltipController_ setMessage:
102 base::SysUTF16ToNSString(notification->tooltip_text())];
103 [[tooltipController_ view] setHidden:
104 [[tooltipController_ message] length] == 0];
106 [view setSubviews:@[ textview_, [tooltipController_ view] ]];
111 - (AutofillNotificationView*)notificationView {
112 return base::mac::ObjCCastStrict<AutofillNotificationView>([self view]);
115 - (NSTextView*)textview {
119 - (NSView*)tooltipView {
120 return [tooltipController_ view];
123 - (NSSize)preferredSizeForWidth:(CGFloat)width {
124 width -= 2 * chrome_style::kHorizontalPadding;
125 if (![[tooltipController_ view] isHidden]) {
126 width -= NSWidth([[tooltipController_ view] frame]) +
127 chrome_style::kHorizontalPadding;
129 // TODO(isherman): Restore the DCHECK below once I figure out why it causes
130 // unit tests to fail.
131 //DCHECK_GT(width, 0);
133 NSSize preferredSize;
134 // This method is logically const. Hence, cache the original frame so that
135 // it can be restored once the preferred size has been computed.
136 NSRect frame = [textview_ frame];
138 // Compute preferred size.
139 [textview_ setFrameSize:NSMakeSize(width, frame.size.height)];
140 [textview_ setVerticallyResizable:YES];
141 [textview_ sizeToFit];
142 preferredSize = [textview_ frame].size;
144 // Restore original properties, since this method is logically const.
145 [textview_ setFrame:frame];
146 [textview_ setVerticallyResizable:NO];
148 preferredSize.height += 2 * autofill::kNotificationPadding;
149 return preferredSize;
152 - (NSSize)preferredSize {
157 - (void)performLayout {
158 NSRect bounds = [[self view] bounds];
159 // Calculate the frame size, leaving room for padding around the notification,
160 // as well as for the tooltip if it is visible.
161 NSRect labelFrame = NSInsetRect(bounds,
162 chrome_style::kHorizontalPadding,
163 autofill::kNotificationPadding);
164 NSView* tooltipView = [tooltipController_ view];
165 if (![tooltipView isHidden]) {
166 labelFrame.size.width -=
167 NSWidth([tooltipView frame]) + chrome_style::kHorizontalPadding;
170 NSView* label = textview_.get();
171 [label setFrame:labelFrame];
173 if (![tooltipView isHidden]) {
174 NSPoint tooltipOrigin =
176 NSMaxX(labelFrame) + chrome_style::kHorizontalPadding,
177 NSMidY(labelFrame) - (NSHeight([tooltipView frame]) / 2.0));
178 [tooltipView setFrameOrigin:tooltipOrigin];
182 - (BOOL)textView:(NSTextView *)textView
183 clickedOnLink:(id)link
184 atIndex:(NSUInteger)charIndex {
185 delegate_->LinkClicked(linkURL_);