Home | History | Annotate | Download | only in cocoa
      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
    231