task_manager_view.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/task_manager/task_manager.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/metrics/stats_table.h" 923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/prefs/pref_service.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/app/chrome_command_ids.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/ui/views/browser_dialogs.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/grit/chromium_strings.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/grit/generated_resources.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accelerators/accelerator.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/simple_menu_model.h" 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/models/table_model.h" 2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "ui/base/models/table_model_observer.h" 2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "ui/events/event_constants.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/events/keycodes/keyboard_codes.h" 2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/gfx/canvas.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/context_menu_controller.h" 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/views/controls/button/label_button.h" 32#include "ui/views/controls/link.h" 33#include "ui/views/controls/link_listener.h" 34#include "ui/views/controls/menu/menu_runner.h" 35#include "ui/views/controls/table/table_grouper.h" 36#include "ui/views/controls/table/table_view.h" 37#include "ui/views/controls/table/table_view_observer.h" 38#include "ui/views/layout/layout_constants.h" 39#include "ui/views/widget/widget.h" 40#include "ui/views/window/dialog_delegate.h" 41 42#if defined(USE_ASH) 43#include "ash/shelf/shelf_util.h" 44#include "ash/wm/window_util.h" 45#include "grit/ash_resources.h" 46#endif 47 48#if defined(OS_WIN) 49#include "chrome/browser/shell_integration.h" 50#include "ui/base/win/shell.h" 51#include "ui/views/win/hwnd_util.h" 52#endif 53 54namespace { 55 56//////////////////////////////////////////////////////////////////////////////// 57// TaskManagerTableModel class 58//////////////////////////////////////////////////////////////////////////////// 59 60class TaskManagerTableModel 61 : public ui::TableModel, 62 public views::TableGrouper, 63 public TaskManagerModelObserver { 64 public: 65 explicit TaskManagerTableModel(TaskManagerModel* model) 66 : model_(model), 67 observer_(NULL) { 68 model_->AddObserver(this); 69 } 70 71 virtual ~TaskManagerTableModel() { 72 model_->RemoveObserver(this); 73 } 74 75 // TableModel overrides: 76 virtual int RowCount() OVERRIDE; 77 virtual base::string16 GetText(int row, int column) OVERRIDE; 78 virtual gfx::ImageSkia GetIcon(int row) OVERRIDE; 79 virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE; 80 virtual int CompareValues(int row1, int row2, int column_id) OVERRIDE; 81 82 // TableGrouper overrides: 83 virtual void GetGroupRange(int model_index, 84 views::GroupRange* range) OVERRIDE; 85 86 // TaskManagerModelObserver overrides: 87 virtual void OnModelChanged() OVERRIDE; 88 virtual void OnItemsChanged(int start, int length) OVERRIDE; 89 virtual void OnItemsAdded(int start, int length) OVERRIDE; 90 virtual void OnItemsRemoved(int start, int length) OVERRIDE; 91 92 private: 93 TaskManagerModel* model_; 94 ui::TableModelObserver* observer_; 95 96 DISALLOW_COPY_AND_ASSIGN(TaskManagerTableModel); 97}; 98 99int TaskManagerTableModel::RowCount() { 100 return model_->ResourceCount(); 101} 102 103base::string16 TaskManagerTableModel::GetText(int row, int col_id) { 104 return model_->GetResourceById(row, col_id); 105} 106 107gfx::ImageSkia TaskManagerTableModel::GetIcon(int row) { 108 return model_->GetResourceIcon(row); 109} 110 111void TaskManagerTableModel::SetObserver(ui::TableModelObserver* observer) { 112 observer_ = observer; 113} 114 115int TaskManagerTableModel::CompareValues(int row1, int row2, int column_id) { 116 return model_->CompareValues(row1, row2, column_id); 117} 118 119void TaskManagerTableModel::GetGroupRange(int model_index, 120 views::GroupRange* range) { 121 TaskManagerModel::GroupRange range_pair = 122 model_->GetGroupRangeForResource(model_index); 123 range->start = range_pair.first; 124 range->length = range_pair.second; 125} 126 127void TaskManagerTableModel::OnModelChanged() { 128 if (observer_) 129 observer_->OnModelChanged(); 130} 131 132void TaskManagerTableModel::OnItemsChanged(int start, int length) { 133 if (observer_) 134 observer_->OnItemsChanged(start, length); 135} 136 137void TaskManagerTableModel::OnItemsAdded(int start, int length) { 138 if (observer_) 139 observer_->OnItemsAdded(start, length); 140} 141 142void TaskManagerTableModel::OnItemsRemoved(int start, int length) { 143 if (observer_) 144 observer_->OnItemsRemoved(start, length); 145} 146 147// The Task manager UI container. 148class TaskManagerView : public views::ButtonListener, 149 public views::DialogDelegateView, 150 public views::TableViewObserver, 151 public views::LinkListener, 152 public views::ContextMenuController, 153 public ui::SimpleMenuModel::Delegate { 154 public: 155 explicit TaskManagerView(chrome::HostDesktopType desktop_type); 156 virtual ~TaskManagerView(); 157 158 // Shows the Task manager window, or re-activates an existing one. 159 static void Show(Browser* browser); 160 161 // views::View: 162 virtual void Layout() OVERRIDE; 163 virtual gfx::Size GetPreferredSize() const OVERRIDE; 164 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; 165 virtual void ViewHierarchyChanged( 166 const ViewHierarchyChangedDetails& details) OVERRIDE; 167 168 // views::ButtonListener: 169 virtual void ButtonPressed(views::Button* sender, 170 const ui::Event& event) OVERRIDE; 171 172 // views::DialogDelegateView: 173 virtual bool CanResize() const OVERRIDE; 174 virtual bool CanMaximize() const OVERRIDE; 175 virtual bool CanMinimize() const OVERRIDE; 176 virtual bool ExecuteWindowsCommand(int command_id) OVERRIDE; 177 virtual base::string16 GetWindowTitle() const OVERRIDE; 178 virtual std::string GetWindowName() const OVERRIDE; 179 virtual int GetDialogButtons() const OVERRIDE; 180 virtual void WindowClosing() OVERRIDE; 181 virtual bool UseNewStyleForThisDialog() const OVERRIDE; 182 183 // views::TableViewObserver: 184 virtual void OnSelectionChanged() OVERRIDE; 185 virtual void OnDoubleClick() OVERRIDE; 186 virtual void OnKeyDown(ui::KeyboardCode keycode) OVERRIDE; 187 188 // views::LinkListener: 189 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 190 191 // Called by the column picker to pick up any new stat counters that 192 // may have appeared since last time. 193 void UpdateStatsCounters(); 194 195 // views::ContextMenuController: 196 virtual void ShowContextMenuForView(views::View* source, 197 const gfx::Point& point, 198 ui::MenuSourceType source_type) OVERRIDE; 199 200 // ui::SimpleMenuModel::Delegate: 201 virtual bool IsCommandIdChecked(int id) const OVERRIDE; 202 virtual bool IsCommandIdEnabled(int id) const OVERRIDE; 203 virtual bool GetAcceleratorForCommandId( 204 int command_id, 205 ui::Accelerator* accelerator) OVERRIDE; 206 virtual void ExecuteCommand(int id, int event_flags) OVERRIDE; 207 208 private: 209 // Creates the child controls. 210 void Init(); 211 212 // Initializes the state of the always-on-top setting as the window is shown. 213 void InitAlwaysOnTopState(); 214 215 // Activates the tab associated with the focused row. 216 void ActivateFocusedTab(); 217 218 // Restores saved always on top state from a previous session. 219 bool GetSavedAlwaysOnTopState(bool* always_on_top) const; 220 221 views::LabelButton* kill_button_; 222 views::Link* about_memory_link_; 223 views::TableView* tab_table_; 224 views::View* tab_table_parent_; 225 226 TaskManager* task_manager_; 227 228 TaskManagerModel* model_; 229 230 // all possible columns, not necessarily visible 231 std::vector<ui::TableColumn> columns_; 232 233 scoped_ptr<TaskManagerTableModel> table_model_; 234 235 // True when the Task Manager window should be shown on top of other windows. 236 bool is_always_on_top_; 237 238 // The host desktop type this task manager belongs to. 239 const chrome::HostDesktopType desktop_type_; 240 241 // We need to own the text of the menu, the Windows API does not copy it. 242 base::string16 always_on_top_menu_text_; 243 244 // An open Task manager window. There can only be one open at a time. This 245 // is reset to NULL when the window is closed. 246 static TaskManagerView* instance_; 247 248 scoped_ptr<views::MenuRunner> menu_runner_; 249 250 DISALLOW_COPY_AND_ASSIGN(TaskManagerView); 251}; 252 253// static 254TaskManagerView* TaskManagerView::instance_ = NULL; 255 256 257TaskManagerView::TaskManagerView(chrome::HostDesktopType desktop_type) 258 : kill_button_(NULL), 259 about_memory_link_(NULL), 260 tab_table_(NULL), 261 tab_table_parent_(NULL), 262 task_manager_(TaskManager::GetInstance()), 263 model_(TaskManager::GetInstance()->model()), 264 is_always_on_top_(false), 265 desktop_type_(desktop_type) { 266 Init(); 267} 268 269TaskManagerView::~TaskManagerView() { 270 // Delete child views now, while our table model still exists. 271 RemoveAllChildViews(true); 272} 273 274void TaskManagerView::Init() { 275 table_model_.reset(new TaskManagerTableModel(model_)); 276 277 // Page column has no header label. 278 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_TASK_COLUMN, 279 ui::TableColumn::LEFT, -1, 1)); 280 columns_.back().sortable = true; 281 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PROFILE_NAME_COLUMN, 282 ui::TableColumn::LEFT, -1, 0)); 283 columns_.back().sortable = true; 284 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, 285 ui::TableColumn::RIGHT, -1, 0)); 286 columns_.back().sortable = true; 287 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, 288 ui::TableColumn::RIGHT, -1, 0)); 289 columns_.back().sortable = true; 290 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, 291 ui::TableColumn::RIGHT, -1, 0)); 292 columns_.back().sortable = true; 293 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, 294 ui::TableColumn::RIGHT, -1, 0)); 295 columns_.back().sortable = true; 296 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_NET_COLUMN, 297 ui::TableColumn::RIGHT, -1, 0)); 298 columns_.back().sortable = true; 299 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, 300 ui::TableColumn::RIGHT, -1, 0)); 301 columns_.back().sortable = true; 302#if defined(OS_WIN) 303 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_GDI_HANDLES_COLUMN, 304 ui::TableColumn::RIGHT, -1, 0)); 305 columns_.back().sortable = true; 306 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_USER_HANDLES_COLUMN, 307 ui::TableColumn::RIGHT, -1, 0)); 308 columns_.back().sortable = true; 309#endif 310 columns_.push_back(ui::TableColumn( 311 IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN, 312 ui::TableColumn::RIGHT, -1, 0)); 313 columns_.back().sortable = true; 314 columns_.push_back(ui::TableColumn( 315 IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN, 316 ui::TableColumn::RIGHT, -1, 0)); 317 columns_.back().sortable = true; 318 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, 319 ui::TableColumn::RIGHT, -1, 0)); 320 columns_.back().sortable = true; 321 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN, 322 ui::TableColumn::RIGHT, -1, 0)); 323 columns_.back().sortable = true; 324 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN, 325 ui::TableColumn::RIGHT, -1, 0)); 326 columns_.back().sortable = true; 327 columns_.push_back(ui::TableColumn( 328 IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN, 329 ui::TableColumn::RIGHT, -1, 0)); 330 columns_.back().sortable = true; 331 columns_.push_back( 332 ui::TableColumn(IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN, 333 ui::TableColumn::RIGHT, -1, 0)); 334 columns_.back().sortable = true; 335 // TODO(port) http://crbug.com/120488 for non-Linux. 336#if defined(OS_LINUX) 337 columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN, 338 ui::TableColumn::RIGHT, -1, 0)); 339 columns_.back().sortable = true; 340#endif 341 342 tab_table_ = new views::TableView( 343 table_model_.get(), columns_, views::ICON_AND_TEXT, false); 344 tab_table_->SetGrouper(table_model_.get()); 345 346 // Hide some columns by default 347 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROFILE_NAME_COLUMN, false); 348 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, false); 349 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, false); 350 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN, 351 false); 352 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN, 353 false); 354 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, 355 false); 356 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN, 357 false); 358 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN, 359 false); 360 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN, 361 false); 362 tab_table_->SetColumnVisibility( 363 IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN, false); 364 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_GDI_HANDLES_COLUMN, false); 365 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_USER_HANDLES_COLUMN, false); 366 tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN, false); 367 368 UpdateStatsCounters(); 369 tab_table_->SetObserver(this); 370 tab_table_->set_context_menu_controller(this); 371 set_context_menu_controller(this); 372 kill_button_ = new views::LabelButton(this, 373 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_KILL)); 374 kill_button_->SetStyle(views::Button::STYLE_BUTTON); 375 about_memory_link_ = new views::Link( 376 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK)); 377 about_memory_link_->set_listener(this); 378 379 // Makes sure our state is consistent. 380 OnSelectionChanged(); 381 382 ui::Accelerator ctrl_w(ui::VKEY_W, ui::EF_CONTROL_DOWN); 383 AddAccelerator(ctrl_w); 384} 385 386void TaskManagerView::UpdateStatsCounters() { 387 base::StatsTable* stats = base::StatsTable::current(); 388 if (stats != NULL) { 389 int max = stats->GetMaxCounters(); 390 // skip the first row (it's header data) 391 for (int i = 1; i < max; i++) { 392 const char* row = stats->GetRowName(i); 393 if (row != NULL && row[0] != '\0' && !tab_table_->HasColumn(i)) { 394 // TODO(erikkay): Use l10n to get display names for stats. Right 395 // now we're just displaying the internal counter name. Perhaps 396 // stat names not in the string table would be filtered out. 397 ui::TableColumn col; 398 col.id = i; 399 col.title = base::ASCIIToUTF16(row); 400 col.alignment = ui::TableColumn::RIGHT; 401 // TODO(erikkay): Width is hard-coded right now, so many column 402 // names are clipped. 403 col.width = 90; 404 col.sortable = true; 405 columns_.push_back(col); 406 tab_table_->AddColumn(col); 407 } 408 } 409 } 410} 411 412void TaskManagerView::ViewHierarchyChanged( 413 const ViewHierarchyChangedDetails& details) { 414 // Since we want the Kill button and the Memory Details link to show up in 415 // the same visual row as the close button, which is provided by the 416 // framework, we must add the buttons to the non-client view, which is the 417 // parent of this view. Similarly, when we're removed from the view 418 // hierarchy, we must take care to clean up those items as well. 419 if (details.child == this) { 420 if (details.is_add) { 421 details.parent->AddChildView(about_memory_link_); 422 details.parent->AddChildView(kill_button_); 423 tab_table_parent_ = tab_table_->CreateParentIfNecessary(); 424 AddChildView(tab_table_parent_); 425 } else { 426 details.parent->RemoveChildView(kill_button_); 427 details.parent->RemoveChildView(about_memory_link_); 428 } 429 } 430} 431 432void TaskManagerView::Layout() { 433 gfx::Size size = kill_button_->GetPreferredSize(); 434 gfx::Rect parent_bounds = parent()->GetContentsBounds(); 435 const int horizontal_margin = views::kPanelHorizMargin; 436 const int vertical_margin = views::kButtonVEdgeMargin; 437 int x = width() - size.width() - horizontal_margin; 438 int y_buttons = parent_bounds.bottom() - size.height() - vertical_margin; 439 kill_button_->SetBounds(x, y_buttons, size.width(), size.height()); 440 441 size = about_memory_link_->GetPreferredSize(); 442 about_memory_link_->SetBounds( 443 horizontal_margin, 444 y_buttons + (kill_button_->height() - size.height()) / 2, 445 size.width(), size.height()); 446 447 gfx::Rect rect = GetLocalBounds(); 448 rect.Inset(horizontal_margin, views::kPanelVertMargin); 449 rect.Inset(0, 0, 0, 450 kill_button_->height() + views::kUnrelatedControlVerticalSpacing); 451 tab_table_parent_->SetBoundsRect(rect); 452} 453 454gfx::Size TaskManagerView::GetPreferredSize() const { 455 return gfx::Size(460, 270); 456} 457 458bool TaskManagerView::AcceleratorPressed(const ui::Accelerator& accelerator) { 459 DCHECK_EQ(ui::VKEY_W, accelerator.key_code()); 460 DCHECK_EQ(ui::EF_CONTROL_DOWN, accelerator.modifiers()); 461 GetWidget()->Close(); 462 return true; 463} 464 465// static 466void TaskManagerView::Show(Browser* browser) { 467 // In ash we can come here through the ChromeShellDelegate. If there is no 468 // browser window at that time of the call, browser could be passed as NULL. 469 const chrome::HostDesktopType desktop_type = 470 browser ? browser->host_desktop_type() : chrome::HOST_DESKTOP_TYPE_ASH; 471 472 if (instance_) { 473 // If there's a Task manager window open already, just activate it. 474 instance_->GetWidget()->Activate(); 475 return; 476 } 477 instance_ = new TaskManagerView(desktop_type); 478 gfx::NativeWindow window = 479 browser ? browser->window()->GetNativeWindow() : NULL; 480#if defined(USE_ASH) 481 if (!window) 482 window = ash::wm::GetActiveWindow(); 483#endif 484 DialogDelegate::CreateDialogWidget(instance_, window, NULL); 485 instance_->InitAlwaysOnTopState(); 486 instance_->model_->StartUpdating(); 487#if defined(OS_WIN) 488 // Set the app id for the task manager to the app id of its parent browser. If 489 // no parent is specified, the app id will default to that of the initial 490 // process. 491 if (browser) { 492 ui::win::SetAppIdForWindow( 493 ShellIntegration::GetChromiumModelIdForProfile( 494 browser->profile()->GetPath()), 495 views::HWNDForWidget(instance_->GetWidget())); 496 } 497#endif 498 instance_->GetWidget()->Show(); 499 500 // Set the initial focus to the list of tasks. 501 views::FocusManager* focus_manager = instance_->GetFocusManager(); 502 if (focus_manager) 503 focus_manager->SetFocusedView(instance_->tab_table_); 504 505#if defined(USE_ASH) 506 gfx::NativeWindow native_window = instance_->GetWidget()->GetNativeWindow(); 507 ash::SetShelfItemDetailsForDialogWindow( 508 native_window, IDR_ASH_SHELF_ICON_TASK_MANAGER, native_window->title()); 509#endif 510} 511 512// ButtonListener implementation. 513void TaskManagerView::ButtonPressed( 514 views::Button* sender, 515 const ui::Event& event) { 516 typedef ui::ListSelectionModel::SelectedIndices SelectedIndices; 517 DCHECK_EQ(kill_button_, sender); 518 SelectedIndices selection(tab_table_->selection_model().selected_indices()); 519 for (SelectedIndices::const_reverse_iterator i = selection.rbegin(); 520 i != selection.rend(); ++i) { 521 task_manager_->KillProcess(*i); 522 } 523} 524 525// DialogDelegate implementation. 526bool TaskManagerView::CanResize() const { 527 return true; 528} 529 530bool TaskManagerView::CanMaximize() const { 531 return true; 532} 533 534bool TaskManagerView::CanMinimize() const { 535 return true; 536} 537 538bool TaskManagerView::ExecuteWindowsCommand(int command_id) { 539 return false; 540} 541 542base::string16 TaskManagerView::GetWindowTitle() const { 543 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_TITLE); 544} 545 546std::string TaskManagerView::GetWindowName() const { 547 return prefs::kTaskManagerWindowPlacement; 548} 549 550int TaskManagerView::GetDialogButtons() const { 551 return ui::DIALOG_BUTTON_NONE; 552} 553 554void TaskManagerView::WindowClosing() { 555 // Now that the window is closed, we can allow a new one to be opened. 556 // (WindowClosing comes in asynchronously from the call to Close() and we 557 // may have already opened a new instance). 558 if (instance_ == this) 559 instance_ = NULL; 560 task_manager_->OnWindowClosed(); 561} 562 563bool TaskManagerView::UseNewStyleForThisDialog() const { 564 return false; 565} 566 567// views::TableViewObserver implementation. 568void TaskManagerView::OnSelectionChanged() { 569 const ui::ListSelectionModel::SelectedIndices& selection( 570 tab_table_->selection_model().selected_indices()); 571 bool selection_contains_browser_process = false; 572 for (size_t i = 0; i < selection.size(); ++i) { 573 if (task_manager_->IsBrowserProcess(selection[i])) { 574 selection_contains_browser_process = true; 575 break; 576 } 577 } 578 kill_button_->SetEnabled(!selection_contains_browser_process && 579 !selection.empty()); 580} 581 582void TaskManagerView::OnDoubleClick() { 583 ActivateFocusedTab(); 584} 585 586void TaskManagerView::OnKeyDown(ui::KeyboardCode keycode) { 587 if (keycode == ui::VKEY_RETURN) 588 ActivateFocusedTab(); 589} 590 591void TaskManagerView::LinkClicked(views::Link* source, int event_flags) { 592 DCHECK_EQ(about_memory_link_, source); 593 task_manager_->OpenAboutMemory(desktop_type_); 594} 595 596void TaskManagerView::ShowContextMenuForView(views::View* source, 597 const gfx::Point& point, 598 ui::MenuSourceType source_type) { 599 UpdateStatsCounters(); 600 ui::SimpleMenuModel menu_model(this); 601 for (std::vector<ui::TableColumn>::iterator i(columns_.begin()); 602 i != columns_.end(); ++i) { 603 menu_model.AddCheckItem(i->id, l10n_util::GetStringUTF16(i->id)); 604 } 605 menu_runner_.reset( 606 new views::MenuRunner(&menu_model, views::MenuRunner::CONTEXT_MENU)); 607 if (menu_runner_->RunMenuAt(GetWidget(), 608 NULL, 609 gfx::Rect(point, gfx::Size()), 610 views::MENU_ANCHOR_TOPLEFT, 611 source_type) == views::MenuRunner::MENU_DELETED) { 612 return; 613 } 614} 615 616bool TaskManagerView::IsCommandIdChecked(int id) const { 617 return tab_table_->IsColumnVisible(id); 618} 619 620bool TaskManagerView::IsCommandIdEnabled(int id) const { 621 return true; 622} 623 624bool TaskManagerView::GetAcceleratorForCommandId( 625 int command_id, 626 ui::Accelerator* accelerator) { 627 return false; 628} 629 630void TaskManagerView::ExecuteCommand(int id, int event_flags) { 631 tab_table_->SetColumnVisibility(id, !tab_table_->IsColumnVisible(id)); 632} 633 634void TaskManagerView::InitAlwaysOnTopState() { 635 is_always_on_top_ = false; 636 if (GetSavedAlwaysOnTopState(&is_always_on_top_)) 637 GetWidget()->SetAlwaysOnTop(is_always_on_top_); 638} 639 640void TaskManagerView::ActivateFocusedTab() { 641 const int active_row = tab_table_->selection_model().active(); 642 if (active_row != -1) 643 task_manager_->ActivateProcess(active_row); 644} 645 646bool TaskManagerView::GetSavedAlwaysOnTopState(bool* always_on_top) const { 647 if (!g_browser_process->local_state()) 648 return false; 649 650 const base::DictionaryValue* dictionary = 651 g_browser_process->local_state()->GetDictionary(GetWindowName().c_str()); 652 return dictionary && 653 dictionary->GetBoolean("always_on_top", always_on_top) && always_on_top; 654} 655 656} // namespace 657 658namespace chrome { 659 660// Declared in browser_dialogs.h so others don't need to depend on our header. 661void ShowTaskManager(Browser* browser) { 662 TaskManagerView::Show(browser); 663} 664 665} // namespace chrome 666