Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / infobars / confirm_infobar_controller.mm
blob7a4823d84db9263b5fdc1807ce265ee18a4b5961
1 // Copyright 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 #include "chrome/browser/ui/cocoa/infobars/confirm_infobar_controller.h"
7 #include "base/logging.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "chrome/browser/infobars/infobar_service.h"
10 #include "chrome/browser/ui/chrome_style.h"
11 #include "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h"
12 #include "components/infobars/core/confirm_infobar_delegate.h"
13 #include "skia/ext/skia_utils_mac.h"
14 #include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
15 #import "ui/base/cocoa/cocoa_base_utils.h"
16 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
17 #include "ui/base/window_open_disposition.h"
19 @implementation ConfirmInfoBarController
21 // Called when someone clicks on the "OK" button.
22 - (IBAction)ok:(id)sender {
23   if (![self isOwned])
24     return;
25   if ([self delegate]->AsConfirmInfoBarDelegate()->Accept())
26     [self removeSelf];
29 // Called when someone clicks on the "Cancel" button.
30 - (IBAction)cancel:(id)sender {
31   if (![self isOwned])
32     return;
33   if ([self delegate]->AsConfirmInfoBarDelegate()->Cancel())
34     [self removeSelf];
37 // Confirm infobars can have OK and/or cancel buttons, depending on
38 // the return value of GetButtons().  We create each button if
39 // required and position them to the left of the close button.
40 - (void)addAdditionalControls {
41   ConfirmInfoBarDelegate* delegate =
42       [self delegate]->AsConfirmInfoBarDelegate();
43   DCHECK(delegate);
44   int visibleButtons = delegate->GetButtons();
46   NSRect okButtonFrame = [okButton_ frame];
47   NSRect cancelButtonFrame = [cancelButton_ frame];
49   DCHECK(NSMaxX(cancelButtonFrame) < NSMinX(okButtonFrame))
50       << "Ok button expected to be on the right of the Cancel button in nib";
52   CGFloat rightEdge = NSMaxX(okButtonFrame);
53   CGFloat spaceBetweenButtons =
54       NSMinX(okButtonFrame) - NSMaxX(cancelButtonFrame);
55   CGFloat spaceBeforeButtons =
56       NSMinX(cancelButtonFrame) - NSMaxX([label_.get() frame]);
58   // Update and position the OK button if needed.  Otherwise, hide it.
59   if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) {
60     [okButton_ setTitle:base::SysUTF16ToNSString(
61           delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))];
62     [GTMUILocalizerAndLayoutTweaker sizeToFitView:okButton_];
63     okButtonFrame = [okButton_ frame];
65     // Position the ok button to the left of the Close button.
66     okButtonFrame.origin.x = rightEdge - okButtonFrame.size.width;
67     [okButton_ setFrame:okButtonFrame];
69     // Update the rightEdge
70     rightEdge = NSMinX(okButtonFrame);
71   } else {
72     [okButton_ removeFromSuperview];
73     okButton_ = nil;
74   }
76   // Update and position the Cancel button if needed.  Otherwise, hide it.
77   if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
78     [cancelButton_ setTitle:base::SysUTF16ToNSString(
79           delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))];
80     [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
81     cancelButtonFrame = [cancelButton_ frame];
83     // If we had a Ok button, leave space between the buttons.
84     if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) {
85       rightEdge -= spaceBetweenButtons;
86     }
88     // Position the Cancel button on our current right edge.
89     cancelButtonFrame.origin.x = rightEdge - cancelButtonFrame.size.width;
90     [cancelButton_ setFrame:cancelButtonFrame];
92     // Update the rightEdge.
93     rightEdge = NSMinX(cancelButtonFrame);
94   } else {
95     [cancelButton_ removeFromSuperview];
96     cancelButton_ = nil;
97   }
99   // If we had either button, leave space before the edge of the textfield.
100   if ((visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) ||
101       (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK)) {
102     rightEdge -= spaceBeforeButtons;
103   }
105   NSRect frame = [label_.get() frame];
106   DCHECK(rightEdge > NSMinX(frame))
107       << "Need to make the xib larger to handle buttons with text this long";
108   frame.size.width = rightEdge - NSMinX(frame);
109   [label_.get() setFrame:frame];
111   // Set the text and link.
112   NSString* message = base::SysUTF16ToNSString(delegate->GetMessageText());
113   NSString* link = base::SysUTF16ToNSString(delegate->GetLinkText());
114   NSUInteger linkOffset = [message length];
115   NSUInteger linkLength = [link length];
116   if (linkLength != 0) {
117     // Add spacing between the label and the link.
118     message = [message stringByAppendingFormat:@"   %@", link];
119     linkOffset = [message length] - [link length];
120   }
121   NSFont* font = [NSFont labelFontOfSize:
122       [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
123   HyperlinkTextView* view = (HyperlinkTextView*)label_.get();
124   [view setMessage:message withFont:font messageColor:[NSColor blackColor]];
125   if (linkLength != 0) {
126     NSColor* linkColor =
127         gfx::SkColorToCalibratedNSColor(chrome_style::GetLinkColor());
128     [view addLinkRange:NSMakeRange(linkOffset, linkLength)
129               withName:@""
130              linkColor:linkColor];
131   }
134 // Called when someone clicks on the link in the infobar.  This method
135 // is called by the InfobarTextField on its delegate (the
136 // AlternateNavInfoBarController).
137 - (void)linkClicked {
138   if (![self isOwned])
139     return;
140   WindowOpenDisposition disposition =
141       ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
142   if ([self delegate]->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
143     [self removeSelf];
146 @end
148 scoped_ptr<infobars::InfoBar> InfoBarService::CreateConfirmInfoBar(
149     scoped_ptr<ConfirmInfoBarDelegate> delegate) {
150   scoped_ptr<InfoBarCocoa> infobar(new InfoBarCocoa(delegate.Pass()));
151   base::scoped_nsobject<ConfirmInfoBarController> controller(
152       [[ConfirmInfoBarController alloc] initWithInfoBar:infobar.get()]);
153   infobar->set_controller(controller);
154   return infobar.Pass();