OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/task_manager.h" | |
6 | |
7 #include "app/l10n_util.h" | |
8 #include "app/table_model_observer.h" | |
9 #include "base/stats_table.h" | |
10 #include "chrome/app/chrome_dll_resource.h" | |
11 #include "chrome/browser/browser_list.h" | |
12 #include "chrome/browser/browser_process.h" | |
13 #include "chrome/browser/browser_window.h" | |
14 #include "chrome/common/pref_names.h" | |
15 #include "chrome/common/pref_service.h" | |
16 #include "grit/chromium_strings.h" | |
17 #include "grit/generated_resources.h" | |
18 #include "grit/theme_resources.h" | |
19 #include "views/accelerator.h" | |
20 #include "views/background.h" | |
21 #include "views/controls/button/native_button.h" | |
22 #include "views/controls/link.h" | |
23 #include "views/controls/menu/menu.h" | |
24 #include "views/controls/table/group_table_view.h" | |
25 #include "views/controls/table/table_view_observer.h" | |
26 #include "views/standard_layout.h" | |
27 #include "views/widget/widget.h" | |
28 #include "views/window/dialog_delegate.h" | |
29 #include "views/window/window.h" | |
30 | |
31 // The task manager window default size. | |
32 static const int kDefaultWidth = 460; | |
33 static const int kDefaultHeight = 270; | |
34 | |
35 // An id for the most important column, made sufficiently large so as not to | |
36 // collide with anything else. | |
37 static const int64 kNuthMagicNumber = 1737350766; | |
38 static const int kBitMask = 0x7FFFFFFF; | |
39 static const int kGoatsTeleportedColumn = | |
40 (94024 * kNuthMagicNumber) & kBitMask; | |
41 | |
42 namespace { | |
43 | |
44 //////////////////////////////////////////////////////////////////////////////// | |
45 // TaskManagerTableModel class | |
46 //////////////////////////////////////////////////////////////////////////////// | |
47 | |
48 class TaskManagerTableModel : public views::GroupTableModel, | |
49 public TaskManagerModelObserver { | |
50 public: | |
51 explicit TaskManagerTableModel(TaskManagerModel* model) | |
52 : model_(model), | |
53 observer_(NULL) { | |
54 model->SetObserver(this); | |
55 } | |
56 ~TaskManagerTableModel() {} | |
57 | |
58 // GroupTableModel. | |
59 int RowCount(); | |
60 std::wstring GetText(int row, int column); | |
61 SkBitmap GetIcon(int row); | |
62 void GetGroupRangeForItem(int item, views::GroupRange* range); | |
63 void SetObserver(TableModelObserver* observer); | |
64 virtual int CompareValues(int row1, int row2, int column_id); | |
65 | |
66 // TaskManagerModelObserver. | |
67 virtual void OnModelChanged(); | |
68 virtual void OnItemsChanged(int start, int length); | |
69 virtual void OnItemsAdded(int start, int length); | |
70 virtual void OnItemsRemoved(int start, int length); | |
71 | |
72 private: | |
73 const TaskManagerModel* model_; | |
74 TableModelObserver* observer_; | |
75 }; | |
76 | |
77 int TaskManagerTableModel::RowCount() { | |
78 return model_->ResourceCount(); | |
79 } | |
80 | |
81 std::wstring TaskManagerTableModel::GetText(int row, int col_id) { | |
82 switch (col_id) { | |
83 case IDS_TASK_MANAGER_PAGE_COLUMN: // Process | |
84 return model_->GetResourceTitle(row); | |
85 | |
86 case IDS_TASK_MANAGER_NET_COLUMN: // Net | |
87 return model_->GetResourceNetworkUsage(row); | |
88 | |
89 case IDS_TASK_MANAGER_CPU_COLUMN: // CPU | |
90 if (!model_->IsResourceFirstInGroup(row)) | |
91 return std::wstring(); | |
92 return model_->GetResourceCPUUsage(row); | |
93 | |
94 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory | |
95 if (!model_->IsResourceFirstInGroup(row)) | |
96 return std::wstring(); | |
97 return model_->GetResourcePrivateMemory(row); | |
98 | |
99 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory | |
100 if (!model_->IsResourceFirstInGroup(row)) | |
101 return std::wstring(); | |
102 return model_->GetResourceSharedMemory(row); | |
103 | |
104 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory | |
105 if (!model_->IsResourceFirstInGroup(row)) | |
106 return std::wstring(); | |
107 return model_->GetResourcePhysicalMemory(row); | |
108 | |
109 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: | |
110 if (!model_->IsResourceFirstInGroup(row)) | |
111 return std::wstring(); | |
112 return model_->GetResourceProcessId(row); | |
113 | |
114 case kGoatsTeleportedColumn: // Goats Teleported! | |
115 return model_->GetResourceGoatsTeleported(row); | |
116 | |
117 default: | |
118 return model_->GetResourceStatsValue(row, col_id); | |
119 } | |
120 } | |
121 | |
122 SkBitmap TaskManagerTableModel::GetIcon(int row) { | |
123 return model_->GetResourceIcon(row); | |
124 } | |
125 | |
126 void TaskManagerTableModel::GetGroupRangeForItem(int item, | |
127 views::GroupRange* range) { | |
128 std::pair<int, int> range_pair = model_->GetGroupRangeForResource(item); | |
129 range->start = range_pair.first; | |
130 range->length = range_pair.second; | |
131 } | |
132 | |
133 void TaskManagerTableModel::SetObserver(TableModelObserver* observer) { | |
134 observer_ = observer; | |
135 } | |
136 | |
137 int TaskManagerTableModel::CompareValues(int row1, int row2, int column_id) { | |
138 return model_->CompareValues(row1, row2, column_id); | |
139 } | |
140 | |
141 void TaskManagerTableModel::OnModelChanged() { | |
142 if (observer_) | |
143 observer_->OnModelChanged(); | |
144 } | |
145 | |
146 void TaskManagerTableModel::OnItemsChanged(int start, int length) { | |
147 if (observer_) | |
148 observer_->OnItemsChanged(start, length); | |
149 } | |
150 | |
151 void TaskManagerTableModel::OnItemsAdded(int start, int length) { | |
152 if (observer_) | |
153 observer_->OnItemsAdded(start, length); | |
154 } | |
155 | |
156 void TaskManagerTableModel::OnItemsRemoved(int start, int length) { | |
157 if (observer_) | |
158 observer_->OnItemsRemoved(start, length); | |
159 } | |
160 | |
161 //////////////////////////////////////////////////////////////////////////////// | |
162 // TaskManagerViewImpl class | |
163 // | |
164 // The view containing the different widgets. | |
165 // | |
166 //////////////////////////////////////////////////////////////////////////////// | |
167 | |
168 class TaskManagerViewImpl : public TaskManagerView, | |
169 public views::View, | |
170 public views::ButtonListener, | |
171 public views::DialogDelegate, | |
172 public views::TableViewObserver, | |
173 public views::LinkController, | |
174 public views::ContextMenuController, | |
175 public views::Menu::Delegate { | |
176 public: | |
177 TaskManagerViewImpl(TaskManager* task_manager, | |
178 TaskManagerModel* model); | |
179 virtual ~TaskManagerViewImpl(); | |
180 | |
181 void Init(); | |
182 virtual void Layout(); | |
183 virtual gfx::Size GetPreferredSize(); | |
184 virtual void ViewHierarchyChanged(bool is_add, views::View* parent, | |
185 views::View* child); | |
186 | |
187 // TaskManagerView | |
188 virtual void GetSelection(std::vector<int>* selection); | |
189 virtual void GetFocused(std::vector<int>* focused); | |
190 virtual void OpenWindow(); | |
191 virtual void ActivateWindow(); | |
192 virtual void CloseWindow(); | |
193 | |
194 // ButtonListener implementation. | |
195 virtual void ButtonPressed(views::Button* sender); | |
196 | |
197 // views::DialogDelegate | |
198 virtual bool CanResize() const; | |
199 virtual bool CanMaximize() const; | |
200 virtual bool ExecuteWindowsCommand(int command_id); | |
201 virtual std::wstring GetWindowTitle() const; | |
202 virtual std::wstring GetWindowName() const; | |
203 virtual int GetDialogButtons() const; | |
204 virtual void WindowClosing(); | |
205 virtual void DeleteDelegate(); | |
206 virtual views::View* GetContentsView(); | |
207 | |
208 // views::TableViewObserver implementation. | |
209 virtual void OnSelectionChanged(); | |
210 virtual void OnDoubleClick(); | |
211 virtual void OnKeyDown(unsigned short virtual_keycode); | |
212 | |
213 // views::LinkController implementation. | |
214 virtual void LinkActivated(views::Link* source, int event_flags); | |
215 | |
216 // Called by the column picker to pick up any new stat counters that | |
217 // may have appeared since last time. | |
218 void UpdateStatsCounters(); | |
219 | |
220 // Menu::Delegate | |
221 virtual void ShowContextMenu(views::View* source, | |
222 int x, | |
223 int y, | |
224 bool is_mouse_gesture); | |
225 virtual bool IsItemChecked(int id) const; | |
226 virtual void ExecuteCommand(int id); | |
227 | |
228 private: | |
229 // Initializes the state of the always-on-top setting as the window is shown. | |
230 void InitAlwaysOnTopState(); | |
231 | |
232 // Adds an always on top item to the window's system menu. | |
233 void AddAlwaysOnTopSystemMenuItem(); | |
234 | |
235 // Restores saved always on top state from a previous session. | |
236 bool GetSavedAlwaysOnTopState(bool* always_on_top) const; | |
237 | |
238 views::NativeButton* kill_button_; | |
239 views::Link* about_memory_link_; | |
240 views::GroupTableView* tab_table_; | |
241 | |
242 TaskManager* task_manager_; | |
243 | |
244 TaskManagerModel* model_; | |
245 | |
246 // all possible columns, not necessarily visible | |
247 std::vector<TableColumn> columns_; | |
248 | |
249 scoped_ptr<TaskManagerTableModel> table_model_; | |
250 | |
251 // True when the Task Manager window should be shown on top of other windows. | |
252 bool is_always_on_top_; | |
253 | |
254 // We need to own the text of the menu, the Windows API does not copy it. | |
255 std::wstring always_on_top_menu_text_; | |
256 | |
257 DISALLOW_COPY_AND_ASSIGN(TaskManagerViewImpl); | |
258 }; | |
259 | |
260 TaskManagerViewImpl::TaskManagerViewImpl(TaskManager* task_manager, | |
261 TaskManagerModel* model) | |
262 : task_manager_(task_manager), | |
263 model_(model), | |
264 is_always_on_top_(false) { | |
265 Init(); | |
266 } | |
267 | |
268 TaskManagerViewImpl::~TaskManagerViewImpl() { | |
269 // Delete child views now, while our table model still exists. | |
270 RemoveAllChildViews(true); | |
271 | |
272 // Prevent the table from accessing the model as part of its destruction, as | |
273 // the model might already be destroyed. | |
274 tab_table_->SetModel(NULL); | |
275 } | |
276 | |
277 void TaskManagerViewImpl::Init() { | |
278 table_model_.reset(new TaskManagerTableModel(model_)); | |
279 | |
280 columns_.push_back(TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, | |
281 TableColumn::LEFT, -1, 1)); | |
282 columns_.back().sortable = true; | |
283 columns_.push_back(TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, | |
284 TableColumn::RIGHT, -1, 0)); | |
285 columns_.back().sortable = true; | |
286 columns_.push_back(TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, | |
287 TableColumn::RIGHT, -1, 0)); | |
288 columns_.back().sortable = true; | |
289 columns_.push_back(TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, | |
290 TableColumn::RIGHT, -1, 0)); | |
291 columns_.back().sortable = true; | |
292 columns_.push_back(TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, | |
293 TableColumn::RIGHT, -1, 0)); | |
294 columns_.back().sortable = true; | |
295 columns_.push_back(TableColumn(IDS_TASK_MANAGER_NET_COLUMN, | |
296 TableColumn::RIGHT, -1, 0)); | |
297 columns_.back().sortable = true; | |
298 columns_.push_back(TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, | |
299 TableColumn::RIGHT, -1, 0)); | |
300 columns_.back().sortable = true; | |
301 | |
302 tab_table_ = new views::GroupTableView(table_model_.get(), columns_, | |
303 views::ICON_AND_TEXT, false, true, | |
304 true); | |
305 tab_table_->SetParentOwned(false); | |
306 | |
307 // Hide some columns by default | |
308 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, false); | |
309 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, false); | |
310 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, false); | |
311 | |
312 UpdateStatsCounters(); | |
313 TableColumn col(kGoatsTeleportedColumn, L"Goats Teleported", | |
314 TableColumn::RIGHT, -1, 0); | |
315 col.sortable = true; | |
316 columns_.push_back(col); | |
317 tab_table_->AddColumn(col); | |
318 tab_table_->SetObserver(this); | |
319 SetContextMenuController(this); | |
320 kill_button_ = new views::NativeButton( | |
321 this, l10n_util::GetString(IDS_TASK_MANAGER_KILL)); | |
322 kill_button_->AddAccelerator(views::Accelerator('E', false, false, false)); | |
323 kill_button_->SetAccessibleKeyboardShortcut(L"E"); | |
324 about_memory_link_ = new views::Link( | |
325 l10n_util::GetString(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK)); | |
326 about_memory_link_->SetController(this); | |
327 | |
328 // Makes sure our state is consistent. | |
329 OnSelectionChanged(); | |
330 } | |
331 | |
332 void TaskManagerViewImpl::UpdateStatsCounters() { | |
333 StatsTable* stats = StatsTable::current(); | |
334 if (stats != NULL) { | |
335 int max = stats->GetMaxCounters(); | |
336 // skip the first row (it's header data) | |
337 for (int i = 1; i < max; i++) { | |
338 const char* row = stats->GetRowName(i); | |
339 if (row != NULL && row[0] != '\0' && !tab_table_->HasColumn(i)) { | |
340 // TODO(erikkay): Use l10n to get display names for stats. Right | |
341 // now we're just displaying the internal counter name. Perhaps | |
342 // stat names not in the string table would be filtered out. | |
343 // TODO(erikkay): Width is hard-coded right now, so many column | |
344 // names are clipped. | |
345 TableColumn col(i, ASCIIToWide(row), TableColumn::RIGHT, 90, 0); | |
346 col.sortable = true; | |
347 columns_.push_back(col); | |
348 tab_table_->AddColumn(col); | |
349 } | |
350 } | |
351 } | |
352 } | |
353 | |
354 void TaskManagerViewImpl::ViewHierarchyChanged(bool is_add, | |
355 views::View* parent, | |
356 views::View* child) { | |
357 // Since we want the Kill button and the Memory Details link to show up in | |
358 // the same visual row as the close button, which is provided by the | |
359 // framework, we must add the buttons to the non-client view, which is the | |
360 // parent of this view. Similarly, when we're removed from the view | |
361 // hierarchy, we must take care to clean up those items as well. | |
362 if (child == this) { | |
363 if (is_add) { | |
364 parent->AddChildView(kill_button_); | |
365 parent->AddChildView(about_memory_link_); | |
366 AddChildView(tab_table_); | |
367 } else { | |
368 parent->RemoveChildView(kill_button_); | |
369 parent->RemoveChildView(about_memory_link_); | |
370 } | |
371 } | |
372 } | |
373 | |
374 void TaskManagerViewImpl::Layout() { | |
375 // kPanelHorizMargin is too big. | |
376 const int kTableButtonSpacing = 12; | |
377 | |
378 gfx::Size size = kill_button_->GetPreferredSize(); | |
379 int prefered_width = size.width(); | |
380 int prefered_height = size.height(); | |
381 | |
382 tab_table_->SetBounds(x() + kPanelHorizMargin, | |
383 y() + kPanelVertMargin, | |
384 width() - 2 * kPanelHorizMargin, | |
385 height() - 2 * kPanelVertMargin - prefered_height); | |
386 | |
387 // y-coordinate of button top left. | |
388 gfx::Rect parent_bounds = GetParent()->GetLocalBounds(false); | |
389 int y_buttons = parent_bounds.bottom() - prefered_height - kButtonVEdgeMargin; | |
390 | |
391 kill_button_->SetBounds(x() + width() - prefered_width - kPanelHorizMargin, | |
392 y_buttons, | |
393 prefered_width, | |
394 prefered_height); | |
395 | |
396 size = about_memory_link_->GetPreferredSize(); | |
397 int link_prefered_width = size.width(); | |
398 int link_prefered_height = size.height(); | |
399 // center between the two buttons horizontally, and line up with | |
400 // bottom of buttons vertically. | |
401 int link_y_offset = std::max(0, prefered_height - link_prefered_height) / 2; | |
402 about_memory_link_->SetBounds( | |
403 x() + kPanelHorizMargin, | |
404 y_buttons + prefered_height - link_prefered_height - link_y_offset, | |
405 link_prefered_width, | |
406 link_prefered_height); | |
407 } | |
408 | |
409 gfx::Size TaskManagerViewImpl::GetPreferredSize() { | |
410 return gfx::Size(kDefaultWidth, kDefaultHeight); | |
411 } | |
412 | |
413 void TaskManagerViewImpl::GetSelection(std::vector<int>* selection) { | |
414 DCHECK(selection); | |
415 for (views::TableSelectionIterator iter = tab_table_->SelectionBegin(); | |
416 iter != tab_table_->SelectionEnd(); ++iter) { | |
417 // The TableView returns the selection starting from the end. | |
418 selection->insert(selection->begin(), *iter); | |
419 } | |
420 } | |
421 | |
422 void TaskManagerViewImpl::GetFocused(std::vector<int>* focused) { | |
423 DCHECK(focused); | |
424 int row_count = tab_table_->RowCount(); | |
425 for (int i = 0; i < row_count; ++i) { | |
426 // The TableView returns the selection starting from the end. | |
427 if (tab_table_->ItemHasTheFocus(i)) | |
428 focused->insert(focused->begin(), i); | |
429 } | |
430 } | |
431 | |
432 void TaskManagerViewImpl::OpenWindow() { | |
433 DCHECK(!window()); | |
434 views::Window::CreateChromeWindow(NULL, gfx::Rect(), this); | |
435 InitAlwaysOnTopState(); | |
436 model_->StartUpdating(); | |
437 window()->Show(); | |
438 } | |
439 | |
440 void TaskManagerViewImpl::ActivateWindow() { | |
441 DCHECK(window()); | |
442 window()->Activate(); | |
443 } | |
444 | |
445 void TaskManagerViewImpl::CloseWindow() { | |
446 if (!window()) | |
447 return; | |
448 // TODO(phajdan.jr): Destroy the window, not just hide it. | |
449 window()->HideWindow(); | |
450 } | |
451 | |
452 // ButtonListener implementation. | |
453 void TaskManagerViewImpl::ButtonPressed(views::Button* sender) { | |
454 if (sender == kill_button_) | |
455 task_manager_->KillSelectedProcesses(); | |
456 } | |
457 | |
458 // DialogDelegate implementation. | |
459 bool TaskManagerViewImpl::CanResize() const { | |
460 return true; | |
461 } | |
462 | |
463 bool TaskManagerViewImpl::CanMaximize() const { | |
464 return true; | |
465 } | |
466 | |
467 bool TaskManagerViewImpl::ExecuteWindowsCommand(int command_id) { | |
468 if (command_id == IDC_ALWAYS_ON_TOP) { | |
469 is_always_on_top_ = !is_always_on_top_; | |
470 | |
471 // Change the menu check state. | |
472 HMENU system_menu = GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); | |
473 MENUITEMINFO menu_info; | |
474 memset(&menu_info, 0, sizeof(MENUITEMINFO)); | |
475 menu_info.cbSize = sizeof(MENUITEMINFO); | |
476 BOOL r = GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, | |
477 FALSE, &menu_info); | |
478 DCHECK(r); | |
479 menu_info.fMask = MIIM_STATE; | |
480 if (is_always_on_top_) | |
481 menu_info.fState = MFS_CHECKED; | |
482 r = SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info); | |
483 | |
484 // Now change the actual window's behavior. | |
485 window()->SetIsAlwaysOnTop(is_always_on_top_); | |
486 | |
487 // Save the state. | |
488 if (g_browser_process->local_state()) { | |
489 DictionaryValue* window_preferences = | |
490 g_browser_process->local_state()->GetMutableDictionary( | |
491 GetWindowName().c_str()); | |
492 window_preferences->SetBoolean(L"always_on_top", is_always_on_top_); | |
493 } | |
494 return true; | |
495 } | |
496 return false; | |
497 } | |
498 | |
499 std::wstring TaskManagerViewImpl::GetWindowTitle() const { | |
500 return l10n_util::GetString(IDS_TASK_MANAGER_TITLE); | |
501 } | |
502 | |
503 std::wstring TaskManagerViewImpl::GetWindowName() const { | |
504 return prefs::kTaskManagerWindowPlacement; | |
505 } | |
506 | |
507 int TaskManagerViewImpl::GetDialogButtons() const { | |
508 return MessageBoxFlags::DIALOGBUTTON_NONE; | |
509 } | |
510 | |
511 void TaskManagerViewImpl::WindowClosing() { | |
512 task_manager_->OnWindowClosed(); | |
513 } | |
514 | |
515 void TaskManagerViewImpl::DeleteDelegate() { | |
516 ReleaseWindow(); | |
517 } | |
518 | |
519 views::View* TaskManagerViewImpl::GetContentsView() { | |
520 return this; | |
521 } | |
522 | |
523 // views::TableViewObserver implementation. | |
524 void TaskManagerViewImpl::OnSelectionChanged() { | |
525 kill_button_->SetEnabled(!task_manager_->BrowserProcessIsSelected() && | |
526 tab_table_->SelectedRowCount() > 0); | |
527 } | |
528 | |
529 void TaskManagerViewImpl::OnDoubleClick() { | |
530 task_manager_->ActivateFocusedTab(); | |
531 } | |
532 | |
533 void TaskManagerViewImpl::OnKeyDown(unsigned short virtual_keycode) { | |
534 if (virtual_keycode == VK_RETURN) | |
535 task_manager_->ActivateFocusedTab(); | |
536 } | |
537 | |
538 // views::LinkController implementation | |
539 void TaskManagerViewImpl::LinkActivated(views::Link* source, | |
540 int event_flags) { | |
541 DCHECK(source == about_memory_link_); | |
542 Browser* browser = BrowserList::GetLastActive(); | |
543 DCHECK(browser); | |
544 browser->OpenURL(GURL("about:memory"), GURL(), NEW_FOREGROUND_TAB, | |
545 PageTransition::LINK); | |
546 // In case the browser window is minimzed, show it. If this is an application | |
547 // or popup, we can only have one tab, hence we need to process this in a | |
548 // tabbed browser window. Currently, |browser| is pointing to the application, | |
549 // popup window. Therefore, we have to retrieve the last active tab again, | |
550 // since a new window has been used. | |
551 if (browser->type() & Browser::TYPE_APP_POPUP) { | |
552 browser = BrowserList::GetLastActive(); | |
553 DCHECK(browser); | |
554 } | |
555 browser->window()->Show(); | |
556 } | |
557 | |
558 void TaskManagerViewImpl::ShowContextMenu(views::View* source, | |
559 int x, | |
560 int y, | |
561 bool is_mouse_gesture) { | |
562 UpdateStatsCounters(); | |
563 scoped_ptr<views::Menu> menu(views::Menu::Create( | |
564 this, views::Menu::TOPLEFT, source->GetWidget()->GetNativeView())); | |
565 for (std::vector<TableColumn>::iterator i = | |
566 columns_.begin(); i != columns_.end(); ++i) { | |
567 menu->AppendMenuItem(i->id, i->title, views::Menu::CHECKBOX); | |
568 } | |
569 menu->RunMenuAt(x, y); | |
570 } | |
571 | |
572 bool TaskManagerViewImpl::IsItemChecked(int id) const { | |
573 return tab_table_->IsColumnVisible(id); | |
574 } | |
575 | |
576 void TaskManagerViewImpl::ExecuteCommand(int id) { | |
577 tab_table_->SetColumnVisibility(id, !tab_table_->IsColumnVisible(id)); | |
578 } | |
579 | |
580 void TaskManagerViewImpl::InitAlwaysOnTopState() { | |
581 is_always_on_top_ = false; | |
582 if (GetSavedAlwaysOnTopState(&is_always_on_top_)) | |
583 window()->SetIsAlwaysOnTop(is_always_on_top_); | |
584 AddAlwaysOnTopSystemMenuItem(); | |
585 } | |
586 | |
587 void TaskManagerViewImpl::AddAlwaysOnTopSystemMenuItem() { | |
588 // The Win32 API requires that we own the text. | |
589 always_on_top_menu_text_ = l10n_util::GetString(IDS_ALWAYS_ON_TOP); | |
590 | |
591 // Let's insert a menu to the window. | |
592 HMENU system_menu = ::GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); | |
593 int index = ::GetMenuItemCount(system_menu) - 1; | |
594 if (index < 0) { | |
595 // Paranoia check. | |
596 NOTREACHED(); | |
597 index = 0; | |
598 } | |
599 // First we add the separator. | |
600 MENUITEMINFO menu_info; | |
601 memset(&menu_info, 0, sizeof(MENUITEMINFO)); | |
602 menu_info.cbSize = sizeof(MENUITEMINFO); | |
603 menu_info.fMask = MIIM_FTYPE; | |
604 menu_info.fType = MFT_SEPARATOR; | |
605 ::InsertMenuItem(system_menu, index, TRUE, &menu_info); | |
606 | |
607 // Then the actual menu. | |
608 menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE; | |
609 menu_info.fType = MFT_STRING; | |
610 menu_info.fState = MFS_ENABLED; | |
611 if (is_always_on_top_) | |
612 menu_info.fState |= MFS_CHECKED; | |
613 menu_info.wID = IDC_ALWAYS_ON_TOP; | |
614 menu_info.dwTypeData = const_cast<wchar_t*>(always_on_top_menu_text_.c_str()); | |
615 ::InsertMenuItem(system_menu, index, TRUE, &menu_info); | |
616 } | |
617 | |
618 bool TaskManagerViewImpl::GetSavedAlwaysOnTopState(bool* always_on_top) const { | |
619 if (!g_browser_process->local_state()) | |
620 return false; | |
621 | |
622 const DictionaryValue* dictionary = | |
623 g_browser_process->local_state()->GetDictionary(GetWindowName().c_str()); | |
624 return dictionary && | |
625 dictionary->GetBoolean(L"always_on_top", always_on_top) && always_on_top; | |
626 } | |
627 | |
628 } // namespace | |
629 | |
630 void TaskManager::CreateView() { | |
631 DCHECK(!view_); | |
632 view_ = new TaskManagerViewImpl(this, model_.get()); | |
633 } | |
OLD | NEW |