Home | History | Annotate | Download | only in cocoa
      1 // Copyright (c) 2011 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 "chrome/browser/browser_process.h"
     12 #include "chrome/browser/debugger/devtools_window.h"
     13 #include "chrome/browser/prefs/pref_service.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     16 #import "chrome/browser/ui/cocoa/view_id_util.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "content/browser/tab_contents/tab_contents.h"
     19 
     20 namespace {
     21 
     22 // Default offset of the contents splitter in pixels.
     23 const int kDefaultContentsSplitOffset = 400;
     24 
     25 // Never make the web part of the tab contents smaller than this (needed if the
     26 // window is only a few pixels high).
     27 const int kMinWebHeight = 50;
     28 
     29 }  // end namespace
     30 
     31 
     32 @interface DevToolsController (Private)
     33 - (void)showDevToolsContents:(TabContents*)devToolsContents
     34                  withProfile:(Profile*)profile;
     35 - (void)resizeDevToolsToNewHeight:(CGFloat)height;
     36 @end
     37 
     38 
     39 @implementation DevToolsController
     40 
     41 - (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
     42   if ((self = [super init])) {
     43     splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
     44     [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
     45     [splitView_ setVertical:NO];
     46     [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
     47     [splitView_ setDelegate:self];
     48 
     49     contentsController_.reset(
     50         [[TabContentsController alloc] initWithContents:NULL
     51                                                delegate:delegate]);
     52   }
     53   return self;
     54 }
     55 
     56 - (void)dealloc {
     57   [splitView_ setDelegate:nil];
     58   [super dealloc];
     59 }
     60 
     61 - (NSView*)view {
     62   return splitView_.get();
     63 }
     64 
     65 - (NSSplitView*)splitView {
     66   return splitView_.get();
     67 }
     68 
     69 - (void)updateDevToolsForTabContents:(TabContents*)contents
     70                          withProfile:(Profile*)profile {
     71   // Get current devtools content.
     72   TabContentsWrapper* devToolsTab = contents ?
     73       DevToolsWindow::GetDevToolsContents(contents) : NULL;
     74   TabContents* devToolsContents = devToolsTab ?
     75       devToolsTab->tab_contents() : NULL;
     76 
     77   [self showDevToolsContents:devToolsContents withProfile:profile];
     78 }
     79 
     80 - (void)ensureContentsVisible {
     81   [contentsController_ ensureContentsVisible];
     82 }
     83 
     84 - (void)showDevToolsContents:(TabContents*)devToolsContents
     85                  withProfile:(Profile*)profile {
     86   [contentsController_ ensureContentsSizeDoesNotChange];
     87 
     88   NSArray* subviews = [splitView_ subviews];
     89   if (devToolsContents) {
     90     DCHECK_GE([subviews count], 1u);
     91 
     92     // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
     93     // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
     94     // VIEW_ID_DEV_TOOLS_DOCKED here.
     95     view_id_util::SetID(
     96         devToolsContents->GetNativeView(), VIEW_ID_DEV_TOOLS_DOCKED);
     97 
     98     CGFloat splitOffset = 0;
     99     if ([subviews count] == 1) {
    100       // Load the default split offset.
    101       splitOffset = profile->GetPrefs()->
    102           GetInteger(prefs::kDevToolsSplitLocation);
    103       if (splitOffset < 0) {
    104         // Initial load, set to default value.
    105         splitOffset = kDefaultContentsSplitOffset;
    106       }
    107       [splitView_ addSubview:[contentsController_ view]];
    108     } else {
    109       DCHECK_EQ([subviews count], 2u);
    110       // If devtools are already visible, keep the current size.
    111       splitOffset = NSHeight([[subviews objectAtIndex:1] frame]);
    112     }
    113 
    114     // Make sure |splitOffset| isn't too large or too small.
    115     splitOffset = std::max(static_cast<CGFloat>(kMinWebHeight), splitOffset);
    116     splitOffset =
    117         std::min(splitOffset, NSHeight([splitView_ frame]) - kMinWebHeight);
    118     DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
    119                               << "smallest available tab contents space.";
    120 
    121     [self resizeDevToolsToNewHeight:splitOffset];
    122   } else {
    123     if ([subviews count] > 1) {
    124       NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
    125       // Store split offset when hiding devtools window only.
    126       int splitOffset = NSHeight([oldDevToolsContentsView frame]);
    127 
    128       profile->GetPrefs()->SetInteger(
    129           prefs::kDevToolsSplitLocation, splitOffset);
    130       [oldDevToolsContentsView removeFromSuperview];
    131       [splitView_ adjustSubviews];
    132     }
    133   }
    134 
    135   [contentsController_ changeTabContents:devToolsContents];
    136 }
    137 
    138 - (void)resizeDevToolsToNewHeight:(CGFloat)height {
    139   NSArray* subviews = [splitView_ subviews];
    140 
    141   // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
    142   // but I can't figure out how to use it. Manually resize web and devtools.
    143   // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
    144   // category on NSSplitView to handle manual resizing.
    145   NSView* devToolsView = [subviews objectAtIndex:1];
    146   NSRect devToolsFrame = [devToolsView frame];
    147   devToolsFrame.size.height = height;
    148   [devToolsView setFrame:devToolsFrame];
    149 
    150   NSView* webView = [subviews objectAtIndex:0];
    151   NSRect webFrame = [webView frame];
    152   webFrame.size.height =
    153       NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + height);
    154   [webView setFrame:webFrame];
    155 
    156   [splitView_ adjustSubviews];
    157 }
    158 
    159 // NSSplitViewDelegate protocol.
    160 - (BOOL)splitView:(NSSplitView *)splitView
    161     shouldAdjustSizeOfSubview:(NSView *)subview {
    162   // Return NO for the devTools view to indicate that it should not be resized
    163   // automatically. It preserves the height set by the user and also keeps
    164   // view height the same while changing tabs when one of the tabs shows infobar
    165   // and others are not.
    166   if ([[splitView_ subviews] indexOfObject:subview] == 1)
    167     return NO;
    168   return YES;
    169 }
    170 
    171 @end
    172