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