1 // Copyright (c) 2012 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/one_click_signin_view_controller.h"
7 #include "base/callback_helpers.h"
8 #include "base/logging.h"
9 #include "base/mac/bundle_locations.h"
10 #import "chrome/browser/ui/chrome_style.h"
11 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
12 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
13 #include "chrome/browser/ui/sync/one_click_signin_histogram.h"
14 #include "chrome/common/url_constants.h"
15 #include "content/public/browser/web_contents.h"
16 #include "grit/chromium_strings.h"
17 #include "grit/generated_resources.h"
18 #include "skia/ext/skia_utils_mac.h"
19 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
20 #include "ui/base/l10n/l10n_util_mac.h"
24 // Shift the origin of |view|'s frame by the given amount in the
25 // positive y direction (up).
26 void ShiftOriginY(NSView* view, CGFloat amount) {
27 NSPoint origin = [view frame].origin;
29 [view setFrameOrigin:origin];
34 @interface OneClickSigninViewController ()
35 - (CGFloat)initializeInformativeTextView;
39 @implementation OneClickSigninViewController
42 - (id)initWithNibName:(NSString*)nibName
43 webContents:(content::WebContents*)webContents
44 syncCallback:(const BrowserWindow::StartSyncCallback&)syncCallback
45 closeCallback:(const base::Closure&)closeCallback
46 isSyncDialog:(BOOL)isSyncDialog
47 email:(const base::string16&)email
48 errorMessage:(NSString*)errorMessage {
49 if ((self = [super initWithNibName:nibName
50 bundle:base::mac::FrameworkBundle()])) {
51 webContents_ = webContents;
52 startSyncCallback_ = syncCallback;
53 closeCallback_ = closeCallback;
54 isSyncDialog_ = isSyncDialog;
55 clickedLearnMore_ = NO;
57 errorMessage_.reset([errorMessage retain]);
59 DCHECK(!startSyncCallback_.is_null());
64 - (void)viewWillClose {
65 // This is usually called after a click handler has initiated sync
66 // and has reset the callback. However, in the case that we are closing
67 // the window and nothing else has initiated the sync, we must do so here
68 if (isSyncDialog_ && !startSyncCallback_.is_null()) {
69 base::ResetAndReturn(&startSyncCallback_).Run(
70 OneClickSigninSyncStarter::UNDO_SYNC);
74 - (IBAction)ok:(id)sender {
76 OneClickSigninHelper::LogConfirmHistogramValue(
78 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_OK :
79 one_click_signin::HISTOGRAM_CONFIRM_OK);
81 base::ResetAndReturn(&startSyncCallback_).Run(
82 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
87 - (IBAction)onClickUndo:(id)sender {
89 OneClickSigninHelper::LogConfirmHistogramValue(
91 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_UNDO :
92 one_click_signin::HISTOGRAM_CONFIRM_UNDO);
94 base::ResetAndReturn(&startSyncCallback_).Run(
95 OneClickSigninSyncStarter::UNDO_SYNC);
100 - (IBAction)onClickAdvancedLink:(id)sender {
102 OneClickSigninHelper::LogConfirmHistogramValue(
104 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_ADVANCED :
105 one_click_signin::HISTOGRAM_CONFIRM_ADVANCED);
107 base::ResetAndReturn(&startSyncCallback_).Run(
108 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
111 content::OpenURLParams params(GURL(chrome::kChromeUISettingsURL),
112 content::Referrer(), CURRENT_TAB,
113 content::PAGE_TRANSITION_LINK, false);
114 webContents_->OpenURL(params);
119 - (IBAction)onClickClose:(id)sender {
121 OneClickSigninHelper::LogConfirmHistogramValue(
123 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_CLOSE :
124 one_click_signin::HISTOGRAM_CONFIRM_CLOSE);
126 base::ResetAndReturn(&startSyncCallback_).Run(
127 OneClickSigninSyncStarter::UNDO_SYNC);
132 - (void)awakeFromNib {
133 // Lay out the text controls from the bottom up.
134 CGFloat totalYOffset = 0.0;
136 if ([errorMessage_ length] == 0) {
138 [GTMUILocalizerAndLayoutTweaker sizeToFitView:advancedLink_].height;
139 [[advancedLink_ cell] setTextColor:
140 gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor())];
142 // Don't display the advanced link for the error bubble.
143 // To align the Learn More link with the OK button, we need to offset by
144 // the height of the Advanced link, plus the padding between it and the
145 // Learn More link above.
146 float advancedLinkHeightPlusPadding =
147 [informativePlaceholderTextField_ frame].origin.y -
148 [advancedLink_ frame].origin.y;
150 totalYOffset -= advancedLinkHeightPlusPadding;
151 [advancedLink_ removeFromSuperview];
154 if (informativePlaceholderTextField_) {
155 ShiftOriginY(informativePlaceholderTextField_, totalYOffset);
156 totalYOffset += [self initializeInformativeTextView];
159 ShiftOriginY(messageTextField_, totalYOffset);
161 [GTMUILocalizerAndLayoutTweaker
162 sizeToFitFixedWidthTextField:messageTextField_];
164 ShiftOriginY(titleTextField_, totalYOffset);
166 [GTMUILocalizerAndLayoutTweaker
167 sizeToFitFixedWidthTextField:titleTextField_];
170 ShiftOriginY(closeButton_, totalYOffset);
172 NSSize delta = NSMakeSize(0.0, totalYOffset);
175 [messageTextField_ setStringValue:l10n_util::GetNSStringWithFixup(
176 IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW)];
177 } else if ([errorMessage_ length] != 0) {
178 [messageTextField_ setStringValue:errorMessage_];
181 // Resize bubble and window to hold the controls.
182 [GTMUILocalizerAndLayoutTweaker
183 resizeViewWithoutAutoResizingSubViews:[self view]
187 OneClickSigninHelper::LogConfirmHistogramValue(
188 one_click_signin::HISTOGRAM_CONFIRM_SHOWN);
192 - (CGFloat)initializeInformativeTextView {
193 NSRect oldFrame = [informativePlaceholderTextField_ frame];
195 // Replace the placeholder NSTextField with the real label NSTextView. The
196 // former doesn't show links in a nice way, but the latter can't be added in
197 // a xib without a containing scroll view, so create the NSTextView
199 informativeTextView_.reset(
200 [[HyperlinkTextView alloc] initWithFrame:oldFrame]);
201 [informativeTextView_.get() setAutoresizingMask:
202 [informativePlaceholderTextField_ autoresizingMask]];
203 [informativeTextView_.get() setDelegate:self];
206 NSString* learnMoreText = l10n_util::GetNSStringWithFixup(IDS_LEARN_MORE);
207 NSString* messageText;
209 ui::ResourceBundle::FontStyle fontStyle = isSyncDialog_ ?
210 chrome_style::kTextFontStyle : ui::ResourceBundle::SmallFont;
211 NSFont* font = ui::ResourceBundle::GetSharedInstance().GetFont(
212 fontStyle).GetNativeFont();
214 // The non-modal bubble already has a text content and only needs the
215 // Learn More link (in a smaller font).
217 messageText = l10n_util::GetNSStringFWithFixup(
218 IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE_NEW, email_);
219 messageText = [messageText stringByAppendingString:@" "];
225 gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor());
226 [informativeTextView_ setMessageAndLink:messageText
227 withLink:learnMoreText
228 atOffset:[messageText length]
230 messageColor:[NSColor blackColor]
231 linkColor:linkColor];
234 // Make the "Advanced" link font as large as the "Learn More" link.
235 [[advancedLink_ cell] setFont:font];
236 [advancedLink_ sizeToFit];
239 [[informativePlaceholderTextField_ cell] setAttributedStringValue:
240 [informativeTextView_ attributedString]];
241 [GTMUILocalizerAndLayoutTweaker
242 sizeToFitFixedWidthTextField:informativePlaceholderTextField_];
243 NSRect newFrame = [informativePlaceholderTextField_ frame];
244 [informativeTextView_ setFrame:newFrame];
247 [[informativePlaceholderTextField_ superview]
248 replaceSubview:informativePlaceholderTextField_
249 with:informativeTextView_.get()];
250 informativePlaceholderTextField_ = nil; // Now released.
252 return NSHeight(newFrame) - NSHeight(oldFrame);
255 - (BOOL)textView:(NSTextView*)textView
256 clickedOnLink:(id)link
257 atIndex:(NSUInteger)charIndex {
258 if (isSyncDialog_ && !clickedLearnMore_) {
259 clickedLearnMore_ = YES;
261 OneClickSigninHelper::LogConfirmHistogramValue(
262 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE);
264 WindowOpenDisposition location = isSyncDialog_ ?
265 NEW_WINDOW : NEW_FOREGROUND_TAB;
266 content::OpenURLParams params(GURL(chrome::kChromeSyncLearnMoreURL),
267 content::Referrer(), location,
268 content::PAGE_TRANSITION_LINK, false);
269 webContents_->OpenURL(params);
274 base::ResetAndReturn(&closeCallback_).Run();