• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2010 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/sidebar_controller.h"
6
7#include <algorithm>
8
9#include <Cocoa/Cocoa.h>
10
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/prefs/pref_service.h"
13#include "chrome/browser/sidebar/sidebar_manager.h"
14#import "chrome/browser/ui/cocoa/view_id_util.h"
15#include "chrome/common/pref_names.h"
16#include "content/browser/tab_contents/tab_contents.h"
17
18namespace {
19
20// By default sidebar width is 1/7th of the current page content width.
21const CGFloat kDefaultSidebarWidthRatio = 1.0 / 7;
22
23// Never make the web part of the tab contents smaller than this (needed if the
24// window is only a few pixels wide).
25const int kMinWebWidth = 50;
26
27}  // end namespace
28
29
30@interface SidebarController (Private)
31- (void)showSidebarContents:(TabContents*)sidebarContents;
32- (void)resizeSidebarToNewWidth:(CGFloat)width;
33@end
34
35
36@implementation SidebarController
37
38- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
39  if ((self = [super init])) {
40    splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
41    [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
42    [splitView_ setVertical:YES];
43    [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
44    [splitView_ setDelegate:self];
45
46    contentsController_.reset(
47        [[TabContentsController alloc] initWithContents:NULL
48                                               delegate:delegate]);
49  }
50  return self;
51}
52
53- (void)dealloc {
54  [splitView_ setDelegate:nil];
55  [super dealloc];
56}
57
58- (NSSplitView*)view {
59  return splitView_.get();
60}
61
62- (NSSplitView*)splitView {
63  return splitView_.get();
64}
65
66- (void)updateSidebarForTabContents:(TabContents*)contents {
67  // Get the active sidebar content.
68  if (SidebarManager::GetInstance() == NULL)  // Happens in tests.
69    return;
70
71  TabContents* sidebarContents = NULL;
72  if (contents && SidebarManager::IsSidebarAllowed()) {
73    SidebarContainer* activeSidebar =
74        SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
75    if (activeSidebar)
76      sidebarContents = activeSidebar->sidebar_contents();
77  }
78
79  TabContents* oldSidebarContents = [contentsController_ tabContents];
80  if (oldSidebarContents == sidebarContents)
81    return;
82
83  // Adjust sidebar view.
84  [self showSidebarContents:sidebarContents];
85
86  // Notify extensions.
87  SidebarManager::GetInstance()->NotifyStateChanges(
88      oldSidebarContents, sidebarContents);
89}
90
91- (void)ensureContentsVisible {
92  [contentsController_ ensureContentsVisible];
93}
94
95- (void)showSidebarContents:(TabContents*)sidebarContents {
96  [contentsController_ ensureContentsSizeDoesNotChange];
97
98  NSArray* subviews = [splitView_ subviews];
99  if (sidebarContents) {
100    DCHECK_GE([subviews count], 1u);
101
102    // Native view is a TabContentsViewCocoa object, whose ViewID was
103    // set to VIEW_ID_TAB_CONTAINER initially, so change it to
104    // VIEW_ID_SIDE_BAR_CONTAINER here.
105    view_id_util::SetID(
106        sidebarContents->GetNativeView(), VIEW_ID_SIDE_BAR_CONTAINER);
107
108    CGFloat sidebarWidth = 0;
109    if ([subviews count] == 1) {
110      // Load the default split offset.
111      sidebarWidth = g_browser_process->local_state()->GetInteger(
112          prefs::kExtensionSidebarWidth);
113      if (sidebarWidth < 0) {
114        // Initial load, set to default value.
115        sidebarWidth =
116            NSWidth([splitView_ frame]) * kDefaultSidebarWidthRatio;
117      }
118      [splitView_ addSubview:[contentsController_ view]];
119    } else {
120      DCHECK_EQ([subviews count], 2u);
121      sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
122    }
123
124    // Make sure |sidebarWidth| isn't too large or too small.
125    sidebarWidth = std::min(sidebarWidth,
126                            NSWidth([splitView_ frame]) - kMinWebWidth);
127    DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
128                               << "smallest available tab contents space.";
129    sidebarWidth = std::max(static_cast<CGFloat>(0), sidebarWidth);
130
131    [self resizeSidebarToNewWidth:sidebarWidth];
132  } else {
133    if ([subviews count] > 1) {
134      NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
135      // Store split offset when hiding sidebar window only.
136      int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
137      g_browser_process->local_state()->SetInteger(
138          prefs::kExtensionSidebarWidth, sidebarWidth);
139      [oldSidebarContentsView removeFromSuperview];
140      [splitView_ adjustSubviews];
141    }
142  }
143
144  [contentsController_ changeTabContents:sidebarContents];
145}
146
147- (void)resizeSidebarToNewWidth:(CGFloat)width {
148  NSArray* subviews = [splitView_ subviews];
149
150  // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
151  // but I can't figure out how to use it. Manually resize web and sidebar.
152  // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
153  // category on NSSplitView to handle manual resizing.
154  NSView* sidebarView = [subviews objectAtIndex:1];
155  NSRect sidebarFrame = [sidebarView frame];
156  sidebarFrame.size.width = width;
157  [sidebarView setFrame:sidebarFrame];
158
159  NSView* webView = [subviews objectAtIndex:0];
160  NSRect webFrame = [webView frame];
161  webFrame.size.width =
162      NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + width);
163  [webView setFrame:webFrame];
164
165  [splitView_ adjustSubviews];
166}
167
168// NSSplitViewDelegate protocol.
169- (BOOL)splitView:(NSSplitView *)splitView
170    shouldAdjustSizeOfSubview:(NSView *)subview {
171  // Return NO for the sidebar view to indicate that it should not be resized
172  // automatically.  The sidebar keeps the width set by the user.
173  if ([[splitView_ subviews] indexOfObject:subview] == 1)
174    return NO;
175  return YES;
176}
177
178@end
179