// 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([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(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