blob: 95dec3b4aa86d239f2ede7f57aadbcc802465d9f [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "tab_view_picker_table.h"
#include "base/logging.h"
@interface TabViewPickerTable (Private)
// If a heading is shown, the indices between the tab items and the table rows
// are shifted by one. These functions convert between tab indices and table
// indices.
- (NSInteger)tabIndexFromTableIndex:(NSInteger)tableIndex;
- (NSInteger)tableIndexFromTabIndex:(NSInteger)tabIndex;
// Returns if |item| is the item shown as heading. If |heading_| is nil, this
// always returns |NO|.
- (BOOL)isHeadingItem:(id)item;
// Reloads the outline view and sets the selection to the row corresponding to
// the currently selected tab.
- (void)reloadDataWhileKeepingCurrentTabSelected;
@end
@implementation TabViewPickerTable
- (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:frame])) {
[self setDelegate:self];
[self setDataSource:self];
}
return self;
}
- (id)initWithCoder:(NSCoder*)coder {
if ((self = [super initWithCoder:coder])) {
[self setDelegate:self];
[self setDataSource:self];
}
return self;
}
- (void)awakeFromNib {
DCHECK(tabView_);
DCHECK_EQ([self delegate], self);
DCHECK_EQ([self dataSource], self);
DCHECK(![self allowsEmptySelection]);
DCHECK(![self allowsMultipleSelection]);
// Suppress the "Selection changed" message that's sent while the table is
// being built for the first time (this causes a selection change to index 0
// and back to the prior index).
id oldTabViewDelegate = [tabView_ delegate];
[tabView_ setDelegate:nil];
[self reloadDataWhileKeepingCurrentTabSelected];
oldTabViewDelegate_ = oldTabViewDelegate;
[tabView_ setDelegate:self];
}
- (NSString*)heading {
return heading_.get();
}
- (void)setHeading:(NSString*)str {
heading_.reset([str copy]);
[self reloadDataWhileKeepingCurrentTabSelected];
}
- (void)reloadDataWhileKeepingCurrentTabSelected {
NSInteger index =
[tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]];
[self reloadData];
if (heading_)
[self expandItem:[self outlineView:self child:0 ofItem:nil]];
NSIndexSet* indexSet =
[NSIndexSet indexSetWithIndex:[self tableIndexFromTabIndex:index]];
[self selectRowIndexes:indexSet byExtendingSelection:NO];
}
// NSTabViewDelegate methods.
- (void) tabView:(NSTabView*)tabView
didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
DCHECK_EQ(tabView_, tabView);
NSInteger index =
[tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]];
NSIndexSet* indexSet =
[NSIndexSet indexSetWithIndex:[self tableIndexFromTabIndex:index]];
[self selectRowIndexes:indexSet byExtendingSelection:NO];
if ([oldTabViewDelegate_
respondsToSelector:@selector(tabView:didSelectTabViewItem:)]) {
[oldTabViewDelegate_ tabView:tabView didSelectTabViewItem:tabViewItem];
}
}
- (BOOL) tabView:(NSTabView*)tabView
shouldSelectTabViewItem:(NSTabViewItem*)tabViewItem {
if ([oldTabViewDelegate_
respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) {
return [oldTabViewDelegate_ tabView:tabView
shouldSelectTabViewItem:tabViewItem];
}
return YES;
}
- (void) tabView:(NSTabView*)tabView
willSelectTabViewItem:(NSTabViewItem*)tabViewItem {
if ([oldTabViewDelegate_
respondsToSelector:@selector(tabView:willSelectTabViewItem:)]) {
[oldTabViewDelegate_ tabView:tabView willSelectTabViewItem:tabViewItem];
}
}
- (NSInteger)tabIndexFromTableIndex:(NSInteger)tableIndex {
if (!heading_)
return tableIndex;
DCHECK(tableIndex > 0);
return tableIndex - 1;
}
- (NSInteger)tableIndexFromTabIndex:(NSInteger)tabIndex {
DCHECK_GE(tabIndex, 0);
DCHECK_LT(tabIndex, [tabView_ numberOfTabViewItems]);
if (!heading_)
return tabIndex;
return tabIndex + 1;
}
- (BOOL)isHeadingItem:(id)item {
return item && item == heading_.get();
}
// NSOutlineViewDataSource methods.
- (NSInteger) outlineView:(NSOutlineView*)outlineView
numberOfChildrenOfItem:(id)item {
if (!item)
return heading_ ? 1 : [tabView_ numberOfTabViewItems];
return (item == heading_.get()) ? [tabView_ numberOfTabViewItems] : 0;
}
- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item {
return [self isHeadingItem:item];
}
- (id)outlineView:(NSOutlineView*)outlineView
child:(NSInteger)index
ofItem:(id)item {
if (!item) {
return heading_.get() ?
heading_.get() : static_cast<id>([tabView_ tabViewItemAtIndex:index]);
}
return (item == heading_.get()) ? [tabView_ tabViewItemAtIndex:index] : nil;
}
- (id) outlineView:(NSOutlineView*)outlineView
objectValueForTableColumn:(NSTableColumn*)tableColumn
byItem:(id)item {
if ([item isKindOfClass:[NSTabViewItem class]])
return [static_cast<NSTabViewItem*>(item) label];
if ([self isHeadingItem:item])
return [item uppercaseString];
return nil;
}
// NSOutlineViewDelegate methods.
- (void)outlineViewSelectionDidChange:(NSNotification*)notification {
int row = [self selectedRow];
[tabView_ selectTabViewItemAtIndex:[self tabIndexFromTableIndex:row]];
}
- (BOOL)outlineView:(NSOutlineView *)sender isGroupItem:(id)item {
return [self isHeadingItem:item];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView shouldExpandItem:(id)item {
return [self isHeadingItem:item];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView shouldCollapseItem:(id)item {
return NO;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item {
return ![self isHeadingItem:item];
}
// -outlineView:shouldShowOutlineCellForItem: is 10.6-only.
- (NSRect)frameOfOutlineCellAtRow:(NSInteger)row {
return NSZeroRect;
}
@end