Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / external_protocol_dialog.mm
blob8355c008dbc6e577154ded38c4ea3e77b27bc3fa
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/external_protocol_dialog.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/external_protocol/external_protocol_handler.h"
12 #include "chrome/browser/shell_integration.h"
13 #include "chrome/grit/chromium_strings.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "ui/base/l10n/l10n_util_mac.h"
16 #include "ui/gfx/text_elider.h"
18 ///////////////////////////////////////////////////////////////////////////////
19 // ExternalProtocolHandler
21 // static
22 void ExternalProtocolHandler::RunExternalProtocolDialog(
23     const GURL& url, int render_process_host_id, int routing_id,
24     ui::PageTransition page_transition, bool has_user_gesture) {
25   [[ExternalProtocolDialogController alloc] initWithGURL:&url
26                                      renderProcessHostId:render_process_host_id
27                                                routingId:routing_id];
30 ///////////////////////////////////////////////////////////////////////////////
31 // ExternalProtocolDialogController
33 @interface ExternalProtocolDialogController(Private)
34 - (void)alertEnded:(NSAlert *)alert
35         returnCode:(int)returnCode
36        contextInfo:(void*)contextInfo;
37 @end
39 @implementation ExternalProtocolDialogController
40 - (id)initWithGURL:(const GURL*)url
41     renderProcessHostId:(int)renderProcessHostId
42     routingId:(int)routingId {
43   DCHECK(base::MessageLoopForUI::IsCurrent());
45   if (!(self = [super init]))
46     return nil;
48   url_ = *url;
49   render_process_host_id_ = renderProcessHostId;
50   routing_id_ = routingId;
51   creation_time_ = base::Time::Now();
53   base::string16 appName =
54       ShellIntegration::GetApplicationNameForProtocol(url_);
55   if (appName.length() == 0) {
56     // No registered apps for this protocol; give up and go home.
57     [self autorelease];
58     return nil;
59   }
61   alert_ = [[NSAlert alloc] init];
63   [alert_ setMessageText:
64       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];
66   NSButton* allowButton = [alert_ addButtonWithTitle:
67       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
68   [allowButton setKeyEquivalent:@""];  // disallow as default
69   [alert_ addButtonWithTitle:
70       l10n_util::GetNSStringWithFixup(
71         IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
73   const int kMaxUrlWithoutSchemeSize = 256;
74   base::string16 elided_url_without_scheme;
75   gfx::ElideString(base::ASCIIToUTF16(url_.possibly_invalid_spec()),
76                   kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
78   NSString* urlString = l10n_util::GetNSStringFWithFixup(
79       IDS_EXTERNAL_PROTOCOL_INFORMATION,
80       base::ASCIIToUTF16(url_.scheme() + ":"),
81       elided_url_without_scheme);
82   NSString* appString = l10n_util::GetNSStringFWithFixup(
83       IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
84       appName);
85   NSString* warningString =
86       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
87   NSString* informativeText =
88       [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
89                                  urlString,
90                                  appString,
91                                  warningString];
93   [alert_ setInformativeText:informativeText];
95   [alert_ setShowsSuppressionButton:YES];
96   [[alert_ suppressionButton] setTitle:
97       l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
99   [alert_ beginSheetModalForWindow:nil  // nil here makes it app-modal
100                      modalDelegate:self
101                     didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
102                        contextInfo:nil];
104   return self;
107 - (void)dealloc {
108   [alert_ release];
110   [super dealloc];
113 - (void)alertEnded:(NSAlert *)alert
114         returnCode:(int)returnCode
115        contextInfo:(void*)contextInfo {
116   ExternalProtocolHandler::BlockState blockState =
117       ExternalProtocolHandler::UNKNOWN;
118   switch (returnCode) {
119     case NSAlertFirstButtonReturn:
120       blockState = ExternalProtocolHandler::DONT_BLOCK;
121       break;
122     case NSAlertSecondButtonReturn:
123       blockState = ExternalProtocolHandler::BLOCK;
124       break;
125     default:
126       NOTREACHED();
127   }
129   // Set the "don't warn me again" info.
130   if ([[alert_ suppressionButton] state] == NSOnState)
131     ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
133   if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
134     UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
135                              base::Time::Now() - creation_time_);
137     ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
138         url_, render_process_host_id_, routing_id_);
139   }
141   [self autorelease];
144 @end