OLD | NEW |
(Empty) | |
| 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/cocoa/table_model_array_controller.h" |
| 6 |
| 7 #include "app/table_model.h" |
| 8 #include "base/sys_string_conversions.h" |
| 9 #include "chrome/browser/remove_rows_table_model.h" |
| 10 |
| 11 @interface TableModelArrayController (PrivateMethods) |
| 12 |
| 13 - (NSUInteger)offsetForGroupID:(int)groupID; |
| 14 - (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset; |
| 15 - (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range; |
| 16 - (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows |
| 17 fromControllerRows:(NSIndexSet*)rows; |
| 18 - (void)modelDidChange; |
| 19 - (void)modelDidAddItemsInRange:(NSRange)range; |
| 20 - (void)modelDidRemoveItemsInRange:(NSRange)range; |
| 21 - (NSDictionary*)columnValuesForRow:(NSInteger)row; |
| 22 |
| 23 @end |
| 24 |
| 25 // Observer for a RemoveRowsTableModel. |
| 26 class RemoveRowsObserverBridge : public TableModelObserver { |
| 27 public: |
| 28 RemoveRowsObserverBridge(TableModelArrayController* controller) |
| 29 : controller_(controller) {} |
| 30 virtual ~RemoveRowsObserverBridge() {} |
| 31 |
| 32 // TableModelObserver methods |
| 33 virtual void OnModelChanged(); |
| 34 virtual void OnItemsChanged(int start, int length); |
| 35 virtual void OnItemsAdded(int start, int length); |
| 36 virtual void OnItemsRemoved(int start, int length); |
| 37 |
| 38 private: |
| 39 TableModelArrayController* controller_; // weak |
| 40 }; |
| 41 |
| 42 void RemoveRowsObserverBridge::OnModelChanged() { |
| 43 [controller_ modelDidChange]; |
| 44 } |
| 45 |
| 46 void RemoveRowsObserverBridge::OnItemsChanged(int start, int length) { |
| 47 OnItemsRemoved(start, length); |
| 48 OnItemsAdded(start, length); |
| 49 } |
| 50 |
| 51 void RemoveRowsObserverBridge::OnItemsAdded(int start, int length) { |
| 52 [controller_ modelDidAddItemsInRange:NSMakeRange(start, length)]; |
| 53 } |
| 54 |
| 55 void RemoveRowsObserverBridge::OnItemsRemoved(int start, int length) { |
| 56 [controller_ modelDidRemoveItemsInRange:NSMakeRange(start, length)]; |
| 57 } |
| 58 |
| 59 @implementation TableModelArrayController |
| 60 |
| 61 static NSString* const kIsGroupRow = @"_is_group_row"; |
| 62 static NSString* const kGroupID = @"_group_id"; |
| 63 |
| 64 - (void)bindToTableModel:(RemoveRowsTableModel*)model |
| 65 withColumns:(NSDictionary*)columns |
| 66 groupTitleColumn:(NSString*)groupTitleColumn { |
| 67 model_ = model; |
| 68 tableObserver_.reset(new RemoveRowsObserverBridge(self)); |
| 69 columns_.reset([columns copy]); |
| 70 groupTitle_.reset([groupTitleColumn copy]); |
| 71 model_->SetObserver(tableObserver_.get()); |
| 72 [self modelDidChange]; |
| 73 } |
| 74 |
| 75 - (void)modelDidChange { |
| 76 NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange: |
| 77 NSMakeRange(0, [[self arrangedObjects] count])]; |
| 78 [self removeObjectsAtArrangedObjectIndexes:indexes]; |
| 79 if (model_->HasGroups()) { |
| 80 const TableModel::Groups& groups = model_->GetGroups(); |
| 81 DCHECK(groupTitle_.get()); |
| 82 for (TableModel::Groups::const_iterator it = groups.begin(); |
| 83 it != groups.end(); ++it) { |
| 84 NSDictionary* group = [NSDictionary dictionaryWithObjectsAndKeys: |
| 85 base::SysWideToNSString(it->title), groupTitle_.get(), |
| 86 [NSNumber numberWithBool:YES], kIsGroupRow, |
| 87 nil]; |
| 88 [self addObject:group]; |
| 89 } |
| 90 } |
| 91 [self modelDidAddItemsInRange:NSMakeRange(0, model_->RowCount())]; |
| 92 } |
| 93 |
| 94 - (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset { |
| 95 const TableModel::Groups& groups = model_->GetGroups(); |
| 96 DCHECK_GT(offset, 0u); |
| 97 for (NSUInteger i = offset - 1; i < groups.size(); ++i) { |
| 98 if (groups[i].id == groupID) |
| 99 return i + 1; |
| 100 } |
| 101 NOTREACHED(); |
| 102 return NSNotFound; |
| 103 } |
| 104 |
| 105 - (NSUInteger)offsetForGroupID:(int)groupID { |
| 106 return [self offsetForGroupID:groupID startingOffset:1]; |
| 107 } |
| 108 |
| 109 - (int)groupIDForControllerRow:(NSUInteger)row { |
| 110 NSDictionary* values = [[self arrangedObjects] objectAtIndex:row]; |
| 111 return [[values objectForKey:kGroupID] intValue]; |
| 112 } |
| 113 |
| 114 - (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows |
| 115 fromControllerRows:(NSIndexSet*)rows { |
| 116 if ([rows count] == 0) |
| 117 return; |
| 118 |
| 119 if (!model_->HasGroups()) { |
| 120 for (NSUInteger i = [rows firstIndex]; |
| 121 i != NSNotFound; |
| 122 i = [rows indexGreaterThanIndex:i]) { |
| 123 modelRows->insert(i); |
| 124 } |
| 125 return; |
| 126 } |
| 127 |
| 128 NSUInteger offset = 1; |
| 129 for (NSUInteger i = [rows firstIndex]; |
| 130 i != NSNotFound; |
| 131 i = [rows indexGreaterThanIndex:i]) { |
| 132 int group = [self groupIDForControllerRow:i]; |
| 133 offset = [self offsetForGroupID:group startingOffset:offset]; |
| 134 modelRows->insert(i - offset); |
| 135 } |
| 136 } |
| 137 |
| 138 - (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range { |
| 139 if (!model_->HasGroups()) |
| 140 return [NSIndexSet indexSetWithIndexesInRange:range]; |
| 141 NSMutableIndexSet* indexes = [NSMutableIndexSet indexSet]; |
| 142 NSUInteger offset = 1; |
| 143 for (NSUInteger i = range.location; i < NSMaxRange(range); ++i) { |
| 144 int group = model_->GetGroupID(i); |
| 145 offset = [self offsetForGroupID:group startingOffset:offset]; |
| 146 [indexes addIndex:i + offset]; |
| 147 } |
| 148 return indexes; |
| 149 } |
| 150 |
| 151 - (void)modelDidAddItemsInRange:(NSRange)range { |
| 152 NSMutableArray* rows = [NSMutableArray arrayWithCapacity:range.length]; |
| 153 for (NSUInteger i=range.location; i<NSMaxRange(range); ++i) |
| 154 [rows addObject:[self columnValuesForRow:i]]; |
| 155 [self insertObjects:rows |
| 156 atArrangedObjectIndexes:[self controllerRowsForModelRowsInRange:range]]; |
| 157 } |
| 158 |
| 159 - (void)modelDidRemoveItemsInRange:(NSRange)range { |
| 160 NSMutableIndexSet* indexes = |
| 161 [NSMutableIndexSet indexSetWithIndexesInRange:range]; |
| 162 if (model_->HasGroups()) { |
| 163 // When this method is called, the model has already removed items, so |
| 164 // accessing items in the model from |range.location| on may not be possible |
| 165 // anymore. Therefore we use the item right before that, if it exists. |
| 166 NSUInteger offset = 0; |
| 167 if (range.location > 0) { |
| 168 int last_group = model_->GetGroupID(range.location - 1); |
| 169 offset = [self offsetForGroupID:last_group]; |
| 170 } |
| 171 [indexes shiftIndexesStartingAtIndex:0 by:offset]; |
| 172 for (NSUInteger row = range.location + offset; |
| 173 row < NSMaxRange(range) + offset; |
| 174 ++row) { |
| 175 if ([self tableView:nil isGroupRow:row]) { |
| 176 // Skip over group rows. |
| 177 [indexes shiftIndexesStartingAtIndex:row by:1]; |
| 178 offset++; |
| 179 } |
| 180 } |
| 181 } |
| 182 [self removeObjectsAtArrangedObjectIndexes:indexes]; |
| 183 } |
| 184 |
| 185 - (NSDictionary*)columnValuesForRow:(NSInteger)row { |
| 186 NSMutableDictionary* dict = [NSMutableDictionary dictionary]; |
| 187 if (model_->HasGroups()) { |
| 188 [dict setObject:[NSNumber numberWithInt:model_->GetGroupID(row)] |
| 189 forKey:kGroupID]; |
| 190 } |
| 191 for (NSString* identifier in columns_.get()) { |
| 192 int column_id = [[columns_ objectForKey:identifier] intValue]; |
| 193 std::wstring text = model_->GetText(row, column_id); |
| 194 [dict setObject:base::SysWideToNSString(text) forKey:identifier]; |
| 195 } |
| 196 return dict; |
| 197 } |
| 198 |
| 199 // Overridden from NSArrayController ----------------------------------------- |
| 200 |
| 201 - (BOOL)canRemove { |
| 202 if (!model_) |
| 203 return NO; |
| 204 RemoveRowsTableModel::Rows rows; |
| 205 [self setModelRows:&rows fromControllerRows:[self selectionIndexes]]; |
| 206 return model_->CanRemoveRows(rows); |
| 207 } |
| 208 |
| 209 - (IBAction)remove:(id)sender { |
| 210 RemoveRowsTableModel::Rows rows; |
| 211 [self setModelRows:&rows fromControllerRows:[self selectionIndexes]]; |
| 212 model_->RemoveRows(rows); |
| 213 } |
| 214 |
| 215 // Table View Delegate -------------------------------------------------------- |
| 216 |
| 217 - (BOOL)tableView:(NSTableView*)tv isGroupRow:(NSInteger)row { |
| 218 NSDictionary* values = [[self arrangedObjects] objectAtIndex:row]; |
| 219 return [[values objectForKey:kIsGroupRow] boolValue]; |
| 220 } |
| 221 |
| 222 - (NSIndexSet*)tableView:(NSTableView*)tableView |
| 223 selectionIndexesForProposedSelection:(NSIndexSet*)proposedIndexes { |
| 224 NSMutableIndexSet* indexes = [proposedIndexes mutableCopy]; |
| 225 for (NSUInteger i = [proposedIndexes firstIndex]; |
| 226 i != NSNotFound; |
| 227 i = [proposedIndexes indexGreaterThanIndex:i]) { |
| 228 if ([self tableView:tableView isGroupRow:i]) { |
| 229 [indexes removeIndex:i]; |
| 230 NSUInteger row = i + 1; |
| 231 while (row < [[self arrangedObjects] count] && |
| 232 ![self tableView:tableView isGroupRow:row]) |
| 233 [indexes addIndex:row++]; |
| 234 } |
| 235 } |
| 236 return indexes; |
| 237 } |
| 238 |
| 239 // Actions -------------------------------------------------------------------- |
| 240 |
| 241 - (IBAction)removeAll:(id)sender { |
| 242 model_->RemoveAll(); |
| 243 } |
| 244 |
| 245 @end |
OLD | NEW |