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 20namespace { 21 22// Default offset of the contents splitter in pixels. 23const 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). 27const 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