Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / one_click_signin_view_controller.mm
blob6ecd11ee8de8b01fd67016cc2f29f1a780c2beab
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 #include "chrome/common/url_constants.h"
12 #include "chrome/grit/chromium_strings.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "components/signin/core/browser/signin_metrics.h"
15 #include "content/public/browser/web_contents.h"
16 #include "grit/components_strings.h"
17 #include "skia/ext/skia_utils_mac.h"
18 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
19 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
20 #include "ui/base/l10n/l10n_util_mac.h"
22 namespace {
24 // The margin between the top edge of the border and the error message text in
25 // the sign-in bubble, in the case of an error.
26 const CGFloat kTopErrorMessageMargin = 12;
28 // Shift the origin of |view|'s frame by the given amount in the
29 // positive y direction (up).
30 void ShiftOriginY(NSView* view, CGFloat amount) {
31   NSPoint origin = [view frame].origin;
32   origin.y += amount;
33   [view setFrameOrigin:origin];
36 }  // namespace
38 @interface OneClickSigninViewController ()
39 - (CGFloat)initializeInformativeTextView;
40 - (void)close;
41 @end
43 @implementation OneClickSigninViewController
46 - (id)initWithNibName:(NSString*)nibName
47           webContents:(content::WebContents*)webContents
48          syncCallback:(const BrowserWindow::StartSyncCallback&)syncCallback
49         closeCallback:(const base::Closure&)closeCallback
50          isSyncDialog:(BOOL)isSyncDialog
51                 email:(const base::string16&)email
52          errorMessage:(NSString*)errorMessage {
53   if ((self = [super initWithNibName:nibName
54                               bundle:base::mac::FrameworkBundle()])) {
55     webContents_ = webContents;
56     startSyncCallback_ = syncCallback;
57     closeCallback_ = closeCallback;
58     isSyncDialog_ = isSyncDialog;
59     clickedLearnMore_ = NO;
60     email_ = email;
61     errorMessage_.reset([errorMessage retain]);
62     if (isSyncDialog_)
63       DCHECK(!startSyncCallback_.is_null());
64   }
65   return self;
68 - (void)viewWillClose {
69   // This is usually called after a click handler has initiated sync
70   // and has reset the callback. However, in the case that we are closing
71   // the window and nothing else has initiated the sync, we must do so here
72   if (isSyncDialog_ && !startSyncCallback_.is_null()) {
73     base::ResetAndReturn(&startSyncCallback_).Run(
74         OneClickSigninSyncStarter::UNDO_SYNC);
75   }
78 - (IBAction)ok:(id)sender {
79   if (isSyncDialog_) {
80     signin_metrics::LogSigninConfirmHistogramValue(
81         clickedLearnMore_ ?
82             signin_metrics::HISTOGRAM_CONFIRM_LEARN_MORE_OK :
83             signin_metrics::HISTOGRAM_CONFIRM_OK);
85     base::ResetAndReturn(&startSyncCallback_).Run(
86       OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
87   }
88   [self close];
91 - (IBAction)onClickUndo:(id)sender {
92   if (isSyncDialog_) {
93     signin_metrics::LogSigninConfirmHistogramValue(
94         clickedLearnMore_ ?
95             signin_metrics::HISTOGRAM_CONFIRM_LEARN_MORE_UNDO :
96             signin_metrics::HISTOGRAM_CONFIRM_UNDO);
98     base::ResetAndReturn(&startSyncCallback_).Run(
99       OneClickSigninSyncStarter::UNDO_SYNC);
100   }
101   [self close];
104 - (IBAction)onClickAdvancedLink:(id)sender {
105   if (isSyncDialog_) {
106     signin_metrics::LogSigninConfirmHistogramValue(
107         clickedLearnMore_ ?
108             signin_metrics::HISTOGRAM_CONFIRM_LEARN_MORE_ADVANCED :
109             signin_metrics::HISTOGRAM_CONFIRM_ADVANCED);
111     base::ResetAndReturn(&startSyncCallback_).Run(
112         OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
113   }
114   else {
115     content::OpenURLParams params(GURL(chrome::kChromeUISettingsURL),
116                                   content::Referrer(), CURRENT_TAB,
117                                   ui::PAGE_TRANSITION_LINK, false);
118     webContents_->OpenURL(params);
119   }
120   [self close];
123 - (IBAction)onClickClose:(id)sender {
124   if (isSyncDialog_) {
125     signin_metrics::LogSigninConfirmHistogramValue(
126         clickedLearnMore_ ?
127             signin_metrics::HISTOGRAM_CONFIRM_LEARN_MORE_CLOSE :
128             signin_metrics::HISTOGRAM_CONFIRM_CLOSE);
130     base::ResetAndReturn(&startSyncCallback_).Run(
131         OneClickSigninSyncStarter::UNDO_SYNC);
132   }
133   [self close];
136 - (void)awakeFromNib {
137   // Lay out the text controls from the bottom up.
138   CGFloat totalYOffset = 0.0;
140   if ([errorMessage_ length] == 0) {
141     totalYOffset +=
142         [GTMUILocalizerAndLayoutTweaker sizeToFitView:advancedLink_].height;
143     [[advancedLink_ cell] setTextColor:
144         gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor())];
145   } else {
146     // Don't display the advanced link for the error bubble.
147     // To align the Learn More link with the OK button, we need to offset by
148     // the height of the Advanced link, plus the padding between it and the
149     // Learn More link above.
150     float advancedLinkHeightPlusPadding =
151         [informativePlaceholderTextField_ frame].origin.y -
152         [advancedLink_ frame].origin.y;
154     totalYOffset -= advancedLinkHeightPlusPadding;
155     [advancedLink_ removeFromSuperview];
156   }
158   if (informativePlaceholderTextField_) {
159     if (!isSyncDialog_ && ([errorMessage_ length] != 0)) {
160       // Move up the "Learn more" origin in error case to account for the
161       // smaller bubble.
162       NSRect frame = [informativePlaceholderTextField_ frame];
163       frame = NSOffsetRect(frame, 0, NSHeight([titleTextField_ frame]));
164       [informativePlaceholderTextField_ setFrame:frame];
165     }
167     ShiftOriginY(informativePlaceholderTextField_, totalYOffset);
168     totalYOffset += [self initializeInformativeTextView];
169   }
171   ShiftOriginY(messageTextField_, totalYOffset);
172   totalYOffset +=
173       [GTMUILocalizerAndLayoutTweaker
174           sizeToFitFixedWidthTextField:messageTextField_];
176   ShiftOriginY(titleTextField_, totalYOffset);
177   totalYOffset +=
178       [GTMUILocalizerAndLayoutTweaker
179           sizeToFitFixedWidthTextField:titleTextField_];
181   NSSize delta = NSMakeSize(0.0, totalYOffset);
183   if (isSyncDialog_) {
184     [messageTextField_ setStringValue:l10n_util::GetNSStringWithFixup(
185         IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW)];
186   } else if ([errorMessage_ length] != 0) {
187     [titleTextField_ setHidden:YES];
188     [messageTextField_ setStringValue:errorMessage_];
190     // Make the bubble less tall, as the title text will be hidden.
191     NSSize size = [[self view] frame].size;
192     size.height = size.height - NSHeight([titleTextField_ frame]);
193     [[self view] setFrameSize:size];
195     // Shift the message text up to where the title text used to be.
196     NSPoint origin = [titleTextField_ frame].origin;
197     [messageTextField_ setFrameOrigin:origin];
198     ShiftOriginY(messageTextField_, -kTopErrorMessageMargin);
200     // Use "OK" instead of "OK, got it" in the error case, and size the button
201     // accordingly.
202     [closeButton_ setTitle:l10n_util::GetNSStringWithFixup(
203         IDS_OK)];
204     [GTMUILocalizerAndLayoutTweaker sizeToFitView:[closeButton_ superview]];
205   }
207   // Resize bubble and window to hold the controls.
208   [GTMUILocalizerAndLayoutTweaker
209       resizeViewWithoutAutoResizingSubViews:[self view]
210                                       delta:delta];
212   if (isSyncDialog_) {
213     signin_metrics::LogSigninConfirmHistogramValue(
214         signin_metrics::HISTOGRAM_CONFIRM_SHOWN);
215   }
218 - (CGFloat)initializeInformativeTextView {
219   NSRect oldFrame = [informativePlaceholderTextField_ frame];
221   // Replace the placeholder NSTextField with the real label NSTextView. The
222   // former doesn't show links in a nice way, but the latter can't be added in
223   // a xib without a containing scroll view, so create the NSTextView
224   // programmatically.
225   informativeTextView_.reset(
226       [[HyperlinkTextView alloc] initWithFrame:oldFrame]);
227   [informativeTextView_.get() setAutoresizingMask:
228       [informativePlaceholderTextField_ autoresizingMask]];
229   [informativeTextView_.get() setDelegate:self];
231   // Set the text.
232   NSString* learnMoreText = l10n_util::GetNSStringWithFixup(IDS_LEARN_MORE);
233   NSString* messageText;
234   NSUInteger learnMoreOffset = 0;
236   ui::ResourceBundle::FontStyle fontStyle = isSyncDialog_ ?
237       chrome_style::kTextFontStyle : ui::ResourceBundle::SmallFont;
238   NSFont* font = ui::ResourceBundle::GetSharedInstance().GetFont(
239       fontStyle).GetNativeFont();
241   // The non-modal bubble already has a text content and only needs the
242   // Learn More link (in a smaller font).
243   if (isSyncDialog_) {
244     messageText = l10n_util::GetNSStringFWithFixup(
245         IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE_NEW, email_);
246     learnMoreOffset = [messageText length];
247     messageText = [messageText stringByAppendingFormat:@" %@", learnMoreText];
248   } else {
249     messageText = learnMoreText;
250   }
252   NSColor* linkColor =
253       gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor());
254   [informativeTextView_ setMessage:messageText
255                           withFont:font
256                       messageColor:[NSColor blackColor]];
257   [informativeTextView_ addLinkRange:NSMakeRange(learnMoreOffset,
258                                                  [learnMoreText length])
259                             withName:@""
260                            linkColor:linkColor];
262   // Make the "Advanced" link font as large as the "Learn More" link.
263   [[advancedLink_ cell] setFont:font];
264   [advancedLink_ sizeToFit];
266   // Size to fit.
267   [[informativePlaceholderTextField_ cell] setAttributedStringValue:
268       [informativeTextView_ attributedString]];
269   [GTMUILocalizerAndLayoutTweaker
270         sizeToFitFixedWidthTextField:informativePlaceholderTextField_];
271   NSRect newFrame = [informativePlaceholderTextField_ frame];
272   [informativeTextView_ setFrame:newFrame];
274   // Swap placeholder.
275   [[informativePlaceholderTextField_ superview]
276      replaceSubview:informativePlaceholderTextField_
277                with:informativeTextView_.get()];
278   informativePlaceholderTextField_ = nil;  // Now released.
280   return NSHeight(newFrame) - NSHeight(oldFrame);
283 - (BOOL)textView:(NSTextView*)textView
284    clickedOnLink:(id)link
285          atIndex:(NSUInteger)charIndex {
286   if (isSyncDialog_ && !clickedLearnMore_) {
287     clickedLearnMore_ = YES;
289     signin_metrics::LogSigninConfirmHistogramValue(
290         signin_metrics::HISTOGRAM_CONFIRM_LEARN_MORE);
291   }
292   WindowOpenDisposition location = isSyncDialog_ ?
293                                    NEW_WINDOW : NEW_FOREGROUND_TAB;
294   content::OpenURLParams params(GURL(chrome::kChromeSyncLearnMoreURL),
295                                 content::Referrer(), location,
296                                 ui::PAGE_TRANSITION_LINK, false);
297   webContents_->OpenURL(params);
298   return YES;
301 - (void)close {
302   base::ResetAndReturn(&closeCallback_).Run();
305 @end