Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / global_error_bubble_controller.mm
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.
4
5 #import "chrome/browser/ui/cocoa/global_error_bubble_controller.h"
6
7 #include "base/logging.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #import "chrome/browser/ui/browser.h"
13 #import "chrome/browser/ui/browser_window.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
16 #import "chrome/browser/ui/cocoa/l10n_util.h"
17 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
18 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h"
19 #include "chrome/browser/ui/global_error/global_error.h"
20 #include "chrome/browser/ui/global_error/global_error_bubble_view_base.h"
21 #include "chrome/browser/ui/global_error/global_error_service.h"
22 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
23 #include "components/search_engines/util.h"
24 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/image/image.h"
27
28 namespace {
29 const CGFloat kParagraphSpacing = 6;
30 } // namespace
31
32 namespace GlobalErrorBubbleControllerInternal {
33
34 // This is the bridge to the C++ GlobalErrorBubbleViewBase object.
35 class Bridge : public GlobalErrorBubbleViewBase {
36  public:
37   Bridge(GlobalErrorBubbleController* controller) : controller_(controller) {
38   }
39
40  private:
41   virtual void CloseBubbleView() OVERRIDE {
42     [controller_ close];
43   }
44
45   GlobalErrorBubbleController* controller_;  // Weak, owns this.
46 };
47
48 }  // namespace GlobalErrorBubbleControllerInternal
49
50 @implementation GlobalErrorBubbleController
51
52 + (GlobalErrorBubbleViewBase*)showForBrowser:(Browser*)browser
53     error:(const base::WeakPtr<GlobalErrorWithStandardBubble>&)error {
54   NSWindow* parentWindow = browser->window()->GetNativeWindow();
55   BrowserWindowController* bwc = [BrowserWindowController
56       browserWindowControllerForWindow:parentWindow];
57   NSView* wrenchButton = [[bwc toolbarController] wrenchButton];
58   NSPoint offset = NSMakePoint(
59       NSMidX([wrenchButton bounds]),
60       wrench_menu_controller::kWrenchBubblePointOffsetY);
61
62   // The bubble will be automatically deleted when the window is closed.
63   GlobalErrorBubbleController* bubble = [[GlobalErrorBubbleController alloc]
64       initWithWindowNibPath:@"GlobalErrorBubble"
65              relativeToView:wrenchButton
66                      offset:offset];
67   bubble->error_ = error;
68   bubble->bridge_.reset(new GlobalErrorBubbleControllerInternal::Bridge(
69       bubble));
70   bubble->browser_ = browser;
71   [bubble showWindow:nil];
72
73   return bubble->bridge_.get();
74 }
75
76 - (void)awakeFromNib {
77   [super awakeFromNib];
78
79   DCHECK(error_);
80
81   gfx::Image image = error_->GetBubbleViewIcon();
82   DCHECK(!image.IsEmpty());
83   [iconView_ setImage:image.ToNSImage()];
84
85   [title_ setStringValue:SysUTF16ToNSString(error_->GetBubbleViewTitle())];
86   std::vector<base::string16> messages = error_->GetBubbleViewMessages();
87   base::string16 message = JoinString(messages, '\n');
88
89   base::scoped_nsobject<NSMutableAttributedString> messageValue(
90       [[NSMutableAttributedString alloc]
91           initWithString:SysUTF16ToNSString(message)]);
92   base::scoped_nsobject<NSMutableParagraphStyle> style(
93       [[NSMutableParagraphStyle alloc] init]);
94   [style setParagraphSpacing:kParagraphSpacing];
95   [messageValue addAttribute:NSParagraphStyleAttributeName
96                        value:style
97                        range:NSMakeRange(0, [messageValue length])];
98
99   [message_ setAttributedStringValue:messageValue];
100
101   [acceptButton_ setTitle:
102       SysUTF16ToNSString(error_->GetBubbleViewAcceptButtonLabel())];
103   base::string16 cancelLabel = error_->GetBubbleViewCancelButtonLabel();
104   if (cancelLabel.empty())
105     [cancelButton_ setHidden:YES];
106   else
107     [cancelButton_ setTitle:SysUTF16ToNSString(cancelLabel)];
108
109   // First make sure that the window is wide enough to accommodate the buttons.
110   NSRect frame = [[self window] frame];
111   [layoutTweaker_ tweakUI:buttonContainer_];
112   CGFloat delta =  NSWidth([buttonContainer_ frame]) - NSWidth(frame);
113   if (delta > 0) {
114     frame.size.width += delta;
115     [[self window] setFrame:frame display:NO];
116   }
117
118   // Adapt window height to bottom buttons. Do this before all other layouting.
119   NSArray* views = [NSArray arrayWithObjects:
120       title_, message_, buttonContainer_, nil];
121   NSSize ds = NSMakeSize(0, cocoa_l10n_util::VerticallyReflowGroup(views));
122   ds = [[self bubble] convertSize:ds toView:nil];
123
124   frame.origin.y -= ds.height;
125   frame.size.height += ds.height;
126   [[self window] setFrame:frame display:YES];
127 }
128
129 - (void)showWindow:(id)sender {
130   BrowserWindowController* bwc = [BrowserWindowController
131       browserWindowControllerForWindow:[self parentWindow]];
132   [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
133   [super showWindow:sender];
134 }
135
136 - (void)close {
137   if (error_)
138     error_->BubbleViewDidClose(browser_);
139   bridge_.reset();
140   BrowserWindowController* bwc = [BrowserWindowController
141       browserWindowControllerForWindow:[self parentWindow]];
142   [bwc releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
143   [super close];
144 }
145
146 - (IBAction)onAccept:(id)sender {
147   if (error_)
148     error_->BubbleViewAcceptButtonPressed(browser_);
149   [self close];
150 }
151
152 - (IBAction)onCancel:(id)sender {
153   if (error_)
154     error_->BubbleViewCancelButtonPressed(browser_);
155   [self close];
156 }
157
158 @end
159
160 GlobalErrorBubbleViewBase* GlobalErrorBubbleViewBase::ShowStandardBubbleView(
161     Browser* browser,
162     const base::WeakPtr<GlobalErrorWithStandardBubble>& error) {
163   return [GlobalErrorBubbleController showForBrowser:browser error:error];
164 }