- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / dev_tools_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/dev_tools_controller.h"
6
7 #include <algorithm>
8
9 #include <Cocoa/Cocoa.h>
10
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #import "chrome/browser/ui/cocoa/view_id_util.h"
15 #include "chrome/common/pref_names.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "ui/base/cocoa/focus_tracker.h"
19
20 using content::WebContents;
21
22 @interface GraySplitView : NSSplitView {
23   BOOL dividerHidden_;
24 }
25
26 @property(assign, nonatomic) BOOL dividerHidden;
27
28 - (NSColor*)dividerColor;
29 - (CGFloat)dividerThickness;
30
31 @end
32
33
34 @implementation GraySplitView
35
36 @synthesize dividerHidden = dividerHidden_;
37
38 - (NSColor*)dividerColor {
39   return [NSColor darkGrayColor];
40 }
41
42 - (CGFloat)dividerThickness {
43   return dividerHidden_ ? 0 : [super dividerThickness];
44 }
45
46 @end
47
48 @interface DevToolsController (Private)
49 - (void)showDevToolsContainer;
50 - (void)hideDevToolsContainer;
51 - (void)updateDevToolsSplitPosition;
52 @end
53
54
55 @implementation DevToolsController
56
57 - (id)init {
58   if ((self = [super init])) {
59     splitView_.reset([[GraySplitView alloc] initWithFrame:NSZeroRect]);
60     [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
61     [splitView_ setVertical:NO];
62     [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
63     [splitView_ setDelegate:self];
64     [splitView_ setDividerHidden:NO];
65
66     dockSide_ = DEVTOOLS_DOCK_SIDE_BOTTOM;
67   }
68   return self;
69 }
70
71 - (void)dealloc {
72   [splitView_ setDelegate:nil];
73   [super dealloc];
74 }
75
76 - (NSView*)view {
77   return splitView_.get();
78 }
79
80 - (NSSplitView*)splitView {
81   return splitView_.get();
82 }
83
84 - (void)updateDevToolsForWebContents:(WebContents*)contents
85                          withProfile:(Profile*)profile {
86   DevToolsWindow* newDevToolsWindow = contents ?
87       DevToolsWindow::GetDockedInstanceForInspectedTab(contents) : NULL;
88
89   // Fast return in case of the same window having same orientation.
90   if (devToolsWindow_ == newDevToolsWindow) {
91     if (!newDevToolsWindow ||
92         (newDevToolsWindow->dock_side() == dockSide_)) {
93       return;
94     }
95   }
96
97   // Store last used position.
98   if (devToolsWindow_) {
99     NSArray* subviews = [splitView_ subviews];
100     DCHECK_EQ([subviews count], 2u);
101     NSView* devToolsView = [subviews objectAtIndex:1];
102     if (dockSide_ == DEVTOOLS_DOCK_SIDE_RIGHT)
103       devToolsWindow_->SetWidth(NSWidth([devToolsView frame]));
104     else if (dockSide_ == DEVTOOLS_DOCK_SIDE_BOTTOM)
105       devToolsWindow_->SetHeight(NSHeight([devToolsView frame]));
106   }
107
108   if (devToolsWindow_)
109     [self hideDevToolsContainer];
110
111   devToolsWindow_ = newDevToolsWindow;
112
113   if (devToolsWindow_) {
114     dockSide_ = devToolsWindow_->dock_side();
115     [self showDevToolsContainer];
116   }
117 }
118
119 - (void)showDevToolsContainer {
120   NSArray* subviews = [splitView_ subviews];
121   DCHECK_EQ([subviews count], 1u);
122   WebContents* devToolsContents = devToolsWindow_->web_contents();
123   focusTracker_.reset(
124       [[FocusTracker alloc] initWithWindow:[splitView_ window]]);
125
126   // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
127   // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
128   // VIEW_ID_DEV_TOOLS_DOCKED here.
129   NSView* devToolsView = devToolsContents->GetView()->GetNativeView();
130   view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED);
131   [splitView_ addSubview:devToolsView];
132
133   BOOL isVertical = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT;
134   [splitView_ setVertical:isVertical];
135   [self updateDevToolsSplitPosition];
136 }
137
138 - (void)hideDevToolsContainer {
139   NSArray* subviews = [splitView_ subviews];
140   DCHECK_EQ([subviews count], 2u);
141   NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
142   [oldDevToolsContentsView removeFromSuperview];
143   [splitView_ adjustSubviews];
144   [focusTracker_ restoreFocusInWindow:[splitView_ window]];
145   focusTracker_.reset();
146 }
147
148 - (void)updateDevToolsSplitPosition {
149   NSArray* subviews = [splitView_ subviews];
150
151   // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
152   // but I can't figure out how to use it. Manually resize web and devtools.
153   // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
154   // category on NSSplitView to handle manual resizing.
155   NSView* webView = [subviews objectAtIndex:0];
156   NSRect webFrame = [webView frame];
157   NSView* devToolsView = [subviews objectAtIndex:1];
158   NSRect devToolsFrame = [devToolsView frame];
159
160   BOOL noDivider = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED;
161   [splitView_ setDividerHidden:noDivider];
162
163   if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) {
164     CGFloat size = devToolsWindow_->GetWidth(NSWidth([splitView_ frame]));
165     devToolsFrame.size.width = size;
166     webFrame.size.width =
167         NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + size);
168   } else {
169     CGFloat size =
170         devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED ?
171             devToolsWindow_->GetMinimizedHeight() :
172             devToolsWindow_->GetHeight(NSHeight([splitView_ frame]));
173     devToolsFrame.size.height = size;
174     webFrame.size.height =
175         NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + size);
176   }
177
178   [[splitView_ window] disableScreenUpdatesUntilFlush];
179   [webView setFrame:webFrame];
180   [devToolsView setFrame:devToolsFrame];
181
182   [splitView_ adjustSubviews];
183 }
184
185 // NSSplitViewDelegate protocol.
186 - (BOOL)splitView:(NSSplitView *)splitView
187     shouldAdjustSizeOfSubview:(NSView *)subview {
188   // Return NO for the devTools view to indicate that it should not be resized
189   // automatically. It preserves the height set by the user and also keeps
190   // view height the same while changing tabs when one of the tabs shows infobar
191   // and others are not.
192   if ([[splitView_ subviews] indexOfObject:subview] == 1)
193     return NO;
194   return YES;
195 }
196
197 - (NSRect)splitView:(NSSplitView*)splitView
198       effectiveRect:(NSRect)proposedEffectiveRect
199        forDrawnRect:(NSRect)drawnRect
200    ofDividerAtIndex:(NSInteger)dividerIndex {
201   if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED) {
202     return NSZeroRect;
203   } else {
204     return proposedEffectiveRect;
205   }
206 }
207
208 - (CGFloat)splitView:(NSSplitView*)splitView
209     constrainMaxCoordinate:(CGFloat)proposedMax
210                ofSubviewAt:(NSInteger)dividerIndex {
211   if ([splitView_ isVertical]) {
212     return NSWidth([splitView_ frame]) - [splitView_ dividerThickness] -
213         devToolsWindow_->GetMinimumWidth();
214   } else {
215     return NSHeight([splitView_ frame]) - [splitView_ dividerThickness] -
216         devToolsWindow_->GetMinimumHeight();
217   }
218 }
219
220 - (CGFloat)splitView:(NSSplitView *)splitView
221     constrainSplitPosition:(CGFloat)proposedPosition
222                ofSubviewAt:(NSInteger)dividerIndex {
223   return round(proposedPosition);
224 }
225
226 -(void)splitViewWillResizeSubviews:(NSNotification *)notification {
227   [[splitView_ window] disableScreenUpdatesUntilFlush];
228 }
229
230 @end