1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/new_task_manager_view.h"
9 #include "base/i18n/number_formatting.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/profiles/profile_window.h"
17 #include "chrome/browser/task_management/task_manager_interface.h"
18 #include "chrome/browser/task_management/task_manager_observer.h"
19 #include "chrome/browser/ui/user_manager.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/grit/chromium_strings.h"
23 #include "chrome/grit/generated_resources.h"
24 #include "components/nacl/browser/nacl_browser.h"
25 #include "content/public/common/result_codes.h"
26 #include "third_party/WebKit/public/web/WebCache.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/models/table_model_observer.h"
29 #include "ui/base/text/bytes_formatting.h"
30 #include "ui/views/controls/label.h"
31 #include "ui/views/controls/link.h"
32 #include "ui/views/controls/table/table_grouper.h"
33 #include "ui/views/controls/table/table_view.h"
34 #include "ui/views/layout/layout_constants.h"
35 #include "ui/views/view.h"
36 #include "ui/views/widget/widget.h"
39 #include "ash/shelf/shelf_util.h"
40 #include "ash/wm/window_util.h"
41 #include "grit/ash_resources.h"
42 #endif // defined(USE_ASH)
45 #include "chrome/browser/shell_integration.h"
46 #include "ui/base/win/shell.h"
47 #include "ui/views/win/hwnd_util.h"
48 #endif // defined(OS_WIN)
50 namespace task_management
{
54 NewTaskManagerView
* g_task_manager_view
= nullptr;
56 #if defined(OS_MACOSX)
57 // Match Activity Monitor's default refresh rate.
58 const int64 kRefreshTimeMS
= 2000;
60 // Activity Monitor shows %cpu with one decimal digit -- be consistent with
62 const char kCpuTextFormatString
[] = "%.1f";
64 const int64 kRefreshTimeMS
= 1000;
65 const char kCpuTextFormatString
[] = "%.0f";
66 #endif // defined(OS_MACOSX)
68 // The columns that are shared by a group will show the value of the column
69 // only once per group.
70 bool IsSharedByGroup(int column_id
) {
72 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
73 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
74 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
75 case IDS_TASK_MANAGER_CPU_COLUMN
:
76 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
77 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
78 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
79 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
80 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
81 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
82 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
83 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
90 // Opens the "about:memory" for the "stats for nerds" link.
91 void OpenAboutMemory(chrome::HostDesktopType desktop_type
) {
92 Profile
* profile
= ProfileManager::GetLastUsedProfileAllowedByPolicy();
93 if (profile
->IsGuestSession() &&
94 !g_browser_process
->local_state()->GetBoolean(
95 prefs::kBrowserGuestModeEnabled
)) {
96 UserManager::Show(base::FilePath(),
97 profiles::USER_MANAGER_NO_TUTORIAL
,
98 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY
);
102 chrome::NavigateParams
params(profile
,
103 GURL(chrome::kChromeUIMemoryURL
),
104 ui::PAGE_TRANSITION_LINK
);
105 params
.disposition
= NEW_FOREGROUND_TAB
;
106 params
.host_desktop_type
= desktop_type
;
107 chrome::Navigate(¶ms
);
110 // Used to sort various column values.
112 int ValueCompare(T value1
, T value2
) {
113 if (value1
== value2
)
115 return value1
< value2
? -1 : 1;
118 // Used when one or both of the results to compare are unavailable.
119 int OrderUnavailableValue(bool v1
, bool v2
) {
125 // A class to stringify the task manager's values into string16s and to
126 // cache the common strings that will be reused many times like "N/A" and so on.
127 class TaskManagerValuesStringifier
{
129 TaskManagerValuesStringifier()
130 : n_a_string_(l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
)),
131 zero_string_(base::ASCIIToUTF16("0")),
132 asterisk_string_(base::ASCIIToUTF16("*")),
133 unknown_string_(l10n_util::GetStringUTF16(
134 IDS_TASK_MANAGER_UNKNOWN_VALUE_TEXT
)) {
137 ~TaskManagerValuesStringifier() {}
139 base::string16
GetCpuUsageText(double cpu_usage
) {
140 return base::UTF8ToUTF16(base::StringPrintf(kCpuTextFormatString
,
144 base::string16
GetMemoryUsageText(int64 memory_usage
, bool has_duplicates
) {
145 if (memory_usage
== -1)
148 #if defined(OS_MACOSX)
149 // System expectation is to show "100 kB", "200 MB", etc.
150 // TODO(thakis): [This TODO has been taken as is from the old task manager]:
151 // Switch to metric units (as opposed to powers of two).
152 base::string16 memory_text
= ui::FormatBytes(memory_usage
);
154 base::string16 memory_text
= base::FormatNumber(memory_usage
/ 1024);
155 // Adjust number string if necessary.
156 base::i18n::AdjustStringForLocaleDirection(&memory_text
);
157 memory_text
= l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT
,
159 #endif // defined(OS_MACOSX)
162 memory_text
+= asterisk_string_
;
167 base::string16
GetIdleWakeupsText(int idle_wakeups
) {
168 if (idle_wakeups
== -1)
171 return base::FormatNumber(idle_wakeups
);
174 base::string16
GetNaClPortText(int nacl_port
) {
175 if (nacl_port
== nacl::kGdbDebugStubPortUnused
)
178 if (nacl_port
== nacl::kGdbDebugStubPortUnknown
)
179 return unknown_string_
;
181 return base::IntToString16(nacl_port
);
184 base::string16
GetWindowsHandlesText(int64 current
, int64 peak
) {
185 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
186 base::IntToString16(current
),
187 base::IntToString16(peak
));
190 base::string16
GetNetworkUsageText(int64 network_usage
) {
191 if (network_usage
== -1)
194 if (network_usage
== 0)
197 base::string16 net_byte
= ui::FormatSpeed(network_usage
);
198 // Force number string to have LTR directionality.
199 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte
);
202 base::string16
GetProcessIdText(base::ProcessId proc_id
) {
203 return base::IntToString16(proc_id
);
206 base::string16
FormatAllocatedAndUsedMemory(int64 allocated
, int64 used
) {
207 return l10n_util::GetStringFUTF16(
208 IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
209 ui::FormatBytesWithUnits(allocated
, ui::DATA_UNITS_KIBIBYTE
, false),
210 ui::FormatBytesWithUnits(used
, ui::DATA_UNITS_KIBIBYTE
, false));
213 base::string16
GetWebCacheStatText(
214 const blink::WebCache::ResourceTypeStat
& stat
) {
215 return FormatAllocatedAndUsedMemory(stat
.size
, stat
.liveSize
);
218 const base::string16
& n_a_string() const { return n_a_string_
; }
219 const base::string16
& zero_string() const { return zero_string_
; }
220 const base::string16
& asterisk_string() const { return asterisk_string_
; }
221 const base::string16
& unknown_string() const { return unknown_string_
; }
224 // The localized string "N/A".
225 const base::string16 n_a_string_
;
227 // The value 0 as a string "0".
228 const base::string16 zero_string_
;
230 // The string "*" that is used to show that there exists duplicates in the
232 const base::string16 asterisk_string_
;
234 // The string "Unknown".
235 const base::string16 unknown_string_
;
237 DISALLOW_COPY_AND_ASSIGN(TaskManagerValuesStringifier
);
242 ////////////////////////////////////////////////////////////////////////////////
244 // IMPORTANT: Do NOT change the below list without changing the COLUMN_LIST
246 const TableColumnData kColumns
[] = {
247 { IDS_TASK_MANAGER_TASK_COLUMN
, ui::TableColumn::LEFT
, -1, 1, true, true,
249 { IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
, ui::TableColumn::LEFT
, -1, 0, true,
251 { IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
253 { IDS_TASK_MANAGER_SHARED_MEM_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
255 { IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
257 { IDS_TASK_MANAGER_CPU_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true, false,
259 { IDS_TASK_MANAGER_NET_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true, false,
261 { IDS_TASK_MANAGER_PROCESS_ID_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
265 { IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
267 { IDS_TASK_MANAGER_USER_HANDLES_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
271 { IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
, ui::TableColumn::RIGHT
, -1, 0,
272 true, false, false },
273 { IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
, ui::TableColumn::RIGHT
, -1,
274 0, true, false, false },
275 { IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
, ui::TableColumn::RIGHT
, -1, 0,
276 true, false, false },
277 { IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
279 { IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
, ui::TableColumn::RIGHT
, -1, 0,
280 true, false, false },
282 #if !defined(DISABLE_NACL)
283 { IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
, ui::TableColumn::RIGHT
, -1, 0,
285 #endif // !defined(DISABLE_NACL)
287 { IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
, ui::TableColumn::RIGHT
,
288 -1, 0, true, false, false },
290 #if defined(OS_MACOSX) || defined(OS_LINUX)
291 // TODO(port): Port the idle wakeups per second to platforms other than Linux
292 // and MacOS (http://crbug.com/120488).
293 { IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
, ui::TableColumn::RIGHT
, -1, 0, true,
295 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
298 const size_t kColumnsSize
= arraysize(kColumns
);
300 const char kSortColumnIdKey
[] = "sort_column_id";
301 const char kSortIsAscendingKey
[] = "sort_is_ascending";
303 // We can't use the integer IDs of the columns converted to strings as session
304 // restore keys. These integer values can change from one build to another as
305 // they are generated. Instead we use the literal string value of the column
306 // ID symbol (i.e. for the ID IDS_TASK_MANAGER_TASK_COLUMN, we use the literal
307 // string "IDS_TASK_MANAGER_TASK_COLUMN". The following macros help us
308 // efficiently get the literal ID for the integer value.
309 #define COLUMNS_LITS(def) \
310 def(IDS_TASK_MANAGER_TASK_COLUMN) \
311 def(IDS_TASK_MANAGER_PROFILE_NAME_COLUMN) \
312 def(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN) \
313 def(IDS_TASK_MANAGER_SHARED_MEM_COLUMN) \
314 def(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN) \
315 def(IDS_TASK_MANAGER_CPU_COLUMN) \
316 def(IDS_TASK_MANAGER_NET_COLUMN) \
317 def(IDS_TASK_MANAGER_PROCESS_ID_COLUMN) \
318 def(IDS_TASK_MANAGER_GDI_HANDLES_COLUMN) \
319 def(IDS_TASK_MANAGER_USER_HANDLES_COLUMN) \
320 def(IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN) \
321 def(IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN) \
322 def(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN) \
323 def(IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN) \
324 def(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN) \
325 def(IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN) \
326 def(IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN) \
327 def(IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN)
328 // Add to the above list in the macro any new IDs added in the future. Also
329 // remove the removed ones.
331 #define COLUMN_ID_AS_STRING(col_id) case col_id: return std::string(#col_id);
333 std::string
GetColumnIdAsString(int column_id
) {
335 COLUMNS_LITS(COLUMN_ID_AS_STRING
)
338 return std::string();
342 ////////////////////////////////////////////////////////////////////////////////
344 // The table model of the task manager table view that will observe the
345 // task manager backend and adapt its interface to match the requirements of the
347 class NewTaskManagerView::TableModel
348 : public TaskManagerObserver
,
349 public ui::TableModel
,
350 public views::TableGrouper
{
352 explicit TableModel(int64 refresh_flags
);
353 ~TableModel() override
;
356 int RowCount() override
;
357 base::string16
GetText(int row
, int column
) override
;
358 gfx::ImageSkia
GetIcon(int row
) override
;
359 void SetObserver(ui::TableModelObserver
* observer
) override
;
360 int CompareValues(int row1
, int row2
, int column_id
) override
;
362 // views::TableGrouper:
363 void GetGroupRange(int model_index
, views::GroupRange
* range
) override
;
365 // task_management::TaskManagerObserver:
366 void OnTaskAdded(TaskId id
) override
;
367 void OnTaskToBeRemoved(TaskId id
) override
;
368 void OnTasksRefreshed(const TaskIdList
& task_ids
) override
;
370 // Start / stop observing the task manager.
371 void StartUpdating();
374 // Activates the browser tab associated with the process in the specified
376 void ActivateTask(int row_index
);
378 // Kills the process on which the task at |row_index| is running.
379 void KillTask(int row_index
);
381 // Based on the given |visibility| and the |column_id|, a particular refresh
382 // type will be enabled or disabled. Multiple columns can map to the same
383 // refresh type, for that we need |table| to determine if any is visible.
384 void UpdateRefreshTypes(views::TableView
* table
,
389 // Checks if the task at |row_index| is running on the browser process.
390 bool IsBrowserProcess(int row_index
) const;
395 // Checks whether the task at |row_index| is the first task in its process
397 bool IsTaskFirstInGroup(int row_index
) const;
399 // The table model observer that will be set by the table view of the task
401 ui::TableModelObserver
* table_model_observer_
;
403 // The sorted list of task IDs by process ID then by task ID.
404 std::vector
<TaskId
> tasks_
;
406 // The owned task manager values stringifier that will be used to convert the
407 // values to string16.
408 TaskManagerValuesStringifier stringifier_
;
410 DISALLOW_COPY_AND_ASSIGN(TableModel
);
413 ////////////////////////////////////////////////////////////////////////////////
414 // NewTaskManagerView::TableModel Implementation:
415 ////////////////////////////////////////////////////////////////////////////////
417 NewTaskManagerView::TableModel::TableModel(int64 refresh_flags
)
418 : TaskManagerObserver(base::TimeDelta::FromMilliseconds(kRefreshTimeMS
),
420 table_model_observer_(nullptr) {
423 NewTaskManagerView::TableModel::~TableModel() {
426 int NewTaskManagerView::TableModel::RowCount() {
427 return static_cast<int>(tasks_
.size());
430 base::string16
NewTaskManagerView::TableModel::GetText(int row
, int column
) {
431 if (IsSharedByGroup(column
) && !IsTaskFirstInGroup(row
))
432 return base::string16();
435 case IDS_TASK_MANAGER_TASK_COLUMN
:
436 return observed_task_manager()->GetTitle(tasks_
[row
]);
438 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
439 return observed_task_manager()->GetProfileName(tasks_
[row
]);
441 case IDS_TASK_MANAGER_NET_COLUMN
:
442 return stringifier_
.GetNetworkUsageText(
443 observed_task_manager()->GetNetworkUsage(tasks_
[row
]));
445 case IDS_TASK_MANAGER_CPU_COLUMN
:
446 return stringifier_
.GetCpuUsageText(
447 observed_task_manager()->GetCpuUsage(tasks_
[row
]));
449 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
450 return stringifier_
.GetMemoryUsageText(
451 observed_task_manager()->GetPrivateMemoryUsage(tasks_
[row
]), false);
453 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
454 return stringifier_
.GetMemoryUsageText(
455 observed_task_manager()->GetSharedMemoryUsage(tasks_
[row
]), false);
457 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
458 return stringifier_
.GetMemoryUsageText(
459 observed_task_manager()->GetPhysicalMemoryUsage(tasks_
[row
]), false);
461 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
462 return stringifier_
.GetProcessIdText(
463 observed_task_manager()->GetProcessId(tasks_
[row
]));
465 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
: {
467 observed_task_manager()->GetGDIHandles(tasks_
[row
], ¤t
, &peak
);
468 return stringifier_
.GetWindowsHandlesText(current
, peak
);
471 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
: {
473 observed_task_manager()->GetUSERHandles(tasks_
[row
], ¤t
, &peak
);
474 return stringifier_
.GetWindowsHandlesText(current
, peak
);
477 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
478 return stringifier_
.GetIdleWakeupsText(
479 observed_task_manager()->GetIdleWakeupsPerSecond(tasks_
[row
]));
481 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
: {
482 blink::WebCache::ResourceTypeStats stats
;
483 if (observed_task_manager()->GetWebCacheStats(tasks_
[row
], &stats
))
484 return stringifier_
.GetWebCacheStatText(stats
.images
);
485 return stringifier_
.n_a_string();
488 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
: {
489 blink::WebCache::ResourceTypeStats stats
;
490 if (observed_task_manager()->GetWebCacheStats(tasks_
[row
], &stats
))
491 return stringifier_
.GetWebCacheStatText(stats
.scripts
);
492 return stringifier_
.n_a_string();
495 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
: {
496 blink::WebCache::ResourceTypeStats stats
;
497 if (observed_task_manager()->GetWebCacheStats(tasks_
[row
], &stats
))
498 return stringifier_
.GetWebCacheStatText(stats
.cssStyleSheets
);
499 return stringifier_
.n_a_string();
502 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
: {
503 bool has_duplicates
= false;
504 return stringifier_
.GetMemoryUsageText(
505 observed_task_manager()->GetGpuMemoryUsage(tasks_
[row
],
510 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
511 return stringifier_
.GetMemoryUsageText(
512 observed_task_manager()->GetSqliteMemoryUsed(tasks_
[row
]), false);
514 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
: {
515 int64 v8_allocated
, v8_used
;
516 if (observed_task_manager()->GetV8Memory(tasks_
[row
],
519 return stringifier_
.FormatAllocatedAndUsedMemory(v8_allocated
,
522 return stringifier_
.n_a_string();
525 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
526 return stringifier_
.GetNaClPortText(
527 observed_task_manager()->GetNaClDebugStubPort(tasks_
[row
]));
531 return base::string16();
535 gfx::ImageSkia
NewTaskManagerView::TableModel::GetIcon(int row
) {
536 return observed_task_manager()->GetIcon(tasks_
[row
]);
539 void NewTaskManagerView::TableModel::SetObserver(
540 ui::TableModelObserver
* observer
) {
541 table_model_observer_
= observer
;
544 int NewTaskManagerView::TableModel::CompareValues(int row1
,
548 case IDS_TASK_MANAGER_TASK_COLUMN
:
549 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
550 return ui::TableModel::CompareValues(row1
, row2
, column_id
);
552 case IDS_TASK_MANAGER_NET_COLUMN
:
554 observed_task_manager()->GetNetworkUsage(tasks_
[row1
]),
555 observed_task_manager()->GetNetworkUsage(tasks_
[row2
]));
557 case IDS_TASK_MANAGER_CPU_COLUMN
:
558 return ValueCompare(observed_task_manager()->GetCpuUsage(tasks_
[row1
]),
559 observed_task_manager()->GetCpuUsage(tasks_
[row2
]));
561 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
563 observed_task_manager()->GetPrivateMemoryUsage(tasks_
[row1
]),
564 observed_task_manager()->GetPrivateMemoryUsage(tasks_
[row2
]));
566 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
568 observed_task_manager()->GetSharedMemoryUsage(tasks_
[row1
]),
569 observed_task_manager()->GetSharedMemoryUsage(tasks_
[row2
]));
571 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
573 observed_task_manager()->GetPhysicalMemoryUsage(tasks_
[row1
]),
574 observed_task_manager()->GetPhysicalMemoryUsage(tasks_
[row2
]));
576 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
578 observed_task_manager()->GetNaClDebugStubPort(tasks_
[row1
]),
579 observed_task_manager()->GetNaClDebugStubPort(tasks_
[row2
]));
581 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
582 return ValueCompare(observed_task_manager()->GetProcessId(tasks_
[row1
]),
583 observed_task_manager()->GetProcessId(tasks_
[row2
]));
585 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
: {
586 int64 current1
, peak1
, current2
, peak2
;
587 observed_task_manager()->GetGDIHandles(tasks_
[row1
], ¤t1
, &peak1
);
588 observed_task_manager()->GetGDIHandles(tasks_
[row2
], ¤t2
, &peak2
);
589 return ValueCompare(current1
, current2
);
592 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
: {
593 int64 current1
, peak1
, current2
, peak2
;
594 observed_task_manager()->GetUSERHandles(tasks_
[row1
], ¤t1
, &peak1
);
595 observed_task_manager()->GetUSERHandles(tasks_
[row2
], ¤t2
, &peak2
);
596 return ValueCompare(current1
, current2
);
599 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
601 observed_task_manager()->GetIdleWakeupsPerSecond(tasks_
[row1
]),
602 observed_task_manager()->GetIdleWakeupsPerSecond(tasks_
[row2
]));
604 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
605 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
606 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
: {
607 blink::WebCache::ResourceTypeStats stats1
;
608 blink::WebCache::ResourceTypeStats stats2
;
609 bool row1_stats_valid
=
610 observed_task_manager()->GetWebCacheStats(tasks_
[row1
], &stats1
);
611 bool row2_stats_valid
=
612 observed_task_manager()->GetWebCacheStats(tasks_
[row2
], &stats2
);
613 if (!row1_stats_valid
|| !row2_stats_valid
)
614 return OrderUnavailableValue(row1_stats_valid
, row2_stats_valid
);
617 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
618 return ValueCompare(stats1
.images
.size
, stats2
.images
.size
);
619 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
620 return ValueCompare(stats1
.scripts
.size
, stats2
.scripts
.size
);
621 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
622 return ValueCompare(stats1
.cssStyleSheets
.size
,
623 stats2
.cssStyleSheets
.size
);
630 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
: {
633 observed_task_manager()->GetGpuMemoryUsage(tasks_
[row1
],
635 observed_task_manager()->GetGpuMemoryUsage(tasks_
[row2
],
639 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
: {
640 int64 allocated1
, allocated2
, used1
, used2
;
641 observed_task_manager()->GetV8Memory(tasks_
[row1
], &allocated1
, &used1
);
642 observed_task_manager()->GetV8Memory(tasks_
[row2
], &allocated2
, &used2
);
643 return ValueCompare(allocated1
, allocated2
);
646 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
648 observed_task_manager()->GetSqliteMemoryUsed(tasks_
[row1
]),
649 observed_task_manager()->GetSqliteMemoryUsed(tasks_
[row2
]));
657 void NewTaskManagerView::TableModel::GetGroupRange(int model_index
,
658 views::GroupRange
* range
) {
660 for ( ; i
>= 0; --i
) {
661 if (IsTaskFirstInGroup(i
))
668 range
->length
= observed_task_manager()->GetNumberOfTasksOnSameProcess(
669 tasks_
[model_index
]);
672 void NewTaskManagerView::TableModel::OnTaskAdded(TaskId id
) {
673 // For the table view scrollbar to behave correctly we must inform it that
674 // a new task has been added.
676 // We will get a newly sorted list from the task manager as opposed to just
677 // adding |id| to |tasks_| because we want to keep |tasks_| sorted by proc IDs
678 // and then by Task IDs.
679 tasks_
= observed_task_manager()->GetTaskIdsList();
680 if (table_model_observer_
)
681 table_model_observer_
->OnItemsAdded(RowCount() - 1, 1);
684 void NewTaskManagerView::TableModel::OnTaskToBeRemoved(TaskId id
) {
685 auto index
= std::find(tasks_
.begin(), tasks_
.end(), id
);
686 if (index
== tasks_
.end())
688 auto removed_index
= index
- tasks_
.begin();
690 if (table_model_observer_
)
691 table_model_observer_
->OnItemsRemoved(removed_index
, 1);
694 void NewTaskManagerView::TableModel::OnTasksRefreshed(
695 const TaskIdList
& task_ids
) {
700 void NewTaskManagerView::TableModel::StartUpdating() {
701 TaskManagerInterface::GetTaskManager()->AddObserver(this);
702 tasks_
= observed_task_manager()->GetTaskIdsList();
706 void NewTaskManagerView::TableModel::StopUpdating() {
707 observed_task_manager()->RemoveObserver(this);
710 void NewTaskManagerView::TableModel::ActivateTask(int row_index
) {
711 observed_task_manager()->ActivateTask(tasks_
[row_index
]);
714 void NewTaskManagerView::TableModel::KillTask(int row_index
) {
715 base::ProcessId proc_id
= observed_task_manager()->GetProcessId(
718 DCHECK_NE(proc_id
, base::GetCurrentProcId());
720 base::Process process
= base::Process::Open(proc_id
);
721 process
.Terminate(content::RESULT_CODE_KILLED
, false);
724 void NewTaskManagerView::TableModel::UpdateRefreshTypes(views::TableView
* table
,
727 bool new_visibility
= visibility
;
728 RefreshType type
= REFRESH_TYPE_NONE
;
730 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
731 case IDS_TASK_MANAGER_TASK_COLUMN
:
732 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
733 return; // The data is these columns do not change.
735 case IDS_TASK_MANAGER_NET_COLUMN
:
736 type
= REFRESH_TYPE_NETWORK_USAGE
;
739 case IDS_TASK_MANAGER_CPU_COLUMN
:
740 type
= REFRESH_TYPE_CPU
;
743 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
744 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
745 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
746 type
= REFRESH_TYPE_MEMORY
;
747 if (table
->IsColumnVisible(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
) ||
748 table
->IsColumnVisible(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
) ||
749 table
->IsColumnVisible(IDS_TASK_MANAGER_SHARED_MEM_COLUMN
)) {
750 new_visibility
= true;
754 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
:
755 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
:
756 type
= REFRESH_TYPE_HANDLES
;
757 if (table
->IsColumnVisible(IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
) ||
758 table
->IsColumnVisible(IDS_TASK_MANAGER_USER_HANDLES_COLUMN
)) {
759 new_visibility
= true;
763 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
764 type
= REFRESH_TYPE_IDLE_WAKEUPS
;
767 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
768 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
769 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
770 type
= REFRESH_TYPE_WEBCACHE_STATS
;
771 if (table
->IsColumnVisible(IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
) ||
772 table
->IsColumnVisible(
773 IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
) ||
774 table
->IsColumnVisible(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
)) {
775 new_visibility
= true;
779 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
780 type
= REFRESH_TYPE_GPU_MEMORY
;
783 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
784 type
= REFRESH_TYPE_SQLITE_MEMORY
;
787 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
788 type
= REFRESH_TYPE_V8_MEMORY
;
791 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
792 type
= REFRESH_TYPE_NACL
;
801 AddRefreshType(type
);
803 RemoveRefreshType(type
);
806 bool NewTaskManagerView::TableModel::IsBrowserProcess(int row_index
) const {
807 return observed_task_manager()->GetProcessId(tasks_
[row_index
]) ==
808 base::GetCurrentProcId();
811 void NewTaskManagerView::TableModel::OnRefresh() {
812 if (table_model_observer_
)
813 table_model_observer_
->OnItemsChanged(0, RowCount());
816 bool NewTaskManagerView::TableModel::IsTaskFirstInGroup(int row_index
) const {
820 return observed_task_manager()->GetProcessId(tasks_
[row_index
- 1]) !=
821 observed_task_manager()->GetProcessId(tasks_
[row_index
]);
824 ////////////////////////////////////////////////////////////////////////////////
825 // NewTaskManagerView Implementation:
826 ////////////////////////////////////////////////////////////////////////////////
828 NewTaskManagerView::~NewTaskManagerView() {
829 // Delete child views now, while our table model still exists.
830 RemoveAllChildViews(true);
834 void NewTaskManagerView::Show(Browser
* browser
) {
835 if (g_task_manager_view
) {
836 // If there's a Task manager window open already, just activate it.
837 g_task_manager_view
->GetWidget()->Activate();
841 // In ash we can come here through the ChromeShellDelegate. If there is no
842 // browser window at that time of the call, browser could be passed as NULL.
843 const chrome::HostDesktopType desktop_type
=
844 browser
? browser
->host_desktop_type() : chrome::HOST_DESKTOP_TYPE_ASH
;
846 g_task_manager_view
= new NewTaskManagerView(desktop_type
);
848 gfx::NativeWindow window
= browser
? browser
->window()->GetNativeWindow()
852 window
= ash::wm::GetActiveWindow();
855 DialogDelegate::CreateDialogWidget(g_task_manager_view
,
858 g_task_manager_view
->InitAlwaysOnTopState();
859 g_task_manager_view
->table_model_
->StartUpdating();
862 // Set the app id for the task manager to the app id of its parent browser. If
863 // no parent is specified, the app id will default to that of the initial
866 ui::win::SetAppIdForWindow(
867 ShellIntegration::GetChromiumModelIdForProfile(
868 browser
->profile()->GetPath()),
869 views::HWNDForWidget(g_task_manager_view
->GetWidget()));
873 g_task_manager_view
->GetWidget()->Show();
875 // Set the initial focus to the list of tasks.
876 views::FocusManager
* focus_manager
=
877 g_task_manager_view
->GetFocusManager();
879 focus_manager
->SetFocusedView(g_task_manager_view
->tab_table_
);
882 gfx::NativeWindow native_window
=
883 g_task_manager_view
->GetWidget()->GetNativeWindow();
884 ash::SetShelfItemDetailsForDialogWindow(native_window
,
885 IDR_ASH_SHELF_ICON_TASK_MANAGER
,
886 native_window
->title());
891 void NewTaskManagerView::Hide() {
892 if (g_task_manager_view
)
893 g_task_manager_view
->GetWidget()->Close();
896 void NewTaskManagerView::Layout() {
897 gfx::Size size
= kill_button_
->GetPreferredSize();
898 gfx::Rect parent_bounds
= parent()->GetContentsBounds();
899 const int horizontal_margin
= views::kPanelHorizMargin
;
900 const int vertical_margin
= views::kButtonVEdgeMargin
;
901 int x
= width() - size
.width() - horizontal_margin
;
902 int y_buttons
= parent_bounds
.bottom() - size
.height() - vertical_margin
;
903 kill_button_
->SetBounds(x
, y_buttons
, size
.width(), size
.height());
905 size
= about_memory_link_
->GetPreferredSize();
906 about_memory_link_
->SetBounds(
908 y_buttons
+ (kill_button_
->height() - size
.height()) / 2,
909 size
.width(), size
.height());
911 gfx::Rect rect
= GetLocalBounds();
912 rect
.Inset(horizontal_margin
, views::kPanelVertMargin
);
914 kill_button_
->height() + views::kUnrelatedControlVerticalSpacing
);
915 tab_table_parent_
->SetBoundsRect(rect
);
918 gfx::Size
NewTaskManagerView::GetPreferredSize() const {
919 return gfx::Size(460, 270);
922 bool NewTaskManagerView::AcceleratorPressed(
923 const ui::Accelerator
& accelerator
) {
924 DCHECK_EQ(ui::VKEY_W
, accelerator
.key_code());
925 DCHECK_EQ(ui::EF_CONTROL_DOWN
, accelerator
.modifiers());
926 GetWidget()->Close();
930 void NewTaskManagerView::ViewHierarchyChanged(
931 const ViewHierarchyChangedDetails
& details
) {
932 views::DialogDelegateView::ViewHierarchyChanged(details
);
933 // Since we want the Kill button and the Memory Details link to show up in
934 // the same visual row as the close button, which is provided by the
935 // framework, we must add the buttons to the non-client view, which is the
936 // parent of this view. Similarly, when we're removed from the view
937 // hierarchy, we must take care to clean up those items as well.
938 if (details
.child
== this) {
939 if (details
.is_add
) {
940 details
.parent
->AddChildView(about_memory_link_
);
941 details
.parent
->AddChildView(kill_button_
);
942 tab_table_parent_
= tab_table_
->CreateParentIfNecessary();
943 AddChildView(tab_table_parent_
);
945 details
.parent
->RemoveChildView(kill_button_
);
946 details
.parent
->RemoveChildView(about_memory_link_
);
951 void NewTaskManagerView::ButtonPressed(views::Button
* sender
,
952 const ui::Event
& event
) {
953 DCHECK_EQ(kill_button_
, sender
);
955 using SelectedIndices
= ui::ListSelectionModel::SelectedIndices
;
956 SelectedIndices
selection(tab_table_
->selection_model().selected_indices());
957 for (SelectedIndices::const_reverse_iterator i
= selection
.rbegin();
958 i
!= selection
.rend();
960 table_model_
->KillTask(*i
);
964 bool NewTaskManagerView::CanResize() const {
968 bool NewTaskManagerView::CanMaximize() const {
972 bool NewTaskManagerView::CanMinimize() const {
976 bool NewTaskManagerView::ExecuteWindowsCommand(int command_id
) {
980 base::string16
NewTaskManagerView::GetWindowTitle() const {
981 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_TITLE
);
984 std::string
NewTaskManagerView::GetWindowName() const {
985 return prefs::kTaskManagerWindowPlacement
;
988 int NewTaskManagerView::GetDialogButtons() const {
989 return ui::DIALOG_BUTTON_NONE
;
992 void NewTaskManagerView::WindowClosing() {
993 // Now that the window is closed, we can allow a new one to be opened.
994 // (WindowClosing comes in asynchronously from the call to Close() and we
995 // may have already opened a new instance).
996 if (g_task_manager_view
== this) {
997 // We don't have to delete |g_task_manager_view| as we don't own it. It's
998 // owned by the Views hierarchy.
999 g_task_manager_view
= nullptr;
1001 StoreColumnsSettings();
1002 table_model_
->StopUpdating();
1005 bool NewTaskManagerView::UseNewStyleForThisDialog() const {
1009 void NewTaskManagerView::OnSelectionChanged() {
1010 const ui::ListSelectionModel::SelectedIndices
& selections(
1011 tab_table_
->selection_model().selected_indices());
1012 bool selection_contains_browser_process
= false;
1013 for (const auto& selection
: selections
) {
1014 if (table_model_
->IsBrowserProcess(selection
)) {
1015 selection_contains_browser_process
= true;
1020 kill_button_
->SetEnabled(!selection_contains_browser_process
&&
1021 !selections
.empty());
1024 void NewTaskManagerView::OnDoubleClick() {
1025 ActivateFocusedTab();
1028 void NewTaskManagerView::OnKeyDown(ui::KeyboardCode keycode
) {
1029 if (keycode
== ui::VKEY_RETURN
)
1030 ActivateFocusedTab();
1033 void NewTaskManagerView::LinkClicked(views::Link
* source
, int event_flags
) {
1034 DCHECK_EQ(about_memory_link_
, source
);
1035 OpenAboutMemory(desktop_type_
);
1038 void NewTaskManagerView::ShowContextMenuForView(
1039 views::View
* source
,
1040 const gfx::Point
& point
,
1041 ui::MenuSourceType source_type
) {
1042 ui::SimpleMenuModel
menu_model(this);
1044 for (const auto& table_column
: columns_
) {
1045 menu_model
.AddCheckItem(table_column
.id
,
1046 l10n_util::GetStringUTF16(table_column
.id
));
1050 new views::MenuRunner(&menu_model
, views::MenuRunner::CONTEXT_MENU
));
1052 if (menu_runner_
->RunMenuAt(GetWidget(),
1054 gfx::Rect(point
, gfx::Size()),
1055 views::MENU_ANCHOR_TOPLEFT
,
1056 source_type
) == views::MenuRunner::MENU_DELETED
) {
1061 bool NewTaskManagerView::IsCommandIdChecked(int id
) const {
1062 return tab_table_
->IsColumnVisible(id
);
1065 bool NewTaskManagerView::IsCommandIdEnabled(int id
) const {
1069 bool NewTaskManagerView::GetAcceleratorForCommandId(
1071 ui::Accelerator
* accelerator
) {
1075 void NewTaskManagerView::ExecuteCommand(int id
, int event_flags
) {
1076 ToggleColumnVisibility(id
);
1079 NewTaskManagerView::NewTaskManagerView(chrome::HostDesktopType desktop_type
)
1081 new NewTaskManagerView::TableModel(REFRESH_TYPE_CPU
|
1082 REFRESH_TYPE_MEMORY
|
1083 REFRESH_TYPE_NETWORK_USAGE
)),
1084 kill_button_(nullptr),
1085 about_memory_link_(nullptr),
1086 tab_table_(nullptr),
1087 tab_table_parent_(nullptr),
1088 desktop_type_(desktop_type
),
1089 is_always_on_top_(false) {
1094 NewTaskManagerView
* NewTaskManagerView::GetInstanceForTests() {
1095 return g_task_manager_view
;
1098 void NewTaskManagerView::Init() {
1099 columns_settings_
.reset(new base::DictionaryValue
);
1101 // Create the table columns.
1102 for (size_t i
= 0; i
< kColumnsSize
; ++i
) {
1103 const auto& col_data
= kColumns
[i
];
1104 columns_
.push_back(ui::TableColumn(col_data
.id
, col_data
.align
,
1105 col_data
.width
, col_data
.percent
));
1106 columns_
.back().sortable
= col_data
.sortable
;
1107 columns_
.back().initial_sort_is_ascending
=
1108 col_data
.initial_sort_is_ascending
;
1111 // Create the table view.
1112 tab_table_
= new views::TableView(
1113 table_model_
.get(), columns_
, views::ICON_AND_TEXT
, false);
1114 tab_table_
->SetGrouper(table_model_
.get());
1115 tab_table_
->SetObserver(this);
1116 tab_table_
->set_context_menu_controller(this);
1117 set_context_menu_controller(this);
1119 RetrieveSavedColumnsSettingsAndUpdateTable();
1121 kill_button_
= new views::LabelButton(this,
1122 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_KILL
));
1123 kill_button_
->SetStyle(views::Button::STYLE_BUTTON
);
1125 about_memory_link_
= new views::Link(
1126 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK
));
1127 about_memory_link_
->set_listener(this);
1129 // Makes sure our state is consistent.
1130 OnSelectionChanged();
1132 AddAccelerator(ui::Accelerator(ui::VKEY_W
, ui::EF_CONTROL_DOWN
));
1135 void NewTaskManagerView::InitAlwaysOnTopState() {
1136 RetriveSavedAlwaysOnTopState();
1137 GetWidget()->SetAlwaysOnTop(is_always_on_top_
);
1140 void NewTaskManagerView::ActivateFocusedTab() {
1141 const int active_row
= tab_table_
->selection_model().active();
1142 if (active_row
!= ui::ListSelectionModel::kUnselectedIndex
)
1143 table_model_
->ActivateTask(active_row
);
1146 void NewTaskManagerView::RetriveSavedAlwaysOnTopState() {
1147 is_always_on_top_
= false;
1149 if (!g_browser_process
->local_state())
1152 const base::DictionaryValue
* dictionary
=
1153 g_browser_process
->local_state()->GetDictionary(GetWindowName());
1155 dictionary
->GetBoolean("always_on_top", &is_always_on_top_
);
1158 void NewTaskManagerView::RetrieveSavedColumnsSettingsAndUpdateTable() {
1159 if (!g_browser_process
->local_state())
1162 const base::DictionaryValue
* dictionary
=
1163 g_browser_process
->local_state()->GetDictionary(
1164 prefs::kTaskManagerColumnVisibility
);
1168 // Do a best effort of retrieving the correct settings from the local state.
1169 // Use the default settings of the value if it fails to be retrieved.
1170 std::string sorted_col_id
;
1171 bool sort_is_ascending
= true;
1172 dictionary
->GetString(kSortColumnIdKey
, &sorted_col_id
);
1173 dictionary
->GetBoolean(kSortIsAscendingKey
, &sort_is_ascending
);
1175 int current_visible_column_index
= 0;
1176 for (size_t i
= 0; i
< kColumnsSize
; ++i
) {
1177 const int col_id
= kColumns
[i
].id
;
1178 const std::string
col_id_key(GetColumnIdAsString(col_id
));
1180 if (col_id_key
.empty())
1183 bool col_visibility
= kColumns
[i
].default_visibility
;
1184 dictionary
->GetBoolean(col_id_key
, &col_visibility
);
1186 // If the above GetBoolean() fails, the |col_visibility| remains at the
1187 // default visibility.
1188 columns_settings_
->SetBoolean(col_id_key
, col_visibility
);
1189 tab_table_
->SetColumnVisibility(col_id
, col_visibility
);
1190 table_model_
->UpdateRefreshTypes(tab_table_
, col_id
, col_visibility
);
1192 if (col_visibility
) {
1193 if (sorted_col_id
== col_id_key
) {
1194 if (sort_is_ascending
== kColumns
[i
].initial_sort_is_ascending
) {
1195 tab_table_
->ToggleSortOrder(current_visible_column_index
);
1197 // Unfortunately the API of ui::TableView doesn't provide a clean way
1198 // to sort by a particular column ID and a sort direction. If the
1199 // retrieved sort direction is different than the initial one, we have
1200 // to toggle the sort order twice!
1201 // Note that the function takes the visible_column_index rather than
1203 tab_table_
->ToggleSortOrder(current_visible_column_index
);
1204 tab_table_
->ToggleSortOrder(current_visible_column_index
);
1208 ++current_visible_column_index
;
1213 void NewTaskManagerView::StoreColumnsSettings() {
1214 PrefService
* local_state
= g_browser_process
->local_state();
1218 DictionaryPrefUpdate
dict_update(local_state
,
1219 prefs::kTaskManagerColumnVisibility
);
1221 base::DictionaryValue::Iterator
it(*columns_settings_
);
1222 while (!it
.IsAtEnd()) {
1223 dict_update
->Set(it
.key(), it
.value().CreateDeepCopy());
1227 // Store the current sort status to be restored again at startup.
1228 if (tab_table_
->sort_descriptors().empty()) {
1229 dict_update
->SetString(kSortColumnIdKey
, "");
1231 const auto& sort_descriptor
= tab_table_
->sort_descriptors().front();
1232 dict_update
->SetString(kSortColumnIdKey
,
1233 GetColumnIdAsString(sort_descriptor
.column_id
));
1234 dict_update
->SetBoolean(kSortIsAscendingKey
, sort_descriptor
.ascending
);
1238 void NewTaskManagerView::ToggleColumnVisibility(int column_id
) {
1239 bool new_visibility
= !tab_table_
->IsColumnVisible(column_id
);
1240 tab_table_
->SetColumnVisibility(column_id
, new_visibility
);
1241 columns_settings_
->SetBoolean(GetColumnIdAsString(column_id
), new_visibility
);
1242 table_model_
->UpdateRefreshTypes(tab_table_
, column_id
, new_visibility
);
1245 } // namespace task_management