| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/cocoa/task_manager_mac.h" | 5 #include "chrome/browser/ui/cocoa/task_manager_mac.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/mac/bundle_locations.h" | 12 #include "base/mac/bundle_locations.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/strings/sys_string_conversions.h" | 14 #include "base/strings/sys_string_conversions.h" |
| 15 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
| 16 #include "chrome/browser/chrome_notification_types.h" |
| 16 #include "chrome/browser/task_management/task_manager_interface.h" | 17 #include "chrome/browser/task_management/task_manager_interface.h" |
| 17 #include "chrome/browser/task_manager/task_manager.h" | |
| 18 #include "chrome/browser/ui/browser.h" | 18 #include "chrome/browser/ui/browser.h" |
| 19 #include "chrome/browser/ui/browser_dialogs.h" | 19 #include "chrome/browser/ui/browser_dialogs.h" |
| 20 #import "chrome/browser/ui/cocoa/window_size_autosaver.h" | 20 #import "chrome/browser/ui/cocoa/window_size_autosaver.h" |
| 21 #include "chrome/browser/ui/task_manager/task_manager_columns.h" |
| 21 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
| 22 #include "chrome/grit/generated_resources.h" | 23 #include "chrome/grit/generated_resources.h" |
| 23 #include "components/prefs/pref_service.h" | 24 #include "components/prefs/pref_service.h" |
| 25 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/notification_source.h" |
| 24 #include "third_party/skia/include/core/SkBitmap.h" | 27 #include "third_party/skia/include/core/SkBitmap.h" |
| 25 #include "ui/base/l10n/l10n_util_mac.h" | 28 #include "ui/base/l10n/l10n_util_mac.h" |
| 26 #include "ui/gfx/image/image_skia.h" | 29 #include "ui/gfx/image/image_skia.h" |
| 27 #include "ui/gfx/image/image_skia_util_mac.h" | 30 #include "ui/gfx/image/image_skia_util_mac.h" |
| 28 | 31 |
| 29 namespace { | 32 namespace { |
| 30 | 33 |
| 31 // Width of "a" and most other letters/digits in "small" table views. | 34 NSString* ColumnIdentifier(int id) { |
| 32 const int kCharWidth = 6; | 35 return [NSString stringWithFormat:@"%d", id]; |
| 33 | 36 } |
| 34 // Some of the strings below have spaces at the end or are missing letters, to | |
| 35 // make the columns look nicer, and to take potentially longer localized strings | |
| 36 // into account. | |
| 37 const struct ColumnWidth { | |
| 38 int columnId; | |
| 39 int minWidth; | |
| 40 int maxWidth; // If this is -1, 1.5*minColumWidth is used as max width. | |
| 41 } columnWidths[] = { | |
| 42 // Note that arraysize includes the trailing \0. That's intended. | |
| 43 { IDS_TASK_MANAGER_TASK_COLUMN, 120, 600 }, | |
| 44 { IDS_TASK_MANAGER_PROFILE_NAME_COLUMN, 60, 200 }, | |
| 45 { IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, | |
| 46 arraysize("800 MiB") * kCharWidth, -1 }, | |
| 47 { IDS_TASK_MANAGER_SHARED_MEM_COLUMN, | |
| 48 arraysize("800 MiB") * kCharWidth, -1 }, | |
| 49 { IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, | |
| 50 arraysize("800 MiB") * kCharWidth, -1 }, | |
| 51 { IDS_TASK_MANAGER_CPU_COLUMN, | |
| 52 arraysize("99.9") * kCharWidth, -1 }, | |
| 53 { IDS_TASK_MANAGER_NET_COLUMN, | |
| 54 arraysize("150 kiB/s") * kCharWidth, -1 }, | |
| 55 { IDS_TASK_MANAGER_PROCESS_ID_COLUMN, | |
| 56 arraysize("73099 ") * kCharWidth, -1 }, | |
| 57 { IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN, | |
| 58 arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 }, | |
| 59 { IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN, | |
| 60 arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 }, | |
| 61 { IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, | |
| 62 arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 }, | |
| 63 { IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN, | |
| 64 arraysize("2000.0K") * kCharWidth, -1 }, | |
| 65 { IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN, | |
| 66 arraysize("800 kB") * kCharWidth, -1 }, | |
| 67 { IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN, | |
| 68 arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 }, | |
| 69 { IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN, | |
| 70 arraysize("32767") * kCharWidth, -1 }, | |
| 71 { IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN, | |
| 72 arraysize("idlewakeups") * kCharWidth, -1 }, | |
| 73 }; | |
| 74 | |
| 75 class SortHelper { | |
| 76 public: | |
| 77 SortHelper(TaskManagerModel* model, NSSortDescriptor* column) | |
| 78 : sort_column_([[column key] intValue]), | |
| 79 ascending_([column ascending]), | |
| 80 model_(model) {} | |
| 81 | |
| 82 bool operator()(int a, int b) { | |
| 83 TaskManagerModel::GroupRange group_range1 = | |
| 84 model_->GetGroupRangeForResource(a); | |
| 85 TaskManagerModel::GroupRange group_range2 = | |
| 86 model_->GetGroupRangeForResource(b); | |
| 87 if (group_range1 == group_range2) { | |
| 88 // The two rows are in the same group, sort so that items in the same | |
| 89 // group always appear in the same order. |ascending_| is intentionally | |
| 90 // ignored. | |
| 91 return a < b; | |
| 92 } | |
| 93 // Sort by the first entry of each of the groups. | |
| 94 int cmp_result = model_->CompareValues( | |
| 95 group_range1.first, group_range2.first, sort_column_); | |
| 96 if (!ascending_) | |
| 97 cmp_result = -cmp_result; | |
| 98 return cmp_result < 0; | |
| 99 } | |
| 100 private: | |
| 101 int sort_column_; | |
| 102 bool ascending_; | |
| 103 TaskManagerModel* model_; // weak; | |
| 104 }; | |
| 105 | 37 |
| 106 } // namespace | 38 } // namespace |
| 107 | 39 |
| 108 @interface TaskManagerWindowController (Private) | 40 @interface TaskManagerWindowController (Private) |
| 109 - (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible; | 41 - (NSTableColumn*)addColumnWithData: |
| 42 (const task_management::TableColumnData&)columnData; |
| 110 - (void)setUpTableColumns; | 43 - (void)setUpTableColumns; |
| 111 - (void)setUpTableHeaderContextMenu; | 44 - (void)setUpTableHeaderContextMenu; |
| 112 - (void)toggleColumn:(id)sender; | 45 - (void)toggleColumn:(id)sender; |
| 113 - (void)adjustSelectionAndEndProcessButton; | 46 - (void)adjustSelectionAndEndProcessButton; |
| 114 - (void)deselectRows; | 47 - (void)deselectRows; |
| 115 @end | 48 @end |
| 116 | 49 |
| 117 //////////////////////////////////////////////////////////////////////////////// | 50 //////////////////////////////////////////////////////////////////////////////// |
| 118 // TaskManagerWindowController implementation: | 51 // TaskManagerWindowController implementation: |
| 119 | 52 |
| 120 @implementation TaskManagerWindowController | 53 @implementation TaskManagerWindowController |
| 121 | 54 |
| 122 - (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver { | 55 - (id)initWithTaskManagerMac:(task_management::TaskManagerMac*)taskManagerMac |
| 56 tableModel: |
| 57 (task_management::TaskManagerTableModel*)tableModel { |
| 123 NSString* nibpath = [base::mac::FrameworkBundle() | 58 NSString* nibpath = [base::mac::FrameworkBundle() |
| 124 pathForResource:@"TaskManager" | 59 pathForResource:@"TaskManager" |
| 125 ofType:@"nib"]; | 60 ofType:@"nib"]; |
| 126 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | 61 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { |
| 127 taskManagerObserver_ = taskManagerObserver; | 62 taskManagerMac_ = taskManagerMac; |
| 128 taskManager_ = taskManagerObserver_->task_manager(); | 63 tableModel_ = tableModel; |
| 129 model_ = taskManager_->model(); | |
| 130 | 64 |
| 131 if (g_browser_process && g_browser_process->local_state()) { | 65 if (g_browser_process && g_browser_process->local_state()) { |
| 132 size_saver_.reset([[WindowSizeAutosaver alloc] | 66 size_saver_.reset([[WindowSizeAutosaver alloc] |
| 133 initWithWindow:[self window] | 67 initWithWindow:[self window] |
| 134 prefService:g_browser_process->local_state() | 68 prefService:g_browser_process->local_state() |
| 135 path:prefs::kTaskManagerWindowPlacement]); | 69 path:prefs::kTaskManagerWindowPlacement]); |
| 136 } | 70 } |
| 137 [[self window] setExcludedFromWindowsMenu:YES]; | 71 [[self window] setExcludedFromWindowsMenu:YES]; |
| 72 |
| 73 [self reloadData]; |
| 138 [self showWindow:self]; | 74 [self showWindow:self]; |
| 139 } | 75 } |
| 140 return self; | 76 return self; |
| 141 } | 77 } |
| 142 | 78 |
| 143 - (void)sortShuffleArray { | 79 - (void)sortShuffleArray { |
| 144 viewToModelMap_.resize(model_->ResourceCount()); | 80 viewToModelMap_.resize(tableModel_->RowCount()); |
| 145 for (size_t i = 0; i < viewToModelMap_.size(); ++i) | 81 for (size_t i = 0; i < viewToModelMap_.size(); ++i) |
| 146 viewToModelMap_[i] = i; | 82 viewToModelMap_[i] = i; |
| 147 | 83 |
| 148 std::sort(viewToModelMap_.begin(), viewToModelMap_.end(), | 84 if (currentSortDescriptor_.sorted_column_id != -1) { |
| 149 SortHelper(model_, currentSortDescriptor_.get())); | 85 task_management::TaskManagerTableModel* tableModel = tableModel_; |
| 86 task_management::TableSortDescriptor currentSortDescriptor = |
| 87 currentSortDescriptor_; |
| 88 std::stable_sort(viewToModelMap_.begin(), viewToModelMap_.end(), |
| 89 [tableModel, currentSortDescriptor](int a, int b) { |
| 90 int aStart, aLength; |
| 91 tableModel->GetRowsGroupRange(a, &aStart, &aLength); |
| 92 int bStart, bLength; |
| 93 tableModel->GetRowsGroupRange(b, &bStart, &bLength); |
| 94 if (aStart == bStart) { |
| 95 // The two rows are in the same group, sort so that |
| 96 // items in the same group always appear in the same |
| 97 // order. The sort descriptor's ascending value is |
| 98 // intentionally ignored. |
| 99 return a < b; |
| 100 } |
| 101 |
| 102 // Sort by the first entry of each of the groups. |
| 103 int cmp_result = tableModel->CompareValues( |
| 104 aStart, bStart, |
| 105 currentSortDescriptor.sorted_column_id); |
| 106 if (!currentSortDescriptor.is_ascending) |
| 107 cmp_result = -cmp_result; |
| 108 return cmp_result < 0; |
| 109 }); |
| 110 } |
| 150 | 111 |
| 151 modelToViewMap_.resize(viewToModelMap_.size()); | 112 modelToViewMap_.resize(viewToModelMap_.size()); |
| 152 for (size_t i = 0; i < viewToModelMap_.size(); ++i) | 113 for (size_t i = 0; i < viewToModelMap_.size(); ++i) |
| 153 modelToViewMap_[viewToModelMap_[i]] = i; | 114 modelToViewMap_[viewToModelMap_[i]] = i; |
| 154 } | 115 } |
| 155 | 116 |
| 156 - (void)reloadData { | 117 - (void)reloadData { |
| 118 [self reloadDataWithRows:0 addedAtIndex:0]; |
| 119 } |
| 120 |
| 121 - (void)reloadDataWithRows:(int)addedRows addedAtIndex:(int)addedRowIndex { |
| 157 // Store old view indices, and the model indices they map to. | 122 // Store old view indices, and the model indices they map to. |
| 158 NSIndexSet* viewSelection = [tableView_ selectedRowIndexes]; | 123 NSIndexSet* viewSelection = [tableView_ selectedRowIndexes]; |
| 159 std::vector<int> modelSelection; | 124 std::vector<int> modelSelection; |
| 160 for (NSUInteger i = [viewSelection lastIndex]; | 125 for (NSUInteger i = [viewSelection lastIndex]; |
| 161 i != NSNotFound; | 126 i != NSNotFound; |
| 162 i = [viewSelection indexLessThanIndex:i]) { | 127 i = [viewSelection indexLessThanIndex:i]) { |
| 163 modelSelection.push_back(viewToModelMap_[i]); | 128 modelSelection.push_back(viewToModelMap_[i]); |
| 164 } | 129 } |
| 165 | 130 |
| 131 // Adjust for any added or removed rows. |
| 132 if (addedRows != 0) { |
| 133 for (int& selectedItem : modelSelection) { |
| 134 if (addedRowIndex > selectedItem) { |
| 135 // Nothing to do; added/removed items are beyond the selected item. |
| 136 continue; |
| 137 } |
| 138 |
| 139 if (addedRows > 0) { |
| 140 selectedItem += addedRows; |
| 141 } else { |
| 142 int removedRows = -addedRows; |
| 143 if (addedRowIndex + removedRows <= selectedItem) |
| 144 selectedItem -= removedRows; |
| 145 else |
| 146 selectedItem = -1; // The item was removed. |
| 147 } |
| 148 } |
| 149 } |
| 150 |
| 166 // Sort. | 151 // Sort. |
| 167 [self sortShuffleArray]; | 152 [self sortShuffleArray]; |
| 168 | 153 |
| 169 // Use the model indices to get the new view indices of the selection, and | 154 // Clear the selection and reload the NSTableView. Note that it is important |
| 170 // set selection to that. This assumes that no rows were added or removed | 155 // to clear the selection before reloading the data, and to reload the |
| 171 // (in that case, the selection is cleared before -reloadData is called). | 156 // selection after reloading the data, because otherwise the table will adjust |
| 172 if (!modelSelection.empty()) | 157 // the selection in ways that are not desirable. |
| 173 DCHECK_EQ([tableView_ numberOfRows], model_->ResourceCount()); | 158 [tableView_ deselectAll:nil]; |
| 159 [tableView_ reloadData]; |
| 160 |
| 161 // Reload the selection. |
| 174 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; | 162 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; |
| 175 for (size_t i = 0; i < modelSelection.size(); ++i) | 163 for (auto selectedItem : modelSelection) { |
| 176 [indexSet addIndex:modelToViewMap_[modelSelection[i]]]; | 164 if (selectedItem != -1) |
| 165 [indexSet addIndex:modelToViewMap_[selectedItem]]; |
| 166 } |
| 177 [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO]; | 167 [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO]; |
| 178 | 168 |
| 179 [tableView_ reloadData]; | |
| 180 [self adjustSelectionAndEndProcessButton]; | 169 [self adjustSelectionAndEndProcessButton]; |
| 181 } | 170 } |
| 182 | 171 |
| 172 - (task_management::TableSortDescriptor)sortDescriptor { |
| 173 return currentSortDescriptor_; |
| 174 } |
| 175 |
| 176 - (void)setSortDescriptor: |
| 177 (const task_management::TableSortDescriptor&)sortDescriptor { |
| 178 base::scoped_nsobject<NSSortDescriptor> nsSortDescriptor( |
| 179 [[NSSortDescriptor alloc] |
| 180 initWithKey:ColumnIdentifier(sortDescriptor.sorted_column_id) |
| 181 ascending:sortDescriptor.is_ascending]); |
| 182 [tableView_ setSortDescriptors:@[ nsSortDescriptor ]]; |
| 183 } |
| 184 |
| 185 - (BOOL)visibilityOfColumnWithId:(int)columnId { |
| 186 NSTableColumn* column = |
| 187 [tableView_ tableColumnWithIdentifier:ColumnIdentifier(columnId)]; |
| 188 return ![column isHidden]; |
| 189 } |
| 190 |
| 191 - (void)setColumnWithId:(int)columnId toVisibility:(BOOL)visibility { |
| 192 NSTableColumn* column = |
| 193 [tableView_ tableColumnWithIdentifier:ColumnIdentifier(columnId)]; |
| 194 [column setHidden:!visibility]; |
| 195 |
| 196 [tableView_ sizeToFit]; |
| 197 [tableView_ setNeedsDisplay]; |
| 198 } |
| 199 |
| 183 - (IBAction)killSelectedProcesses:(id)sender { | 200 - (IBAction)killSelectedProcesses:(id)sender { |
| 184 NSIndexSet* selection = [tableView_ selectedRowIndexes]; | 201 NSIndexSet* selection = [tableView_ selectedRowIndexes]; |
| 185 for (NSUInteger i = [selection lastIndex]; | 202 for (NSUInteger i = [selection lastIndex]; |
| 186 i != NSNotFound; | 203 i != NSNotFound; |
| 187 i = [selection indexLessThanIndex:i]) { | 204 i = [selection indexLessThanIndex:i]) { |
| 188 taskManager_->KillProcess(viewToModelMap_[i]); | 205 tableModel_->KillTask(viewToModelMap_[i]); |
| 189 } | 206 } |
| 190 } | 207 } |
| 191 | 208 |
| 192 - (void)selectDoubleClickedTab:(id)sender { | 209 - (void)tableWasDoubleClicked:(id)sender { |
| 193 NSInteger row = [tableView_ clickedRow]; | 210 NSInteger row = [tableView_ clickedRow]; |
| 194 if (row < 0) | 211 if (row < 0) |
| 195 return; // Happens e.g. if the table header is double-clicked. | 212 return; // Happens e.g. if the table header is double-clicked. |
| 196 taskManager_->ActivateProcess(viewToModelMap_[row]); | 213 tableModel_->ActivateTask(viewToModelMap_[row]); |
| 197 } | |
| 198 | |
| 199 - (NSTableView*)tableView { | |
| 200 return tableView_; | |
| 201 } | 214 } |
| 202 | 215 |
| 203 - (void)awakeFromNib { | 216 - (void)awakeFromNib { |
| 204 [self setUpTableColumns]; | 217 [self setUpTableColumns]; |
| 205 [self setUpTableHeaderContextMenu]; | 218 [self setUpTableHeaderContextMenu]; |
| 206 [self adjustSelectionAndEndProcessButton]; | 219 [self adjustSelectionAndEndProcessButton]; |
| 207 | 220 |
| 208 [tableView_ setDoubleAction:@selector(selectDoubleClickedTab:)]; | 221 [tableView_ setDoubleAction:@selector(tableWasDoubleClicked:)]; |
| 209 [tableView_ setIntercellSpacing:NSMakeSize(0.0, 0.0)]; | 222 [tableView_ setIntercellSpacing:NSMakeSize(0.0, 0.0)]; |
| 210 [tableView_ sizeToFit]; | 223 [tableView_ sizeToFit]; |
| 211 } | 224 } |
| 212 | 225 |
| 213 - (void)dealloc { | 226 - (void)dealloc { |
| 214 [tableView_ setDelegate:nil]; | 227 [tableView_ setDelegate:nil]; |
| 215 [tableView_ setDataSource:nil]; | 228 [tableView_ setDataSource:nil]; |
| 216 [super dealloc]; | 229 [super dealloc]; |
| 217 } | 230 } |
| 218 | 231 |
| 219 // Adds a column which has the given string id as title. |isVisible| specifies | 232 // Adds a column which has the given string id as title. |isVisible| specifies |
| 220 // if the column is initially visible. | 233 // if the column is initially visible. |
| 221 - (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible { | 234 - (NSTableColumn*)addColumnWithData: |
| 235 (const task_management::TableColumnData&)columnData { |
| 222 base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc] | 236 base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc] |
| 223 initWithIdentifier:[NSString stringWithFormat:@"%d", columnId]]); | 237 initWithIdentifier:ColumnIdentifier(columnData.id)]); |
| 224 | 238 |
| 225 NSTextAlignment textAlignment = | 239 NSTextAlignment textAlignment = (columnData.align == ui::TableColumn::LEFT) |
| 226 (columnId == IDS_TASK_MANAGER_TASK_COLUMN || | 240 ? NSLeftTextAlignment |
| 227 columnId == IDS_TASK_MANAGER_PROFILE_NAME_COLUMN) ? | 241 : NSRightTextAlignment; |
| 228 NSLeftTextAlignment : NSRightTextAlignment; | |
| 229 | 242 |
| 230 [[column.get() headerCell] | 243 [[column.get() headerCell] |
| 231 setStringValue:l10n_util::GetNSStringWithFixup(columnId)]; | 244 setStringValue:l10n_util::GetNSStringWithFixup(columnData.id)]; |
| 232 [[column.get() headerCell] setAlignment:textAlignment]; | 245 [[column.get() headerCell] setAlignment:textAlignment]; |
| 233 [[column.get() dataCell] setAlignment:textAlignment]; | 246 [[column.get() dataCell] setAlignment:textAlignment]; |
| 234 | 247 |
| 235 NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; | 248 NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; |
| 236 [[column.get() dataCell] setFont:font]; | 249 [[column.get() dataCell] setFont:font]; |
| 237 | 250 |
| 238 [column.get() setHidden:!isVisible]; | 251 [column.get() setHidden:!columnData.default_visibility]; |
| 239 [column.get() setEditable:NO]; | 252 [column.get() setEditable:NO]; |
| 240 | 253 |
| 241 // The page column should by default be sorted ascending. | |
| 242 BOOL ascending = columnId == IDS_TASK_MANAGER_TASK_COLUMN; | |
| 243 | |
| 244 base::scoped_nsobject<NSSortDescriptor> sortDescriptor( | 254 base::scoped_nsobject<NSSortDescriptor> sortDescriptor( |
| 245 [[NSSortDescriptor alloc] | 255 [[NSSortDescriptor alloc] |
| 246 initWithKey:[NSString stringWithFormat:@"%d", columnId] | 256 initWithKey:ColumnIdentifier(columnData.id) |
| 247 ascending:ascending]); | 257 ascending:columnData.initial_sort_is_ascending]); |
| 248 [column.get() setSortDescriptorPrototype:sortDescriptor.get()]; | 258 [column.get() setSortDescriptorPrototype:sortDescriptor.get()]; |
| 249 | 259 |
| 250 // Default values, only used in release builds if nobody notices the DCHECK | 260 [column.get() setMinWidth:columnData.min_width]; |
| 251 // during development when adding new columns. | 261 int maxWidth = columnData.max_width; |
| 252 int minWidth = 200, maxWidth = 400; | 262 if (maxWidth < 0) |
| 253 | 263 maxWidth = 3 * columnData.min_width / 2; // *1.5 for ints. |
| 254 size_t i; | |
| 255 for (i = 0; i < arraysize(columnWidths); ++i) { | |
| 256 if (columnWidths[i].columnId == columnId) { | |
| 257 minWidth = columnWidths[i].minWidth; | |
| 258 maxWidth = columnWidths[i].maxWidth; | |
| 259 if (maxWidth < 0) | |
| 260 maxWidth = 3 * minWidth / 2; // *1.5 for ints. | |
| 261 break; | |
| 262 } | |
| 263 } | |
| 264 DCHECK(i < arraysize(columnWidths)) << "Could not find " << columnId; | |
| 265 [column.get() setMinWidth:minWidth]; | |
| 266 [column.get() setMaxWidth:maxWidth]; | 264 [column.get() setMaxWidth:maxWidth]; |
| 267 [column.get() setResizingMask:NSTableColumnAutoresizingMask | | 265 [column.get() setResizingMask:NSTableColumnAutoresizingMask | |
| 268 NSTableColumnUserResizingMask]; | 266 NSTableColumnUserResizingMask]; |
| 269 | 267 |
| 270 [tableView_ addTableColumn:column.get()]; | 268 [tableView_ addTableColumn:column.get()]; |
| 271 return column.get(); // Now retained by |tableView_|. | 269 return column.get(); // Now retained by |tableView_|. |
| 272 } | 270 } |
| 273 | 271 |
| 274 // Adds all the task manager's columns to the table. | 272 // Adds all the task manager's columns to the table. |
| 275 - (void)setUpTableColumns { | 273 - (void)setUpTableColumns { |
| 276 for (NSTableColumn* column in [tableView_ tableColumns]) | 274 for (NSTableColumn* column in [tableView_ tableColumns]) |
| 277 [tableView_ removeTableColumn:column]; | 275 [tableView_ removeTableColumn:column]; |
| 278 NSTableColumn* nameColumn = [self addColumnWithId:IDS_TASK_MANAGER_TASK_COLUMN | |
| 279 visible:YES]; | |
| 280 // |nameColumn| displays an icon for every row -- this is done by an | |
| 281 // NSButtonCell. | |
| 282 base::scoped_nsobject<NSButtonCell> nameCell( | |
| 283 [[NSButtonCell alloc] initTextCell:@""]); | |
| 284 [nameCell.get() setImagePosition:NSImageLeft]; | |
| 285 [nameCell.get() setButtonType:NSSwitchButton]; | |
| 286 [nameCell.get() setAlignment:[[nameColumn dataCell] alignment]]; | |
| 287 [nameCell.get() setFont:[[nameColumn dataCell] font]]; | |
| 288 [nameColumn setDataCell:nameCell.get()]; | |
| 289 | 276 |
| 290 // Initially, sort on the tab name. | 277 for (size_t i = 0; i < task_management::kColumnsSize; ++i) { |
| 291 [tableView_ setSortDescriptors: | 278 const auto& columnData = task_management::kColumns[i]; |
| 292 [NSArray arrayWithObject:[nameColumn sortDescriptorPrototype]]]; | 279 NSTableColumn* column = [self addColumnWithData:columnData]; |
| 293 [self addColumnWithId:IDS_TASK_MANAGER_PROFILE_NAME_COLUMN visible:NO]; | 280 |
| 294 [self addColumnWithId:IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN visible:YES]; | 281 if (columnData.id == IDS_TASK_MANAGER_TASK_COLUMN) { |
| 295 [self addColumnWithId:IDS_TASK_MANAGER_SHARED_MEM_COLUMN visible:NO]; | 282 // The task column displays an icon for every row, done by an |
| 296 [self addColumnWithId:IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN visible:NO]; | 283 // NSButtonCell. |
| 297 [self addColumnWithId:IDS_TASK_MANAGER_CPU_COLUMN visible:YES]; | 284 base::scoped_nsobject<NSButtonCell> nameCell( |
| 298 [self addColumnWithId:IDS_TASK_MANAGER_NET_COLUMN visible:YES]; | 285 [[NSButtonCell alloc] initTextCell:@""]); |
| 299 [self addColumnWithId:IDS_TASK_MANAGER_PROCESS_ID_COLUMN visible:YES]; | 286 [nameCell.get() setImagePosition:NSImageLeft]; |
| 300 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN | 287 [nameCell.get() setButtonType:NSSwitchButton]; |
| 301 visible:NO]; | 288 [nameCell.get() setAlignment:[[column dataCell] alignment]]; |
| 302 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN | 289 [nameCell.get() setFont:[[column dataCell] font]]; |
| 303 visible:NO]; | 290 [column setDataCell:nameCell.get()]; |
| 304 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN visible:NO]; | 291 } |
| 305 [self addColumnWithId:IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN visible:NO]; | 292 } |
| 306 [self addColumnWithId:IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN visible:NO]; | |
| 307 [self addColumnWithId:IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN | |
| 308 visible:NO]; | |
| 309 [self addColumnWithId:IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN | |
| 310 visible:NO]; | |
| 311 [self addColumnWithId:IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN | |
| 312 visible:NO]; | |
| 313 } | 293 } |
| 314 | 294 |
| 315 // Creates a context menu for the table header that allows the user to toggle | 295 // Creates a context menu for the table header that allows the user to toggle |
| 316 // which columns should be shown and which should be hidden (like e.g. | 296 // which columns should be shown and which should be hidden (like the Activity |
| 317 // Task Manager.app's table header context menu). | 297 // Monitor.app's table header context menu). |
| 318 - (void)setUpTableHeaderContextMenu { | 298 - (void)setUpTableHeaderContextMenu { |
| 319 base::scoped_nsobject<NSMenu> contextMenu( | 299 base::scoped_nsobject<NSMenu> contextMenu( |
| 320 [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]); | 300 [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]); |
| 301 [contextMenu setDelegate:self]; |
| 302 [[tableView_ headerView] setMenu:contextMenu.get()]; |
| 303 } |
| 304 |
| 305 - (void)menuNeedsUpdate:(NSMenu*)menu { |
| 306 [menu removeAllItems]; |
| 307 |
| 321 for (NSTableColumn* column in [tableView_ tableColumns]) { | 308 for (NSTableColumn* column in [tableView_ tableColumns]) { |
| 322 NSMenuItem* item = [contextMenu.get() | 309 NSMenuItem* item = [menu addItemWithTitle:[[column headerCell] stringValue] |
| 323 addItemWithTitle:[[column headerCell] stringValue] | 310 action:@selector(toggleColumn:) |
| 324 action:@selector(toggleColumn:) | 311 keyEquivalent:@""]; |
| 325 keyEquivalent:@""]; | |
| 326 [item setTarget:self]; | 312 [item setTarget:self]; |
| 327 [item setRepresentedObject:column]; | 313 [item setRepresentedObject:column]; |
| 328 [item setState:[column isHidden] ? NSOffState : NSOnState]; | 314 [item setState:[column isHidden] ? NSOffState : NSOnState]; |
| 329 } | 315 } |
| 330 [[tableView_ headerView] setMenu:contextMenu.get()]; | |
| 331 } | 316 } |
| 332 | 317 |
| 333 // Callback for the table header context menu. Toggles visibility of the table | 318 // Callback for the table header context menu. Toggles visibility of the table |
| 334 // column associated with the clicked menu item. | 319 // column associated with the clicked menu item. |
| 335 - (void)toggleColumn:(id)item { | 320 - (void)toggleColumn:(id)item { |
| 336 DCHECK([item isKindOfClass:[NSMenuItem class]]); | 321 DCHECK([item isKindOfClass:[NSMenuItem class]]); |
| 337 if (![item isKindOfClass:[NSMenuItem class]]) | 322 if (![item isKindOfClass:[NSMenuItem class]]) |
| 338 return; | 323 return; |
| 339 | 324 |
| 340 NSTableColumn* column = [item representedObject]; | 325 NSTableColumn* column = [item representedObject]; |
| 326 int columnId = [[column identifier] intValue]; |
| 341 DCHECK(column); | 327 DCHECK(column); |
| 342 NSInteger oldState = [item state]; | 328 NSInteger oldState = [item state]; |
| 343 NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState; | 329 NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState; |
| 344 | 330 |
| 345 // If hiding the column, make sure at least one column will remain visible. | 331 // If hiding the column, make sure at least one column will remain visible. |
| 346 if (newState == NSOffState) { | 332 if (newState == NSOffState) { |
| 347 // Find the first column that will be visible after hiding |column|. | 333 // Find the first column that will be visible after hiding |column|. |
| 348 NSTableColumn* firstRemainingVisibleColumn = nil; | 334 NSTableColumn* firstRemainingVisibleColumn = nil; |
| 349 | 335 |
| 350 for (NSTableColumn* nextColumn in [tableView_ tableColumns]) { | 336 for (NSTableColumn* nextColumn in [tableView_ tableColumns]) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 364 // on hiding the last visible column (perhaps they plan to choose another | 350 // on hiding the last visible column (perhaps they plan to choose another |
| 365 // one after that to be visible), odds are they will try making another | 351 // one after that to be visible), odds are they will try making another |
| 366 // column visible and then hiding the one column that would not hide. | 352 // column visible and then hiding the one column that would not hide. |
| 367 if (firstRemainingVisibleColumn == nil) { | 353 if (firstRemainingVisibleColumn == nil) { |
| 368 return; | 354 return; |
| 369 } | 355 } |
| 370 | 356 |
| 371 // If |column| is being used to sort the table (i.e. it's the primary sort | 357 // If |column| is being used to sort the table (i.e. it's the primary sort |
| 372 // column), make the first remaining visible column the new primary sort | 358 // column), make the first remaining visible column the new primary sort |
| 373 // column. | 359 // column. |
| 374 int primarySortColumnId = [[currentSortDescriptor_.get() key] intValue]; | 360 int primarySortColumnId = currentSortDescriptor_.sorted_column_id; |
| 375 DCHECK(primarySortColumnId); | 361 DCHECK(primarySortColumnId); |
| 376 int columnId = [[column identifier] intValue]; | |
| 377 | 362 |
| 378 if (primarySortColumnId == columnId) { | 363 if (primarySortColumnId == columnId) { |
| 379 NSSortDescriptor* newSortDescriptor = | 364 NSSortDescriptor* newSortDescriptor = |
| 380 [firstRemainingVisibleColumn sortDescriptorPrototype]; | 365 [firstRemainingVisibleColumn sortDescriptorPrototype]; |
| 381 [tableView_ setSortDescriptors: | 366 [tableView_ setSortDescriptors:@[ newSortDescriptor ]]; |
| 382 [NSArray arrayWithObject:newSortDescriptor]]; | |
| 383 } | 367 } |
| 384 } | 368 } |
| 385 | 369 |
| 386 // Make the change. | 370 // Make the change. (This will call back into the SetColumnVisibility() |
| 387 [column setHidden:newState == NSOffState]; | 371 // function to actually do the visibility change.) |
| 388 [item setState:newState]; | 372 tableModel_->ToggleColumnVisibility(columnId); |
| 389 | |
| 390 [tableView_ sizeToFit]; | |
| 391 [tableView_ setNeedsDisplay]; | |
| 392 } | 373 } |
| 393 | 374 |
| 394 // This function appropriately sets the enabled states on the table's editing | 375 // This function appropriately sets the enabled states on the table's editing |
| 395 // buttons. | 376 // buttons. |
| 396 - (void)adjustSelectionAndEndProcessButton { | 377 - (void)adjustSelectionAndEndProcessButton { |
| 397 bool selectionContainsBrowserProcess = false; | 378 bool allSelectionRowsAreKillableTasks = true; |
| 379 NSMutableIndexSet* groupIndexes = [NSMutableIndexSet indexSet]; |
| 398 | 380 |
| 399 // If a row is selected, make sure that all rows belonging to the same process | |
| 400 // are selected as well. Also, check if the selection contains the browser | |
| 401 // process. | |
| 402 NSIndexSet* selection = [tableView_ selectedRowIndexes]; | 381 NSIndexSet* selection = [tableView_ selectedRowIndexes]; |
| 403 for (NSUInteger i = [selection lastIndex]; | 382 for (NSUInteger i = [selection lastIndex]; |
| 404 i != NSNotFound; | 383 i != NSNotFound; |
| 405 i = [selection indexLessThanIndex:i]) { | 384 i = [selection indexLessThanIndex:i]) { |
| 406 int modelIndex = viewToModelMap_[i]; | 385 int modelIndex = viewToModelMap_[i]; |
| 407 if (taskManager_->IsBrowserProcess(modelIndex)) | |
| 408 selectionContainsBrowserProcess = true; | |
| 409 | 386 |
| 410 TaskManagerModel::GroupRange rangePair = | 387 if (!tableModel_->IsTaskKillable(modelIndex)) |
| 411 model_->GetGroupRangeForResource(modelIndex); | 388 allSelectionRowsAreKillableTasks = false; |
| 412 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; | 389 |
| 413 for (int j = 0; j < rangePair.second; ++j) | 390 int groupStart, groupLength; |
| 414 [indexSet addIndex:modelToViewMap_[rangePair.first + j]]; | 391 tableModel_->GetRowsGroupRange(modelIndex, &groupStart, &groupLength); |
| 415 [tableView_ selectRowIndexes:indexSet byExtendingSelection:YES]; | 392 for (int j = 0; j < groupLength; ++j) |
| 393 [groupIndexes addIndex:modelToViewMap_[groupStart + j]]; |
| 416 } | 394 } |
| 417 | 395 |
| 418 bool enabled = [selection count] > 0 && !selectionContainsBrowserProcess && | 396 [tableView_ selectRowIndexes:groupIndexes byExtendingSelection:YES]; |
| 419 task_management::TaskManagerInterface::IsEndProcessEnabled(); | 397 |
| 398 bool enabled = [selection count] > 0 && allSelectionRowsAreKillableTasks && |
| 399 task_management::TaskManagerInterface::IsEndProcessEnabled(); |
| 420 [endProcessButton_ setEnabled:enabled]; | 400 [endProcessButton_ setEnabled:enabled]; |
| 421 } | 401 } |
| 422 | 402 |
| 423 - (void)deselectRows { | 403 - (void)deselectRows { |
| 424 [tableView_ deselectAll:self]; | 404 [tableView_ deselectAll:self]; |
| 425 } | 405 } |
| 426 | 406 |
| 427 // Table view delegate methods. | 407 // Table view delegate methods. |
| 428 | 408 |
| 429 // The selection is being changed by mouse (drag/click). | 409 // The selection is being changed by mouse (drag/click). |
| 430 - (void)tableViewSelectionIsChanging:(NSNotification*)aNotification { | 410 - (void)tableViewSelectionIsChanging:(NSNotification*)aNotification { |
| 431 [self adjustSelectionAndEndProcessButton]; | 411 [self adjustSelectionAndEndProcessButton]; |
| 432 } | 412 } |
| 433 | 413 |
| 434 // The selection is being changed by keyboard (arrows). | 414 // The selection is being changed by keyboard (arrows). |
| 435 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification { | 415 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification { |
| 436 [self adjustSelectionAndEndProcessButton]; | 416 [self adjustSelectionAndEndProcessButton]; |
| 437 } | 417 } |
| 438 | 418 |
| 439 - (void)windowWillClose:(NSNotification*)notification { | 419 - (void)windowWillClose:(NSNotification*)notification { |
| 440 if (taskManagerObserver_) { | 420 if (taskManagerMac_) { |
| 441 taskManagerObserver_->WindowWasClosed(); | 421 tableModel_->StoreColumnsSettings(); |
| 442 taskManagerObserver_ = nil; | 422 taskManagerMac_->WindowWasClosed(); |
| 423 taskManagerMac_ = nullptr; |
| 424 tableModel_ = nullptr; |
| 443 } | 425 } |
| 444 [self autorelease]; | 426 [self autorelease]; |
| 445 } | 427 } |
| 446 | 428 |
| 447 @end | 429 @end |
| 448 | 430 |
| 449 @implementation TaskManagerWindowController (NSTableDataSource) | 431 @implementation TaskManagerWindowController (NSTableDataSource) |
| 450 | 432 |
| 451 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { | 433 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { |
| 452 DCHECK(tableView == tableView_ || tableView_ == nil); | 434 DCHECK(tableView == tableView_ || tableView_ == nil); |
| 453 return model_->ResourceCount(); | 435 return tableModel_->RowCount(); |
| 454 } | 436 } |
| 455 | 437 |
| 456 - (NSString*)modelTextForRow:(int)row column:(int)columnId { | 438 - (NSString*)modelTextForRow:(int)row column:(int)columnId { |
| 457 DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size()); | 439 DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size()); |
| 458 return base::SysUTF16ToNSString( | 440 return base::SysUTF16ToNSString( |
| 459 model_->GetResourceById(viewToModelMap_[row], columnId)); | 441 tableModel_->GetText(viewToModelMap_[row], columnId)); |
| 460 } | 442 } |
| 461 | 443 |
| 462 - (id)tableView:(NSTableView*)tableView | 444 - (id)tableView:(NSTableView*)tableView |
| 463 objectValueForTableColumn:(NSTableColumn*)tableColumn | 445 objectValueForTableColumn:(NSTableColumn*)tableColumn |
| 464 row:(NSInteger)rowIndex { | 446 row:(NSInteger)rowIndex { |
| 465 // NSButtonCells expect an on/off state as objectValue. Their title is set | 447 // NSButtonCells expect an on/off state as objectValue. Their title is set |
| 466 // in |tableView:dataCellForTableColumn:row:| below. | 448 // in |tableView:dataCellForTableColumn:row:| below. |
| 467 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { | 449 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { |
| 468 return [NSNumber numberWithInt:NSOffState]; | 450 return [NSNumber numberWithInt:NSOffState]; |
| 469 } | 451 } |
| 470 | 452 |
| 471 return [self modelTextForRow:rowIndex | 453 return [self modelTextForRow:rowIndex |
| 472 column:[[tableColumn identifier] intValue]]; | 454 column:[[tableColumn identifier] intValue]]; |
| 473 } | 455 } |
| 474 | 456 |
| 475 - (NSCell*)tableView:(NSTableView*)tableView | 457 - (NSCell*)tableView:(NSTableView*)tableView |
| 476 dataCellForTableColumn:(NSTableColumn*)tableColumn | 458 dataCellForTableColumn:(NSTableColumn*)tableColumn |
| 477 row:(NSInteger)rowIndex { | 459 row:(NSInteger)rowIndex { |
| 478 NSCell* cell = [tableColumn dataCellForRow:rowIndex]; | 460 NSCell* cell = [tableColumn dataCellForRow:rowIndex]; |
| 479 | 461 |
| 480 // Set the favicon and title for the task in the name column. | 462 // Set the favicon and title for the task in the name column. |
| 481 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { | 463 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { |
| 482 DCHECK([cell isKindOfClass:[NSButtonCell class]]); | 464 DCHECK([cell isKindOfClass:[NSButtonCell class]]); |
| 483 NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell); | 465 NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell); |
| 484 NSString* title = [self modelTextForRow:rowIndex | 466 NSString* title = [self modelTextForRow:rowIndex |
| 485 column:[[tableColumn identifier] intValue]]; | 467 column:[[tableColumn identifier] intValue]]; |
| 486 [buttonCell setTitle:title]; | 468 [buttonCell setTitle:title]; |
| 487 [buttonCell setImage: | 469 [buttonCell |
| 488 taskManagerObserver_->GetImageForRow(viewToModelMap_[rowIndex])]; | 470 setImage:taskManagerMac_->GetImageForRow(viewToModelMap_[rowIndex])]; |
| 489 [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button. | 471 [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button. |
| 490 [buttonCell setHighlightsBy:NSNoCellMask]; | 472 [buttonCell setHighlightsBy:NSNoCellMask]; |
| 491 } | 473 } |
| 492 | 474 |
| 493 return cell; | 475 return cell; |
| 494 } | 476 } |
| 495 | 477 |
| 496 - (void) tableView:(NSTableView*)tableView | 478 - (void)tableView:(NSTableView*)tableView |
| 497 sortDescriptorsDidChange:(NSArray*)oldDescriptors { | 479 sortDescriptorsDidChange:(NSArray*)oldDescriptors { |
| 498 NSArray* newDescriptors = [tableView sortDescriptors]; | 480 if (withinSortDescriptorsDidChange_) |
| 499 if ([newDescriptors count] < 1) { | 481 return; |
| 500 currentSortDescriptor_.reset(nil); | 482 |
| 483 NSSortDescriptor* oldDescriptor = [oldDescriptors firstObject]; |
| 484 NSSortDescriptor* newDescriptor = [[tableView sortDescriptors] firstObject]; |
| 485 |
| 486 // Implement three-way sorting, toggling "unsorted" as a third option. |
| 487 if (oldDescriptor && newDescriptor && |
| 488 [[oldDescriptor key] isEqual:[newDescriptor key]]) { |
| 489 // The user clicked to change the sort on the previously sorted column. |
| 490 // AppKit toggled the sort order. However, if the sort was toggled to become |
| 491 // the initial sorting direction, clear it instead. |
| 492 NSTableColumn* column = [tableView |
| 493 tableColumnWithIdentifier:ColumnIdentifier( |
| 494 [[newDescriptor key] intValue])]; |
| 495 NSSortDescriptor* initialDescriptor = [column sortDescriptorPrototype]; |
| 496 if ([newDescriptor ascending] == [initialDescriptor ascending]) { |
| 497 withinSortDescriptorsDidChange_ = YES; |
| 498 [tableView_ setSortDescriptors:[NSArray array]]; |
| 499 newDescriptor = nil; |
| 500 withinSortDescriptorsDidChange_ = NO; |
| 501 } |
| 502 } |
| 503 |
| 504 if (newDescriptor) { |
| 505 currentSortDescriptor_.sorted_column_id = [[newDescriptor key] intValue]; |
| 506 currentSortDescriptor_.is_ascending = [newDescriptor ascending]; |
| 501 } else { | 507 } else { |
| 502 currentSortDescriptor_.reset([[newDescriptors objectAtIndex:0] retain]); | 508 currentSortDescriptor_.sorted_column_id = -1; |
| 503 } | 509 } |
| 504 | 510 |
| 505 [self reloadData]; // Sorts. | 511 [self reloadData]; // Sorts. |
| 506 } | 512 } |
| 507 | 513 |
| 508 @end | 514 @end |
| 509 | 515 |
| 516 @implementation TaskManagerWindowController (TestingAPI) |
| 517 |
| 518 - (NSTableView*)tableViewForTesting { |
| 519 return tableView_; |
| 520 } |
| 521 |
| 522 - (NSButton*)endProcessButtonForTesting { |
| 523 return endProcessButton_; |
| 524 } |
| 525 |
| 526 @end |
| 527 |
| 528 namespace task_management { |
| 529 |
| 510 //////////////////////////////////////////////////////////////////////////////// | 530 //////////////////////////////////////////////////////////////////////////////// |
| 511 // TaskManagerMac implementation: | 531 // TaskManagerMac implementation: |
| 512 | 532 |
| 513 TaskManagerMac::TaskManagerMac(TaskManager* task_manager) | 533 TaskManagerMac::TaskManagerMac() |
| 514 : task_manager_(task_manager), | 534 : table_model_(new TaskManagerTableModel( |
| 515 model_(task_manager->model()) { | 535 REFRESH_TYPE_CPU | REFRESH_TYPE_MEMORY | REFRESH_TYPE_NETWORK_USAGE, |
| 516 window_controller_ = | 536 this)), |
| 517 [[TaskManagerWindowController alloc] initWithTaskManagerObserver:this]; | 537 window_controller_([[TaskManagerWindowController alloc] |
| 518 model_->AddObserver(this); | 538 initWithTaskManagerMac:this |
| 539 tableModel:table_model_.get()]) { |
| 540 table_model_->SetObserver(this); // Hook up the ui::TableModelObserver. |
| 541 table_model_->RetrieveSavedColumnsSettingsAndUpdateTable(); |
| 542 |
| 543 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
| 544 content::NotificationService::AllSources()); |
| 519 } | 545 } |
| 520 | 546 |
| 521 // static | 547 // static |
| 522 TaskManagerMac* TaskManagerMac::instance_ = NULL; | 548 TaskManagerMac* TaskManagerMac::instance_ = nullptr; |
| 523 | 549 |
| 524 TaskManagerMac::~TaskManagerMac() { | 550 TaskManagerMac::~TaskManagerMac() { |
| 525 if (this == instance_) { | 551 table_model_->SetObserver(nullptr); |
| 526 // Do not do this when running in unit tests: |StartUpdating()| never got | |
| 527 // called in that case. | |
| 528 task_manager_->OnWindowClosed(); | |
| 529 } | |
| 530 model_->RemoveObserver(this); | |
| 531 } | 552 } |
| 532 | 553 |
| 533 //////////////////////////////////////////////////////////////////////////////// | 554 //////////////////////////////////////////////////////////////////////////////// |
| 534 // TaskManagerMac, TaskManagerModelObserver implementation: | 555 // ui::TableModelObserver implementation: |
| 535 | 556 |
| 536 void TaskManagerMac::OnModelChanged() { | 557 void TaskManagerMac::OnModelChanged() { |
| 537 [window_controller_ deselectRows]; | 558 [window_controller_ deselectRows]; |
| 538 [window_controller_ reloadData]; | 559 [window_controller_ reloadData]; |
| 539 } | 560 } |
| 540 | 561 |
| 541 void TaskManagerMac::OnItemsChanged(int start, int length) { | 562 void TaskManagerMac::OnItemsChanged(int start, int length) { |
| 542 [window_controller_ reloadData]; | 563 [window_controller_ reloadData]; |
| 543 } | 564 } |
| 544 | 565 |
| 545 void TaskManagerMac::OnItemsAdded(int start, int length) { | 566 void TaskManagerMac::OnItemsAdded(int start, int length) { |
| 546 [window_controller_ deselectRows]; | 567 [window_controller_ reloadDataWithRows:length addedAtIndex:start]; |
| 547 [window_controller_ reloadData]; | |
| 548 } | 568 } |
| 549 | 569 |
| 550 void TaskManagerMac::OnItemsRemoved(int start, int length) { | 570 void TaskManagerMac::OnItemsRemoved(int start, int length) { |
| 551 [window_controller_ deselectRows]; | 571 [window_controller_ reloadDataWithRows:-length addedAtIndex:start]; |
| 552 [window_controller_ reloadData]; | 572 } |
| 573 |
| 574 //////////////////////////////////////////////////////////////////////////////// |
| 575 // TableViewDelegate implementation: |
| 576 |
| 577 bool TaskManagerMac::IsColumnVisible(int column_id) const { |
| 578 return [window_controller_ visibilityOfColumnWithId:column_id]; |
| 579 } |
| 580 |
| 581 void TaskManagerMac::SetColumnVisibility(int column_id, bool new_visibility) { |
| 582 [window_controller_ setColumnWithId:column_id toVisibility:new_visibility]; |
| 583 } |
| 584 |
| 585 bool TaskManagerMac::IsTableSorted() const { |
| 586 return [window_controller_ sortDescriptor].sorted_column_id != -1; |
| 587 } |
| 588 |
| 589 TableSortDescriptor TaskManagerMac::GetSortDescriptor() const { |
| 590 return [window_controller_ sortDescriptor]; |
| 591 } |
| 592 |
| 593 void TaskManagerMac::SetSortDescriptor(const TableSortDescriptor& descriptor) { |
| 594 [window_controller_ setSortDescriptor:descriptor]; |
| 595 } |
| 596 |
| 597 //////////////////////////////////////////////////////////////////////////////// |
| 598 // Called by the TaskManagerWindowController: |
| 599 |
| 600 void TaskManagerMac::WindowWasClosed() { |
| 601 delete this; |
| 602 instance_ = nullptr; // |instance_| is static |
| 553 } | 603 } |
| 554 | 604 |
| 555 NSImage* TaskManagerMac::GetImageForRow(int row) { | 605 NSImage* TaskManagerMac::GetImageForRow(int row) { |
| 556 return gfx::NSImageFromImageSkia(model_->GetResourceIcon(row)); | 606 const CGFloat kImageWidth = 16.0; |
| 607 NSImage* image = gfx::NSImageFromImageSkia(table_model_->GetIcon(row)); |
| 608 if (!image) { |
| 609 image = [[[NSImage alloc] initWithSize:NSMakeSize(kImageWidth, kImageWidth)] |
| 610 autorelease]; |
| 611 } |
| 612 return image; |
| 557 } | 613 } |
| 558 | 614 |
| 559 //////////////////////////////////////////////////////////////////////////////// | 615 void TaskManagerMac::Observe(int type, |
| 560 // TaskManagerMac, public: | 616 const content::NotificationSource& source, |
| 561 | 617 const content::NotificationDetails& details) { |
| 562 void TaskManagerMac::WindowWasClosed() { | 618 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); |
| 563 delete this; | 619 Hide(); |
| 564 instance_ = NULL; // |instance_| is static | |
| 565 } | 620 } |
| 566 | 621 |
| 567 // static | 622 // static |
| 568 void TaskManagerMac::Show() { | 623 TaskManagerTableModel* TaskManagerMac::Show() { |
| 569 if (instance_) { | 624 if (instance_) { |
| 570 [[instance_->window_controller_ window] | 625 [[instance_->window_controller_ window] |
| 571 makeKeyAndOrderFront:instance_->window_controller_]; | 626 makeKeyAndOrderFront:instance_->window_controller_]; |
| 572 return; | 627 } else { |
| 628 instance_ = new TaskManagerMac(); |
| 573 } | 629 } |
| 574 // Create a new instance. | 630 |
| 575 instance_ = new TaskManagerMac(TaskManager::GetInstance()); | 631 return instance_->table_model_.get(); |
| 576 instance_->model_->StartUpdating(); | |
| 577 } | 632 } |
| 578 | 633 |
| 579 // static | 634 // static |
| 580 void TaskManagerMac::Hide() { | 635 void TaskManagerMac::Hide() { |
| 581 if (instance_) | 636 if (instance_) |
| 582 [instance_->window_controller_ close]; | 637 [instance_->window_controller_ close]; |
| 583 } | 638 } |
| 584 | 639 |
| 640 } // namespace task_management |
| 641 |
| 585 namespace chrome { | 642 namespace chrome { |
| 586 | 643 |
| 587 // Declared in browser_dialogs.h. | 644 // Declared in browser_dialogs.h. |
| 588 task_management::TaskManagerTableModel* ShowTaskManager(Browser* browser) { | 645 task_management::TaskManagerTableModel* ShowTaskManager(Browser* browser) { |
| 589 if (chrome::ToolkitViewsDialogsEnabled()) | 646 if (chrome::ToolkitViewsDialogsEnabled()) |
| 590 return chrome::ShowTaskManagerViews(browser); | 647 return chrome::ShowTaskManagerViews(browser); |
| 591 | 648 |
| 592 TaskManagerMac::Show(); | 649 return task_management::TaskManagerMac::Show(); |
| 593 return nullptr; // No ui::TableModel* to return on Mac, so return nullptr. | |
| 594 } | 650 } |
| 595 | 651 |
| 596 void HideTaskManager() { | 652 void HideTaskManager() { |
| 597 if (chrome::ToolkitViewsDialogsEnabled()) { | 653 if (chrome::ToolkitViewsDialogsEnabled()) { |
| 598 chrome::HideTaskManagerViews(); | 654 chrome::HideTaskManagerViews(); |
| 599 return; | 655 return; |
| 600 } | 656 } |
| 601 | 657 |
| 602 TaskManagerMac::Hide(); | 658 task_management::TaskManagerMac::Hide(); |
| 603 } | |
| 604 | |
| 605 bool NotifyOldTaskManagerBytesRead(const net::URLRequest& request, | |
| 606 int64_t bytes_read) { | |
| 607 if (task_management::TaskManagerInterface::IsNewTaskManagerEnabled()) | |
| 608 return false; | |
| 609 | |
| 610 TaskManager::GetInstance()->model()->NotifyBytesRead(request, bytes_read); | |
| 611 return true; | |
| 612 } | 659 } |
| 613 | 660 |
| 614 } // namespace chrome | 661 } // namespace chrome |
| 615 | |
| OLD | NEW |