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