Introduced IDR_SIGNIN_INTERNALS_INDEX_* strings to grit_whitelist.txt
[chromium-blink-merge.git] / remoting / host / disconnect_window_mac.mm
blob9cb170a3b724966296942540a40ee34eade734df
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 <Cocoa/Cocoa.h>
7 #import "remoting/host/disconnect_window_mac.h"
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/i18n/rtl.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "remoting/base/string_resources.h"
16 #include "remoting/host/client_session_control.h"
17 #include "remoting/host/host_window.h"
18 #include "ui/base/l10n/l10n_util_mac.h"
20 @interface DisconnectWindowController()
21 - (BOOL)isRToL;
22 - (void)Hide;
23 @end
25 const int kMaximumConnectedNameWidthInPixels = 600;
27 namespace remoting {
29 class DisconnectWindowMac : public HostWindow {
30  public:
31   DisconnectWindowMac();
32   virtual ~DisconnectWindowMac();
34   // HostWindow overrides.
35   virtual void Start(
36       const base::WeakPtr<ClientSessionControl>& client_session_control)
37       OVERRIDE;
39  private:
40   DisconnectWindowController* window_controller_;
42   DISALLOW_COPY_AND_ASSIGN(DisconnectWindowMac);
45 DisconnectWindowMac::DisconnectWindowMac()
46     : window_controller_(nil) {
49 DisconnectWindowMac::~DisconnectWindowMac() {
50   DCHECK(CalledOnValidThread());
52   // DisconnectWindowController is responsible for releasing itself in its
53   // windowWillClose: method.
54   [window_controller_ Hide];
55   window_controller_ = nil;
58 void DisconnectWindowMac::Start(
59     const base::WeakPtr<ClientSessionControl>& client_session_control) {
60   DCHECK(CalledOnValidThread());
61   DCHECK(client_session_control);
62   DCHECK(window_controller_ == nil);
64   // Create the window.
65   base::Closure disconnect_callback =
66       base::Bind(&ClientSessionControl::DisconnectSession,
67                  client_session_control);
68   std::string client_jid = client_session_control->client_jid();
69   std::string username = client_jid.substr(0, client_jid.find('/'));
70   window_controller_ =
71       [[DisconnectWindowController alloc] initWithCallback:disconnect_callback
72                                                   username:username];
73   [window_controller_ showWindow:nil];
76 // static
77 scoped_ptr<HostWindow> HostWindow::CreateDisconnectWindow() {
78   return scoped_ptr<HostWindow>(new DisconnectWindowMac());
81 }  // namespace remoting
83 @implementation DisconnectWindowController
84 - (id)initWithCallback:(const base::Closure&)disconnect_callback
85               username:(const std::string&)username {
86   self = [super initWithWindowNibName:@"disconnect_window"];
87   if (self) {
88     disconnect_callback_ = disconnect_callback;
89     username_ = UTF8ToUTF16(username);
90   }
91   return self;
94 - (void)dealloc {
95   [super dealloc];
98 - (IBAction)stopSharing:(id)sender {
99   if (!disconnect_callback_.is_null()) {
100     disconnect_callback_.Run();
101   }
104 - (BOOL)isRToL {
105   return base::i18n::IsRTL();
108 - (void)Hide {
109   disconnect_callback_.Reset();
110   [self close];
113 - (void)windowDidLoad {
114   [connectedToField_ setStringValue:l10n_util::GetNSStringF(IDR_MESSAGE_SHARED,
115                                                             username_)];
116   [disconnectButton_ setTitle:l10n_util::GetNSString(IDR_STOP_SHARING_BUTTON)];
118   // Resize the window dynamically based on the content.
119   CGFloat oldConnectedWidth = NSWidth([connectedToField_ bounds]);
120   [connectedToField_ sizeToFit];
121   NSRect connectedToFrame = [connectedToField_ frame];
122   CGFloat newConnectedWidth = NSWidth(connectedToFrame);
124   // Set a max width for the connected to text field.
125   if (newConnectedWidth > kMaximumConnectedNameWidthInPixels) {
126     newConnectedWidth = kMaximumConnectedNameWidthInPixels;
127     connectedToFrame.size.width = newConnectedWidth;
128     [connectedToField_ setFrame:connectedToFrame];
129   }
131   CGFloat oldDisconnectWidth = NSWidth([disconnectButton_ bounds]);
132   [disconnectButton_ sizeToFit];
133   NSRect disconnectFrame = [disconnectButton_ frame];
134   CGFloat newDisconnectWidth = NSWidth(disconnectFrame);
136   // Move the disconnect button appropriately.
137   disconnectFrame.origin.x += newConnectedWidth - oldConnectedWidth;
138   [disconnectButton_ setFrame:disconnectFrame];
140   // Then resize the window appropriately
141   NSWindow *window = [self window];
142   NSRect windowFrame = [window frame];
143   windowFrame.size.width += (newConnectedWidth - oldConnectedWidth +
144                              newDisconnectWidth - oldDisconnectWidth);
145   [window setFrame:windowFrame display:NO];
147   if ([self isRToL]) {
148     // Handle right to left case
149     CGFloat buttonInset = NSWidth(windowFrame) - NSMaxX(disconnectFrame);
150     CGFloat buttonTextSpacing
151         = NSMinX(disconnectFrame) - NSMaxX(connectedToFrame);
152     disconnectFrame.origin.x = buttonInset;
153     connectedToFrame.origin.x = NSMaxX(disconnectFrame) + buttonTextSpacing;
154     [connectedToField_ setFrame:connectedToFrame];
155     [disconnectButton_ setFrame:disconnectFrame];
156   }
158   // Center the window at the bottom of the screen, above the dock (if present).
159   NSRect desktopRect = [[NSScreen mainScreen] visibleFrame];
160   NSRect windowRect = [[self window] frame];
161   CGFloat x = (NSWidth(desktopRect) - NSWidth(windowRect)) / 2;
162   CGFloat y = NSMinY(desktopRect);
163   [[self window] setFrameOrigin:NSMakePoint(x, y)];
166 - (void)windowWillClose:(NSNotification*)notification {
167   [self stopSharing:self];
168   [self autorelease];
171 @end
174 @interface DisconnectWindow()
175 - (BOOL)isRToL;
176 @end
178 @implementation DisconnectWindow
180 - (id)initWithContentRect:(NSRect)contentRect
181                 styleMask:(NSUInteger)aStyle
182                   backing:(NSBackingStoreType)bufferingType
183                   defer:(BOOL)flag {
184   // Pass NSBorderlessWindowMask for the styleMask to remove the title bar.
185   self = [super initWithContentRect:contentRect
186                           styleMask:NSBorderlessWindowMask
187                             backing:bufferingType
188                               defer:flag];
190   if (self) {
191     // Set window to be clear and non-opaque so we can see through it.
192     [self setBackgroundColor:[NSColor clearColor]];
193     [self setOpaque:NO];
194     [self setMovableByWindowBackground:YES];
196     // Pull the window up to Status Level so that it always displays.
197     [self setLevel:NSStatusWindowLevel];
198   }
199   return self;
202 - (BOOL)isRToL {
203   DCHECK([[self windowController] respondsToSelector:@selector(isRToL)]);
204   return [[self windowController] isRToL];
207 @end
210 @interface DisconnectView()
211 - (BOOL)isRToL;
212 @end
214 @implementation DisconnectView
216 - (BOOL)isRToL {
217   DCHECK([[self window] isKindOfClass:[DisconnectWindow class]]);
218   return [static_cast<DisconnectWindow*>([self window]) isRToL];
221 - (void)drawRect:(NSRect)rect {
222   // All magic numbers taken from screen shots provided by UX.
223   NSRect bounds = NSInsetRect([self bounds], 1, 1);
225   NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:bounds
226                                                        xRadius:5
227                                                        yRadius:5];
228   NSColor *gray = [NSColor colorWithCalibratedWhite:0.91 alpha:1.0];
229   [gray setFill];
230   [path fill];
231   [path setLineWidth:4];
232   NSColor *green = [NSColor colorWithCalibratedRed:0.13
233                                              green:0.69
234                                               blue:0.11
235                                              alpha:1.0];
236   [green setStroke];
237   [path stroke];
240   // Draw drag handle on proper side
241   const CGFloat kHeight = 21.0;
242   const CGFloat kBaseInset = 12.0;
243   const CGFloat kDragHandleWidth = 5.0;
245   NSColor *dark = [NSColor colorWithCalibratedWhite:0.70 alpha:1.0];
246   NSColor *light = [NSColor colorWithCalibratedWhite:0.97 alpha:1.0];
248   // Turn off aliasing so it's nice and crisp.
249   NSGraphicsContext *context = [NSGraphicsContext currentContext];
250   BOOL alias = [context shouldAntialias];
251   [context setShouldAntialias:NO];
253   // Handle bidirectional locales properly.
254   CGFloat inset = [self isRToL] ? NSMaxX(bounds) - kBaseInset - kDragHandleWidth
255                                 : kBaseInset;
257   NSPoint top = NSMakePoint(inset, NSMidY(bounds) - kHeight / 2.0);
258   NSPoint bottom = NSMakePoint(inset, top.y + kHeight);
260   path = [NSBezierPath bezierPath];
261   [path moveToPoint:top];
262   [path lineToPoint:bottom];
263   [dark setStroke];
264   [path stroke];
266   top.x += 1;
267   bottom.x += 1;
268   path = [NSBezierPath bezierPath];
269   [path moveToPoint:top];
270   [path lineToPoint:bottom];
271   [light setStroke];
272   [path stroke];
274   top.x += 2;
275   bottom.x += 2;
276   path = [NSBezierPath bezierPath];
277   [path moveToPoint:top];
278   [path lineToPoint:bottom];
279   [dark setStroke];
280   [path stroke];
282   top.x += 1;
283   bottom.x += 1;
284   path = [NSBezierPath bezierPath];
285   [path moveToPoint:top];
286   [path lineToPoint:bottom];
287   [light setStroke];
288   [path stroke];
290   [context setShouldAntialias:alias];
293 @end