Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: chrome/browser/ui/cocoa/task_manager_mac.mm

Issue 2197483003: Move the Mac Task Manager to the new backend code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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;
ncarter (slow) 2016/08/02 19:49:36 Apparently this is what std::iota is for.
ncarter (slow) 2016/08/02 20:01:06 Erm, I meant the one on line 81, is std::iota-able
Avi (use Gerrit) 2016/08/02 20:06:57 You mean line 80. The problem is that _no_one_ kn
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) {
ncarter (slow) 2016/08/02 19:49:36 I'm pretty sure you can simplify this whole block
Avi (use Gerrit) 2016/08/02 20:06:56 Here's where I have a problem. The code that I wro
ncarter (slow) 2016/08/02 20:16:10 Sure. I think this is one of those things where th
133 for (int& selectedItem : modelSelection) {
134 if (addedRows > 0) {
135 if (addedRowIndex <= selectedItem) {
136 selectedItem += addedRows;
137 } else {
138 // Nothing to do; added items are beyond the selected item.
139 }
140 } else { // removed rows
141 if (addedRowIndex > selectedItem) {
ncarter (slow) 2016/08/02 20:16:10 Maybe at least hoist the "// Nothing to do" case o
Avi (use Gerrit) 2016/08/02 20:31:30 Done.
142 // Nothing to do; removed items are beyond the selected item.
143 } else {
144 int removedRows = -addedRows;
145 if (addedRowIndex + removedRows <= selectedItem) {
afakhry 2016/08/02 16:41:33 Nit: remove braces?
Avi (use Gerrit) 2016/08/02 17:39:44 Maybe? If Mark wants me to I will, but this is a b
146 selectedItem -= removedRows;
147 } else {
148 selectedItem = -1; // The item was removed.
149 }
150 }
151 }
152 }
153 }
154
166 // Sort. 155 // Sort.
167 [self sortShuffleArray]; 156 [self sortShuffleArray];
168 157
169 // Use the model indices to get the new view indices of the selection, and 158 // 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 159 // to clear the selection before reloading the data, and to reload the
171 // (in that case, the selection is cleared before -reloadData is called). 160 // selection after reloading the data, because otherwise the table will adjust
172 if (!modelSelection.empty()) 161 // the selection in ways that are not desirable.
173 DCHECK_EQ([tableView_ numberOfRows], model_->ResourceCount()); 162 [tableView_ deselectAll:nil];
163 [tableView_ reloadData];
164
165 // Reload the selection.
174 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; 166 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
175 for (size_t i = 0; i < modelSelection.size(); ++i) 167 for (auto selectedItem : modelSelection) {
176 [indexSet addIndex:modelToViewMap_[modelSelection[i]]]; 168 if (selectedItem != -1)
169 [indexSet addIndex:modelToViewMap_[selectedItem]];
170 }
177 [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO]; 171 [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO];
178 172
179 [tableView_ reloadData];
180 [self adjustSelectionAndEndProcessButton]; 173 [self adjustSelectionAndEndProcessButton];
181 } 174 }
182 175
176 - (task_management::TableSortDescriptor)sortDescriptor {
177 return currentSortDescriptor_;
178 }
179
180 - (void)setSortDescriptor:
181 (const task_management::TableSortDescriptor&)sortDescriptor {
182 base::scoped_nsobject<NSSortDescriptor> nsSortDescriptor(
183 [[NSSortDescriptor alloc]
184 initWithKey:ColumnIdentifier(sortDescriptor.sorted_column_id)
185 ascending:sortDescriptor.is_ascending]);
186 [tableView_ setSortDescriptors:@[ nsSortDescriptor ]];
187 }
188
189 - (BOOL)visibilityOfColumnWithId:(int)columnId {
190 NSTableColumn* column =
191 [tableView_ tableColumnWithIdentifier:ColumnIdentifier(columnId)];
192 return ![column isHidden];
193 }
194
195 - (void)setColumnWithId:(int)columnId toVisibility:(BOOL)visibility {
196 NSTableColumn* column =
197 [tableView_ tableColumnWithIdentifier:ColumnIdentifier(columnId)];
198 [column setHidden:!visibility];
199
200 [tableView_ sizeToFit];
201 [tableView_ setNeedsDisplay];
202 }
203
183 - (IBAction)killSelectedProcesses:(id)sender { 204 - (IBAction)killSelectedProcesses:(id)sender {
184 NSIndexSet* selection = [tableView_ selectedRowIndexes]; 205 NSIndexSet* selection = [tableView_ selectedRowIndexes];
185 for (NSUInteger i = [selection lastIndex]; 206 for (NSUInteger i = [selection lastIndex];
186 i != NSNotFound; 207 i != NSNotFound;
187 i = [selection indexLessThanIndex:i]) { 208 i = [selection indexLessThanIndex:i]) {
188 taskManager_->KillProcess(viewToModelMap_[i]); 209 tableModel_->KillTask(viewToModelMap_[i]);
189 } 210 }
190 } 211 }
191 212
192 - (void)selectDoubleClickedTab:(id)sender { 213 - (void)tableWasDoubleClicked:(id)sender {
193 NSInteger row = [tableView_ clickedRow]; 214 NSInteger row = [tableView_ clickedRow];
194 if (row < 0) 215 if (row < 0)
195 return; // Happens e.g. if the table header is double-clicked. 216 return; // Happens e.g. if the table header is double-clicked.
196 taskManager_->ActivateProcess(viewToModelMap_[row]); 217 tableModel_->ActivateTask(viewToModelMap_[row]);
197 }
198
199 - (NSTableView*)tableView {
200 return tableView_;
201 } 218 }
202 219
203 - (void)awakeFromNib { 220 - (void)awakeFromNib {
204 [self setUpTableColumns]; 221 [self setUpTableColumns];
205 [self setUpTableHeaderContextMenu]; 222 [self setUpTableHeaderContextMenu];
206 [self adjustSelectionAndEndProcessButton]; 223 [self adjustSelectionAndEndProcessButton];
207 224
208 [tableView_ setDoubleAction:@selector(selectDoubleClickedTab:)]; 225 [tableView_ setDoubleAction:@selector(tableWasDoubleClicked:)];
209 [tableView_ setIntercellSpacing:NSMakeSize(0.0, 0.0)]; 226 [tableView_ setIntercellSpacing:NSMakeSize(0.0, 0.0)];
210 [tableView_ sizeToFit]; 227 [tableView_ sizeToFit];
211 } 228 }
212 229
213 - (void)dealloc { 230 - (void)dealloc {
214 [tableView_ setDelegate:nil]; 231 [tableView_ setDelegate:nil];
215 [tableView_ setDataSource:nil]; 232 [tableView_ setDataSource:nil];
216 [super dealloc]; 233 [super dealloc];
217 } 234 }
218 235
219 // Adds a column which has the given string id as title. |isVisible| specifies 236 // Adds a column which has the given string id as title. |isVisible| specifies
220 // if the column is initially visible. 237 // if the column is initially visible.
221 - (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible { 238 - (NSTableColumn*)addColumnWithData:
239 (const task_management::TableColumnData&)columnData {
222 base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc] 240 base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
223 initWithIdentifier:[NSString stringWithFormat:@"%d", columnId]]); 241 initWithIdentifier:ColumnIdentifier(columnData.id)]);
224 242
225 NSTextAlignment textAlignment = 243 NSTextAlignment textAlignment = (columnData.align == ui::TableColumn::LEFT)
226 (columnId == IDS_TASK_MANAGER_TASK_COLUMN || 244 ? NSLeftTextAlignment
227 columnId == IDS_TASK_MANAGER_PROFILE_NAME_COLUMN) ? 245 : NSRightTextAlignment;
228 NSLeftTextAlignment : NSRightTextAlignment;
229 246
230 [[column.get() headerCell] 247 [[column.get() headerCell]
231 setStringValue:l10n_util::GetNSStringWithFixup(columnId)]; 248 setStringValue:l10n_util::GetNSStringWithFixup(columnData.id)];
232 [[column.get() headerCell] setAlignment:textAlignment]; 249 [[column.get() headerCell] setAlignment:textAlignment];
233 [[column.get() dataCell] setAlignment:textAlignment]; 250 [[column.get() dataCell] setAlignment:textAlignment];
234 251
235 NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]; 252 NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
236 [[column.get() dataCell] setFont:font]; 253 [[column.get() dataCell] setFont:font];
237 254
238 [column.get() setHidden:!isVisible]; 255 [column.get() setHidden:!columnData.default_visibility];
239 [column.get() setEditable:NO]; 256 [column.get() setEditable:NO];
240 257
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( 258 base::scoped_nsobject<NSSortDescriptor> sortDescriptor(
245 [[NSSortDescriptor alloc] 259 [[NSSortDescriptor alloc]
246 initWithKey:[NSString stringWithFormat:@"%d", columnId] 260 initWithKey:ColumnIdentifier(columnData.id)
247 ascending:ascending]); 261 ascending:columnData.initial_sort_is_ascending]);
248 [column.get() setSortDescriptorPrototype:sortDescriptor.get()]; 262 [column.get() setSortDescriptorPrototype:sortDescriptor.get()];
249 263
250 // Default values, only used in release builds if nobody notices the DCHECK 264 [column.get() setMinWidth:columnData.min_width];
251 // during development when adding new columns. 265 int maxWidth = columnData.max_width;
252 int minWidth = 200, maxWidth = 400; 266 if (maxWidth < 0)
253 267 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]; 268 [column.get() setMaxWidth:maxWidth];
267 [column.get() setResizingMask:NSTableColumnAutoresizingMask | 269 [column.get() setResizingMask:NSTableColumnAutoresizingMask |
268 NSTableColumnUserResizingMask]; 270 NSTableColumnUserResizingMask];
269 271
270 [tableView_ addTableColumn:column.get()]; 272 [tableView_ addTableColumn:column.get()];
271 return column.get(); // Now retained by |tableView_|. 273 return column.get(); // Now retained by |tableView_|.
272 } 274 }
273 275
274 // Adds all the task manager's columns to the table. 276 // Adds all the task manager's columns to the table.
275 - (void)setUpTableColumns { 277 - (void)setUpTableColumns {
276 for (NSTableColumn* column in [tableView_ tableColumns]) 278 for (NSTableColumn* column in [tableView_ tableColumns])
277 [tableView_ removeTableColumn:column]; 279 [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 280
290 // Initially, sort on the tab name. 281 for (size_t i = 0; i < task_management::kColumnsSize; ++i) {
291 [tableView_ setSortDescriptors: 282 const auto& columnData = task_management::kColumns[i];
292 [NSArray arrayWithObject:[nameColumn sortDescriptorPrototype]]]; 283 NSTableColumn* column = [self addColumnWithData:columnData];
293 [self addColumnWithId:IDS_TASK_MANAGER_PROFILE_NAME_COLUMN visible:NO]; 284
294 [self addColumnWithId:IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN visible:YES]; 285 if (columnData.id == IDS_TASK_MANAGER_TASK_COLUMN) {
295 [self addColumnWithId:IDS_TASK_MANAGER_SHARED_MEM_COLUMN visible:NO]; 286 // The task column displays an icon for every row, done by an
296 [self addColumnWithId:IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN visible:NO]; 287 // NSButtonCell.
297 [self addColumnWithId:IDS_TASK_MANAGER_CPU_COLUMN visible:YES]; 288 base::scoped_nsobject<NSButtonCell> nameCell(
298 [self addColumnWithId:IDS_TASK_MANAGER_NET_COLUMN visible:YES]; 289 [[NSButtonCell alloc] initTextCell:@""]);
299 [self addColumnWithId:IDS_TASK_MANAGER_PROCESS_ID_COLUMN visible:YES]; 290 [nameCell.get() setImagePosition:NSImageLeft];
300 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN 291 [nameCell.get() setButtonType:NSSwitchButton];
301 visible:NO]; 292 [nameCell.get() setAlignment:[[column dataCell] alignment]];
302 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN 293 [nameCell.get() setFont:[[column dataCell] font]];
303 visible:NO]; 294 [column setDataCell:nameCell.get()];
304 [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN visible:NO]; 295 }
305 [self addColumnWithId:IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN visible:NO]; 296 }
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 } 297 }
314 298
315 // Creates a context menu for the table header that allows the user to toggle 299 // 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. 300 // which columns should be shown and which should be hidden (like the Activity
317 // Task Manager.app's table header context menu). 301 // Monitor.app's table header context menu).
318 - (void)setUpTableHeaderContextMenu { 302 - (void)setUpTableHeaderContextMenu {
319 base::scoped_nsobject<NSMenu> contextMenu( 303 base::scoped_nsobject<NSMenu> contextMenu(
320 [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]); 304 [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]);
305 [contextMenu setDelegate:self];
306 [[tableView_ headerView] setMenu:contextMenu.get()];
307 }
308
309 - (void)menuNeedsUpdate:(NSMenu*)menu {
310 [menu removeAllItems];
311
321 for (NSTableColumn* column in [tableView_ tableColumns]) { 312 for (NSTableColumn* column in [tableView_ tableColumns]) {
322 NSMenuItem* item = [contextMenu.get() 313 NSMenuItem* item = [menu addItemWithTitle:[[column headerCell] stringValue]
323 addItemWithTitle:[[column headerCell] stringValue] 314 action:@selector(toggleColumn:)
324 action:@selector(toggleColumn:) 315 keyEquivalent:@""];
325 keyEquivalent:@""];
326 [item setTarget:self]; 316 [item setTarget:self];
327 [item setRepresentedObject:column]; 317 [item setRepresentedObject:column];
328 [item setState:[column isHidden] ? NSOffState : NSOnState]; 318 [item setState:[column isHidden] ? NSOffState : NSOnState];
329 } 319 }
330 [[tableView_ headerView] setMenu:contextMenu.get()];
331 } 320 }
332 321
333 // Callback for the table header context menu. Toggles visibility of the table 322 // Callback for the table header context menu. Toggles visibility of the table
334 // column associated with the clicked menu item. 323 // column associated with the clicked menu item.
335 - (void)toggleColumn:(id)item { 324 - (void)toggleColumn:(id)item {
336 DCHECK([item isKindOfClass:[NSMenuItem class]]); 325 DCHECK([item isKindOfClass:[NSMenuItem class]]);
337 if (![item isKindOfClass:[NSMenuItem class]]) 326 if (![item isKindOfClass:[NSMenuItem class]])
338 return; 327 return;
339 328
340 NSTableColumn* column = [item representedObject]; 329 NSTableColumn* column = [item representedObject];
330 int columnId = [[column identifier] intValue];
341 DCHECK(column); 331 DCHECK(column);
342 NSInteger oldState = [item state]; 332 NSInteger oldState = [item state];
343 NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState; 333 NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState;
344 334
345 // If hiding the column, make sure at least one column will remain visible. 335 // If hiding the column, make sure at least one column will remain visible.
346 if (newState == NSOffState) { 336 if (newState == NSOffState) {
347 // Find the first column that will be visible after hiding |column|. 337 // Find the first column that will be visible after hiding |column|.
348 NSTableColumn* firstRemainingVisibleColumn = nil; 338 NSTableColumn* firstRemainingVisibleColumn = nil;
349 339
350 for (NSTableColumn* nextColumn in [tableView_ tableColumns]) { 340 for (NSTableColumn* nextColumn in [tableView_ tableColumns]) {
(...skipping 13 matching lines...) Expand all
364 // on hiding the last visible column (perhaps they plan to choose another 354 // 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 355 // 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. 356 // column visible and then hiding the one column that would not hide.
367 if (firstRemainingVisibleColumn == nil) { 357 if (firstRemainingVisibleColumn == nil) {
368 return; 358 return;
369 } 359 }
370 360
371 // If |column| is being used to sort the table (i.e. it's the primary sort 361 // 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 362 // column), make the first remaining visible column the new primary sort
373 // column. 363 // column.
374 int primarySortColumnId = [[currentSortDescriptor_.get() key] intValue]; 364 int primarySortColumnId = currentSortDescriptor_.sorted_column_id;
375 DCHECK(primarySortColumnId); 365 DCHECK(primarySortColumnId);
376 int columnId = [[column identifier] intValue];
377 366
378 if (primarySortColumnId == columnId) { 367 if (primarySortColumnId == columnId) {
379 NSSortDescriptor* newSortDescriptor = 368 NSSortDescriptor* newSortDescriptor =
380 [firstRemainingVisibleColumn sortDescriptorPrototype]; 369 [firstRemainingVisibleColumn sortDescriptorPrototype];
381 [tableView_ setSortDescriptors: 370 [tableView_ setSortDescriptors:@[ newSortDescriptor ]];
382 [NSArray arrayWithObject:newSortDescriptor]];
383 } 371 }
384 } 372 }
385 373
386 // Make the change. 374 // Make the change. (This will call back into the SetColumnVisibility()
387 [column setHidden:newState == NSOffState]; 375 // function to actually do the visibility change.)
388 [item setState:newState]; 376 tableModel_->ToggleColumnVisibility(columnId);
389
390 [tableView_ sizeToFit];
391 [tableView_ setNeedsDisplay];
392 } 377 }
393 378
394 // This function appropriately sets the enabled states on the table's editing 379 // This function appropriately sets the enabled states on the table's editing
395 // buttons. 380 // buttons.
396 - (void)adjustSelectionAndEndProcessButton { 381 - (void)adjustSelectionAndEndProcessButton {
397 bool selectionContainsBrowserProcess = false; 382 bool allSelectionRowsAreKillableTasks = true;
383 NSMutableIndexSet* groupIndexes = [NSMutableIndexSet indexSet];
398 384
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]; 385 NSIndexSet* selection = [tableView_ selectedRowIndexes];
403 for (NSUInteger i = [selection lastIndex]; 386 for (NSUInteger i = [selection lastIndex];
404 i != NSNotFound; 387 i != NSNotFound;
405 i = [selection indexLessThanIndex:i]) { 388 i = [selection indexLessThanIndex:i]) {
406 int modelIndex = viewToModelMap_[i]; 389 int modelIndex = viewToModelMap_[i];
407 if (taskManager_->IsBrowserProcess(modelIndex))
408 selectionContainsBrowserProcess = true;
409 390
410 TaskManagerModel::GroupRange rangePair = 391 if (!tableModel_->IsTaskKillable(modelIndex))
411 model_->GetGroupRangeForResource(modelIndex); 392 allSelectionRowsAreKillableTasks = false;
412 NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet]; 393
413 for (int j = 0; j < rangePair.second; ++j) 394 int groupStart, groupLength;
414 [indexSet addIndex:modelToViewMap_[rangePair.first + j]]; 395 tableModel_->GetRowsGroupRange(modelIndex, &groupStart, &groupLength);
415 [tableView_ selectRowIndexes:indexSet byExtendingSelection:YES]; 396 for (int j = 0; j < groupLength; ++j)
397 [groupIndexes addIndex:modelToViewMap_[groupStart + j]];
416 } 398 }
417 399
418 bool enabled = [selection count] > 0 && !selectionContainsBrowserProcess && 400 [tableView_ selectRowIndexes:groupIndexes byExtendingSelection:YES];
419 task_management::TaskManagerInterface::IsEndProcessEnabled(); 401
402 bool enabled = [selection count] > 0 && allSelectionRowsAreKillableTasks &&
403 task_management::TaskManagerInterface::IsEndProcessEnabled();
420 [endProcessButton_ setEnabled:enabled]; 404 [endProcessButton_ setEnabled:enabled];
421 } 405 }
422 406
423 - (void)deselectRows { 407 - (void)deselectRows {
424 [tableView_ deselectAll:self]; 408 [tableView_ deselectAll:self];
425 } 409 }
426 410
427 // Table view delegate methods. 411 // Table view delegate methods.
428 412
429 // The selection is being changed by mouse (drag/click). 413 // The selection is being changed by mouse (drag/click).
430 - (void)tableViewSelectionIsChanging:(NSNotification*)aNotification { 414 - (void)tableViewSelectionIsChanging:(NSNotification*)aNotification {
431 [self adjustSelectionAndEndProcessButton]; 415 [self adjustSelectionAndEndProcessButton];
432 } 416 }
433 417
434 // The selection is being changed by keyboard (arrows). 418 // The selection is being changed by keyboard (arrows).
435 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification { 419 - (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
436 [self adjustSelectionAndEndProcessButton]; 420 [self adjustSelectionAndEndProcessButton];
437 } 421 }
438 422
439 - (void)windowWillClose:(NSNotification*)notification { 423 - (void)windowWillClose:(NSNotification*)notification {
440 if (taskManagerObserver_) { 424 if (taskManagerMac_) {
441 taskManagerObserver_->WindowWasClosed(); 425 tableModel_->StoreColumnsSettings();
442 taskManagerObserver_ = nil; 426 taskManagerMac_->WindowWasClosed();
427 taskManagerMac_ = nullptr;
428 tableModel_ = nullptr;
443 } 429 }
444 [self autorelease]; 430 [self autorelease];
445 } 431 }
446 432
447 @end 433 @end
448 434
449 @implementation TaskManagerWindowController (NSTableDataSource) 435 @implementation TaskManagerWindowController (NSTableDataSource)
450 436
451 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { 437 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
452 DCHECK(tableView == tableView_ || tableView_ == nil); 438 DCHECK(tableView == tableView_ || tableView_ == nil);
453 return model_->ResourceCount(); 439 return tableModel_->RowCount();
454 } 440 }
455 441
456 - (NSString*)modelTextForRow:(int)row column:(int)columnId { 442 - (NSString*)modelTextForRow:(int)row column:(int)columnId {
457 DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size()); 443 DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size());
458 return base::SysUTF16ToNSString( 444 return base::SysUTF16ToNSString(
459 model_->GetResourceById(viewToModelMap_[row], columnId)); 445 tableModel_->GetText(viewToModelMap_[row], columnId));
460 } 446 }
461 447
462 - (id)tableView:(NSTableView*)tableView 448 - (id)tableView:(NSTableView*)tableView
463 objectValueForTableColumn:(NSTableColumn*)tableColumn 449 objectValueForTableColumn:(NSTableColumn*)tableColumn
464 row:(NSInteger)rowIndex { 450 row:(NSInteger)rowIndex {
465 // NSButtonCells expect an on/off state as objectValue. Their title is set 451 // NSButtonCells expect an on/off state as objectValue. Their title is set
466 // in |tableView:dataCellForTableColumn:row:| below. 452 // in |tableView:dataCellForTableColumn:row:| below.
467 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { 453 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) {
468 return [NSNumber numberWithInt:NSOffState]; 454 return [NSNumber numberWithInt:NSOffState];
469 } 455 }
470 456
471 return [self modelTextForRow:rowIndex 457 return [self modelTextForRow:rowIndex
472 column:[[tableColumn identifier] intValue]]; 458 column:[[tableColumn identifier] intValue]];
473 } 459 }
474 460
475 - (NSCell*)tableView:(NSTableView*)tableView 461 - (NSCell*)tableView:(NSTableView*)tableView
476 dataCellForTableColumn:(NSTableColumn*)tableColumn 462 dataCellForTableColumn:(NSTableColumn*)tableColumn
477 row:(NSInteger)rowIndex { 463 row:(NSInteger)rowIndex {
478 NSCell* cell = [tableColumn dataCellForRow:rowIndex]; 464 NSCell* cell = [tableColumn dataCellForRow:rowIndex];
479 465
480 // Set the favicon and title for the task in the name column. 466 // Set the favicon and title for the task in the name column.
481 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) { 467 if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_TASK_COLUMN) {
482 DCHECK([cell isKindOfClass:[NSButtonCell class]]); 468 DCHECK([cell isKindOfClass:[NSButtonCell class]]);
483 NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell); 469 NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
484 NSString* title = [self modelTextForRow:rowIndex 470 NSString* title = [self modelTextForRow:rowIndex
485 column:[[tableColumn identifier] intValue]]; 471 column:[[tableColumn identifier] intValue]];
486 [buttonCell setTitle:title]; 472 [buttonCell setTitle:title];
487 [buttonCell setImage: 473 [buttonCell
488 taskManagerObserver_->GetImageForRow(viewToModelMap_[rowIndex])]; 474 setImage:taskManagerMac_->GetImageForRow(viewToModelMap_[rowIndex])];
489 [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button. 475 [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
490 [buttonCell setHighlightsBy:NSNoCellMask]; 476 [buttonCell setHighlightsBy:NSNoCellMask];
491 } 477 }
492 478
493 return cell; 479 return cell;
494 } 480 }
495 481
496 - (void) tableView:(NSTableView*)tableView 482 - (void)tableView:(NSTableView*)tableView
497 sortDescriptorsDidChange:(NSArray*)oldDescriptors { 483 sortDescriptorsDidChange:(NSArray*)oldDescriptors {
498 NSArray* newDescriptors = [tableView sortDescriptors]; 484 if (withinSortDescriptorsDidChange_)
ncarter (slow) 2016/08/02 19:49:36 Is recursion here unavoidable, or could we wire th
Avi (use Gerrit) 2016/08/02 20:06:56 This is a callback from the NSTableView class that
499 if ([newDescriptors count] < 1) { 485 return;
500 currentSortDescriptor_.reset(nil); 486
487 NSSortDescriptor* oldDescriptor = [oldDescriptors firstObject];
488 NSSortDescriptor* newDescriptor = [[tableView sortDescriptors] firstObject];
489
490 // Implement three-way sorting, toggling "unsorted" as a third option.
491 if (oldDescriptor && newDescriptor &&
492 [[oldDescriptor key] isEqual:[newDescriptor key]]) {
493 // The user clicked to change the sort on the previously sorted column.
494 // AppKit toggled the sort order. However, if the sort was toggled to become
495 // the initial sorting direction, clear it instead.
496 NSTableColumn* column = [tableView
497 tableColumnWithIdentifier:ColumnIdentifier(
498 [[newDescriptor key] intValue])];
499 NSSortDescriptor* initialDescriptor = [column sortDescriptorPrototype];
500 if ([newDescriptor ascending] == [initialDescriptor ascending]) {
501 withinSortDescriptorsDidChange_ = YES;
502 [tableView_ setSortDescriptors:[NSArray array]];
503 newDescriptor = nil;
504 withinSortDescriptorsDidChange_ = NO;
505 }
506 }
507
508 if (newDescriptor) {
509 currentSortDescriptor_.sorted_column_id = [[newDescriptor key] intValue];
510 currentSortDescriptor_.is_ascending = [newDescriptor ascending];
501 } else { 511 } else {
502 currentSortDescriptor_.reset([[newDescriptors objectAtIndex:0] retain]); 512 currentSortDescriptor_.sorted_column_id = -1;
503 } 513 }
504 514
505 [self reloadData]; // Sorts. 515 [self reloadData]; // Sorts.
506 } 516 }
507 517
508 @end 518 @end
509 519
520 @implementation TaskManagerWindowController (TestingAPI)
521
522 - (NSTableView*)tableViewForTesting {
523 return tableView_;
524 }
525
526 - (NSButton*)endProcessButtonForTesting {
527 return endProcessButton_;
528 }
529
530 @end
531
532 namespace task_management {
533
510 //////////////////////////////////////////////////////////////////////////////// 534 ////////////////////////////////////////////////////////////////////////////////
511 // TaskManagerMac implementation: 535 // TaskManagerMac implementation:
512 536
513 TaskManagerMac::TaskManagerMac(TaskManager* task_manager) 537 TaskManagerMac::TaskManagerMac()
514 : task_manager_(task_manager), 538 : table_model_(new TaskManagerTableModel(
515 model_(task_manager->model()) { 539 REFRESH_TYPE_CPU | REFRESH_TYPE_MEMORY | REFRESH_TYPE_NETWORK_USAGE,
516 window_controller_ = 540 this)),
517 [[TaskManagerWindowController alloc] initWithTaskManagerObserver:this]; 541 window_controller_([[TaskManagerWindowController alloc]
518 model_->AddObserver(this); 542 initWithTaskManagerMac:this
543 tableModel:table_model_.get()]) {
544 table_model_->SetObserver(this); // Hook up the ui::TableModelObserver.
545 table_model_->RetrieveSavedColumnsSettingsAndUpdateTable();
546
547 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
548 content::NotificationService::AllSources());
519 } 549 }
520 550
521 // static 551 // static
522 TaskManagerMac* TaskManagerMac::instance_ = NULL; 552 TaskManagerMac* TaskManagerMac::instance_ = nullptr;
523 553
524 TaskManagerMac::~TaskManagerMac() { 554 TaskManagerMac::~TaskManagerMac() {
525 if (this == instance_) { 555 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 } 556 }
532 557
533 //////////////////////////////////////////////////////////////////////////////// 558 ////////////////////////////////////////////////////////////////////////////////
534 // TaskManagerMac, TaskManagerModelObserver implementation: 559 // ui::TableModelObserver implementation:
535 560
536 void TaskManagerMac::OnModelChanged() { 561 void TaskManagerMac::OnModelChanged() {
537 [window_controller_ deselectRows]; 562 [window_controller_ deselectRows];
538 [window_controller_ reloadData]; 563 [window_controller_ reloadData];
539 } 564 }
540 565
541 void TaskManagerMac::OnItemsChanged(int start, int length) { 566 void TaskManagerMac::OnItemsChanged(int start, int length) {
542 [window_controller_ reloadData]; 567 [window_controller_ reloadData];
543 } 568 }
544 569
545 void TaskManagerMac::OnItemsAdded(int start, int length) { 570 void TaskManagerMac::OnItemsAdded(int start, int length) {
546 [window_controller_ deselectRows]; 571 [window_controller_ reloadDataWithRows:length addedAtIndex:start];
547 [window_controller_ reloadData];
548 } 572 }
549 573
550 void TaskManagerMac::OnItemsRemoved(int start, int length) { 574 void TaskManagerMac::OnItemsRemoved(int start, int length) {
551 [window_controller_ deselectRows]; 575 [window_controller_ reloadDataWithRows:-length addedAtIndex:start];
552 [window_controller_ reloadData]; 576 }
577
578 ////////////////////////////////////////////////////////////////////////////////
579 // TableViewDelegate implementation:
580
581 bool TaskManagerMac::IsColumnVisible(int column_id) const {
582 return [window_controller_ visibilityOfColumnWithId:column_id];
583 }
584
585 void TaskManagerMac::SetColumnVisibility(int column_id, bool new_visibility) {
586 [window_controller_ setColumnWithId:column_id toVisibility:new_visibility];
587 }
588
589 bool TaskManagerMac::IsTableSorted() const {
590 return [window_controller_ sortDescriptor].sorted_column_id != -1;
591 }
592
593 TableSortDescriptor TaskManagerMac::GetSortDescriptor() const {
594 return [window_controller_ sortDescriptor];
595 }
596
597 void TaskManagerMac::SetSortDescriptor(const TableSortDescriptor& descriptor) {
598 [window_controller_ setSortDescriptor:descriptor];
599 }
600
601 ////////////////////////////////////////////////////////////////////////////////
602 // Called by the TaskManagerWindowController:
603
604 void TaskManagerMac::WindowWasClosed() {
605 delete this;
606 instance_ = nullptr; // |instance_| is static
553 } 607 }
554 608
555 NSImage* TaskManagerMac::GetImageForRow(int row) { 609 NSImage* TaskManagerMac::GetImageForRow(int row) {
556 return gfx::NSImageFromImageSkia(model_->GetResourceIcon(row)); 610 const CGFloat kImageWidth = 16.0;
611 NSImage* image = gfx::NSImageFromImageSkia(table_model_->GetIcon(row));
612 if (!image) {
613 image = [[[NSImage alloc] initWithSize:NSMakeSize(kImageWidth, kImageWidth)]
614 autorelease];
615 }
616 return image;
557 } 617 }
558 618
559 //////////////////////////////////////////////////////////////////////////////// 619 void TaskManagerMac::Observe(int type,
560 // TaskManagerMac, public: 620 const content::NotificationSource& source,
561 621 const content::NotificationDetails& details) {
562 void TaskManagerMac::WindowWasClosed() { 622 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
afakhry 2016/08/02 16:41:33 I thought you hated notifications! :)
Avi (use Gerrit) 2016/08/02 17:39:44 😢 You don't even know how much it hurts to have to
563 delete this; 623 Hide();
564 instance_ = NULL; // |instance_| is static
565 } 624 }
566 625
567 // static 626 // static
568 void TaskManagerMac::Show() { 627 TaskManagerTableModel* TaskManagerMac::Show() {
569 if (instance_) { 628 if (instance_) {
570 [[instance_->window_controller_ window] 629 [[instance_->window_controller_ window]
571 makeKeyAndOrderFront:instance_->window_controller_]; 630 makeKeyAndOrderFront:instance_->window_controller_];
572 return; 631 } else {
632 instance_ = new TaskManagerMac();
573 } 633 }
574 // Create a new instance. 634
575 instance_ = new TaskManagerMac(TaskManager::GetInstance()); 635 return instance_->table_model_.get();
576 instance_->model_->StartUpdating();
577 } 636 }
578 637
579 // static 638 // static
580 void TaskManagerMac::Hide() { 639 void TaskManagerMac::Hide() {
581 if (instance_) 640 if (instance_)
582 [instance_->window_controller_ close]; 641 [instance_->window_controller_ close];
583 } 642 }
584 643
644 } // namespace task_management
645
585 namespace chrome { 646 namespace chrome {
586 647
587 // Declared in browser_dialogs.h. 648 // Declared in browser_dialogs.h.
588 task_management::TaskManagerTableModel* ShowTaskManager(Browser* browser) { 649 task_management::TaskManagerTableModel* ShowTaskManager(Browser* browser) {
589 if (chrome::ToolkitViewsDialogsEnabled()) 650 if (chrome::ToolkitViewsDialogsEnabled())
590 return chrome::ShowTaskManagerViews(browser); 651 return chrome::ShowTaskManagerViews(browser);
591 652
592 TaskManagerMac::Show(); 653 return task_management::TaskManagerMac::Show();
593 return nullptr; // No ui::TableModel* to return on Mac, so return nullptr.
594 } 654 }
595 655
596 void HideTaskManager() { 656 void HideTaskManager() {
597 if (chrome::ToolkitViewsDialogsEnabled()) { 657 if (chrome::ToolkitViewsDialogsEnabled()) {
598 chrome::HideTaskManagerViews(); 658 chrome::HideTaskManagerViews();
599 return; 659 return;
600 } 660 }
601 661
602 TaskManagerMac::Hide(); 662 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 } 663 }
613 664
614 } // namespace chrome 665 } // namespace chrome
615
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698