| Index: chrome/browser/cocoa/table_model_array_controller.mm
|
| diff --git a/chrome/browser/cocoa/table_model_array_controller.mm b/chrome/browser/cocoa/table_model_array_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e88e6e103cf8a60701a7a6d0ecc6390cd822ce6a
|
| --- /dev/null
|
| +++ b/chrome/browser/cocoa/table_model_array_controller.mm
|
| @@ -0,0 +1,245 @@
|
| +// 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 "chrome/browser/cocoa/table_model_array_controller.h"
|
| +
|
| +#include "app/table_model.h"
|
| +#include "base/sys_string_conversions.h"
|
| +#include "chrome/browser/remove_rows_table_model.h"
|
| +
|
| +@interface TableModelArrayController (PrivateMethods)
|
| +
|
| +- (NSUInteger)offsetForGroupID:(int)groupID;
|
| +- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset;
|
| +- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range;
|
| +- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
|
| + fromControllerRows:(NSIndexSet*)rows;
|
| +- (void)modelDidChange;
|
| +- (void)modelDidAddItemsInRange:(NSRange)range;
|
| +- (void)modelDidRemoveItemsInRange:(NSRange)range;
|
| +- (NSDictionary*)columnValuesForRow:(NSInteger)row;
|
| +
|
| +@end
|
| +
|
| +// Observer for a RemoveRowsTableModel.
|
| +class RemoveRowsObserverBridge : public TableModelObserver {
|
| + public:
|
| + RemoveRowsObserverBridge(TableModelArrayController* controller)
|
| + : controller_(controller) {}
|
| + virtual ~RemoveRowsObserverBridge() {}
|
| +
|
| + // TableModelObserver methods
|
| + virtual void OnModelChanged();
|
| + virtual void OnItemsChanged(int start, int length);
|
| + virtual void OnItemsAdded(int start, int length);
|
| + virtual void OnItemsRemoved(int start, int length);
|
| +
|
| + private:
|
| + TableModelArrayController* controller_; // weak
|
| +};
|
| +
|
| +void RemoveRowsObserverBridge::OnModelChanged() {
|
| + [controller_ modelDidChange];
|
| +}
|
| +
|
| +void RemoveRowsObserverBridge::OnItemsChanged(int start, int length) {
|
| + OnItemsRemoved(start, length);
|
| + OnItemsAdded(start, length);
|
| +}
|
| +
|
| +void RemoveRowsObserverBridge::OnItemsAdded(int start, int length) {
|
| + [controller_ modelDidAddItemsInRange:NSMakeRange(start, length)];
|
| +}
|
| +
|
| +void RemoveRowsObserverBridge::OnItemsRemoved(int start, int length) {
|
| + [controller_ modelDidRemoveItemsInRange:NSMakeRange(start, length)];
|
| +}
|
| +
|
| +@implementation TableModelArrayController
|
| +
|
| +static NSString* const kIsGroupRow = @"_is_group_row";
|
| +static NSString* const kGroupID = @"_group_id";
|
| +
|
| +- (void)bindToTableModel:(RemoveRowsTableModel*)model
|
| + withColumns:(NSDictionary*)columns
|
| + groupTitleColumn:(NSString*)groupTitleColumn {
|
| + model_ = model;
|
| + tableObserver_.reset(new RemoveRowsObserverBridge(self));
|
| + columns_.reset([columns copy]);
|
| + groupTitle_.reset([groupTitleColumn copy]);
|
| + model_->SetObserver(tableObserver_.get());
|
| + [self modelDidChange];
|
| +}
|
| +
|
| +- (void)modelDidChange {
|
| + NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:
|
| + NSMakeRange(0, [[self arrangedObjects] count])];
|
| + [self removeObjectsAtArrangedObjectIndexes:indexes];
|
| + if (model_->HasGroups()) {
|
| + const TableModel::Groups& groups = model_->GetGroups();
|
| + DCHECK(groupTitle_.get());
|
| + for (TableModel::Groups::const_iterator it = groups.begin();
|
| + it != groups.end(); ++it) {
|
| + NSDictionary* group = [NSDictionary dictionaryWithObjectsAndKeys:
|
| + base::SysWideToNSString(it->title), groupTitle_.get(),
|
| + [NSNumber numberWithBool:YES], kIsGroupRow,
|
| + nil];
|
| + [self addObject:group];
|
| + }
|
| + }
|
| + [self modelDidAddItemsInRange:NSMakeRange(0, model_->RowCount())];
|
| +}
|
| +
|
| +- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset {
|
| + const TableModel::Groups& groups = model_->GetGroups();
|
| + DCHECK_GT(offset, 0u);
|
| + for (NSUInteger i = offset - 1; i < groups.size(); ++i) {
|
| + if (groups[i].id == groupID)
|
| + return i + 1;
|
| + }
|
| + NOTREACHED();
|
| + return NSNotFound;
|
| +}
|
| +
|
| +- (NSUInteger)offsetForGroupID:(int)groupID {
|
| + return [self offsetForGroupID:groupID startingOffset:1];
|
| +}
|
| +
|
| +- (int)groupIDForControllerRow:(NSUInteger)row {
|
| + NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
|
| + return [[values objectForKey:kGroupID] intValue];
|
| +}
|
| +
|
| +- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
|
| + fromControllerRows:(NSIndexSet*)rows {
|
| + if ([rows count] == 0)
|
| + return;
|
| +
|
| + if (!model_->HasGroups()) {
|
| + for (NSUInteger i = [rows firstIndex];
|
| + i != NSNotFound;
|
| + i = [rows indexGreaterThanIndex:i]) {
|
| + modelRows->insert(i);
|
| + }
|
| + return;
|
| + }
|
| +
|
| + NSUInteger offset = 1;
|
| + for (NSUInteger i = [rows firstIndex];
|
| + i != NSNotFound;
|
| + i = [rows indexGreaterThanIndex:i]) {
|
| + int group = [self groupIDForControllerRow:i];
|
| + offset = [self offsetForGroupID:group startingOffset:offset];
|
| + modelRows->insert(i - offset);
|
| + }
|
| +}
|
| +
|
| +- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range {
|
| + if (!model_->HasGroups())
|
| + return [NSIndexSet indexSetWithIndexesInRange:range];
|
| + NSMutableIndexSet* indexes = [NSMutableIndexSet indexSet];
|
| + NSUInteger offset = 1;
|
| + for (NSUInteger i = range.location; i < NSMaxRange(range); ++i) {
|
| + int group = model_->GetGroupID(i);
|
| + offset = [self offsetForGroupID:group startingOffset:offset];
|
| + [indexes addIndex:i + offset];
|
| + }
|
| + return indexes;
|
| +}
|
| +
|
| +- (void)modelDidAddItemsInRange:(NSRange)range {
|
| + NSMutableArray* rows = [NSMutableArray arrayWithCapacity:range.length];
|
| + for (NSUInteger i=range.location; i<NSMaxRange(range); ++i)
|
| + [rows addObject:[self columnValuesForRow:i]];
|
| + [self insertObjects:rows
|
| + atArrangedObjectIndexes:[self controllerRowsForModelRowsInRange:range]];
|
| +}
|
| +
|
| +- (void)modelDidRemoveItemsInRange:(NSRange)range {
|
| + NSMutableIndexSet* indexes =
|
| + [NSMutableIndexSet indexSetWithIndexesInRange:range];
|
| + if (model_->HasGroups()) {
|
| + // When this method is called, the model has already removed items, so
|
| + // accessing items in the model from |range.location| on may not be possible
|
| + // anymore. Therefore we use the item right before that, if it exists.
|
| + NSUInteger offset = 0;
|
| + if (range.location > 0) {
|
| + int last_group = model_->GetGroupID(range.location - 1);
|
| + offset = [self offsetForGroupID:last_group];
|
| + }
|
| + [indexes shiftIndexesStartingAtIndex:0 by:offset];
|
| + for (NSUInteger row = range.location + offset;
|
| + row < NSMaxRange(range) + offset;
|
| + ++row) {
|
| + if ([self tableView:nil isGroupRow:row]) {
|
| + // Skip over group rows.
|
| + [indexes shiftIndexesStartingAtIndex:row by:1];
|
| + offset++;
|
| + }
|
| + }
|
| + }
|
| + [self removeObjectsAtArrangedObjectIndexes:indexes];
|
| +}
|
| +
|
| +- (NSDictionary*)columnValuesForRow:(NSInteger)row {
|
| + NSMutableDictionary* dict = [NSMutableDictionary dictionary];
|
| + if (model_->HasGroups()) {
|
| + [dict setObject:[NSNumber numberWithInt:model_->GetGroupID(row)]
|
| + forKey:kGroupID];
|
| + }
|
| + for (NSString* identifier in columns_.get()) {
|
| + int column_id = [[columns_ objectForKey:identifier] intValue];
|
| + std::wstring text = model_->GetText(row, column_id);
|
| + [dict setObject:base::SysWideToNSString(text) forKey:identifier];
|
| + }
|
| + return dict;
|
| +}
|
| +
|
| +// Overridden from NSArrayController -----------------------------------------
|
| +
|
| +- (BOOL)canRemove {
|
| + if (!model_)
|
| + return NO;
|
| + RemoveRowsTableModel::Rows rows;
|
| + [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
|
| + return model_->CanRemoveRows(rows);
|
| +}
|
| +
|
| +- (IBAction)remove:(id)sender {
|
| + RemoveRowsTableModel::Rows rows;
|
| + [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
|
| + model_->RemoveRows(rows);
|
| +}
|
| +
|
| +// Table View Delegate --------------------------------------------------------
|
| +
|
| +- (BOOL)tableView:(NSTableView*)tv isGroupRow:(NSInteger)row {
|
| + NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
|
| + return [[values objectForKey:kIsGroupRow] boolValue];
|
| +}
|
| +
|
| +- (NSIndexSet*)tableView:(NSTableView*)tableView
|
| + selectionIndexesForProposedSelection:(NSIndexSet*)proposedIndexes {
|
| + NSMutableIndexSet* indexes = [proposedIndexes mutableCopy];
|
| + for (NSUInteger i = [proposedIndexes firstIndex];
|
| + i != NSNotFound;
|
| + i = [proposedIndexes indexGreaterThanIndex:i]) {
|
| + if ([self tableView:tableView isGroupRow:i]) {
|
| + [indexes removeIndex:i];
|
| + NSUInteger row = i + 1;
|
| + while (row < [[self arrangedObjects] count] &&
|
| + ![self tableView:tableView isGroupRow:row])
|
| + [indexes addIndex:row++];
|
| + }
|
| + }
|
| + return indexes;
|
| +}
|
| +
|
| +// Actions --------------------------------------------------------------------
|
| +
|
| +- (IBAction)removeAll:(id)sender {
|
| + model_->RemoveAll();
|
| +}
|
| +
|
| +@end
|
|
|