browser_tab_strip_controller.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root// Use of this source code is governed by a BSD-style license that can be 3aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root// found in the LICENSE file. 4aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 5aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" 6aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 7aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "base/auto_reset.h" 8aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "base/command_line.h" 9aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "base/prefs/pref_service.h" 10aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/browser_process.h" 11aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/extensions/tab_helper.h" 12aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/favicon/favicon_tab_helper.h" 13aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/profiles/profile.h" 14aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/browser.h" 15aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/browser_tabstrip.h" 16aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/tabs/tab_menu_model.h" 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "chrome/browser/ui/tabs/tab_strip_model.h" 18aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" 19aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "chrome/browser/ui/tabs/tab_utils.h" 20aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "chrome/browser/ui/views/frame/browser_view.h" 21aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "chrome/browser/ui/views/tabs/tab.h" 22aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "chrome/browser/ui/views/tabs/tab_renderer_data.h" 23aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/browser/ui/views/tabs/tab_strip.h" 24aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/common/chrome_notification_types.h" 25aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/common/chrome_switches.h" 26aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/common/pref_names.h" 27aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "chrome/common/url_constants.h" 28aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "content/public/browser/notification_service.h" 29aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "content/public/browser/user_metrics.h" 3047cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root#include "content/public/browser/web_contents.h" 31c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root#include "ui/base/layout.h" 32c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root#include "ui/base/models/list_selection_model.h" 33aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "ui/gfx/image/image.h" 34aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "ui/views/controls/menu/menu_item_view.h" 35aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root#include "ui/views/controls/menu/menu_runner.h" 36aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#include "ui/views/widget/widget.h" 37aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 38aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Rootusing content::UserMetricsAction; 39aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Rootusing content::WebContents; 40aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 4147cc520bd63c1eabfdef23cbab10457701f2a395Kenny Rootnamespace { 4247cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root 439df6cea08a4eb527ba5b6fc9275e8b0571c12892Kenny RootTabRendererData::NetworkState TabContentsNetworkState( 449df6cea08a4eb527ba5b6fc9275e8b0571c12892Kenny Root WebContents* contents) { 459df6cea08a4eb527ba5b6fc9275e8b0571c12892Kenny Root if (!contents || !contents->IsLoading()) 46aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TabRendererData::NETWORK_STATE_NONE; 47aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (contents->IsWaitingForResponse()) 48aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TabRendererData::NETWORK_STATE_WAITING; 49aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TabRendererData::NETWORK_STATE_LOADING; 50aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root} 51aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 52aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny RootTabStripLayoutType DetermineTabStripLayout(PrefService* prefs, 53aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root bool* adjust_layout) { 54aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root *adjust_layout = false; 55aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (CommandLine::ForCurrentProcess()->HasSwitch( 56aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root switches::kEnableStackedTabStrip)) { 57aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TAB_STRIP_LAYOUT_STACKED; 58aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 59aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root // For chromeos always allow entering stacked mode. 60aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#if !defined(OS_CHROMEOS) 61aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (ui::GetDisplayLayout() != ui::LAYOUT_TOUCH) 62aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TAB_STRIP_LAYOUT_SHRINK; 63aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root#endif 64aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root *adjust_layout = true; 65aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root switch (prefs->GetInteger(prefs::kTabStripLayoutType)) { 66aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root case TAB_STRIP_LAYOUT_STACKED: 67aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TAB_STRIP_LAYOUT_STACKED; 68aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root default: 69aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return TAB_STRIP_LAYOUT_SHRINK; 70aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 71aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root} 72aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 73aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root} // namespace 74aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 75aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Rootclass BrowserTabStripController::TabContextMenuContents 76aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root : public ui::SimpleMenuModel::Delegate { 77aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root public: 78aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root TabContextMenuContents(Tab* tab, 79aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root BrowserTabStripController* controller) 80aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root : tab_(tab), 81aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root controller_(controller), 8280f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root last_command_(TabStripModel::CommandFirst) { 8380f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root model_.reset(new TabMenuModel( 8480f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root this, controller->model_, 8580f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root controller->tabstrip_->GetModelIndexOfTab(tab))); 8680f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root menu_runner_.reset(new views::MenuRunner(model_.get())); 8780f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root } 8880f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root 8980f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root virtual ~TabContextMenuContents() { 9080f0c28bcba376c34616ed27c7af3e02d4677d37Kenny Root if (controller_) 91aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root controller_->tabstrip_->StopAllHighlighting(); 92aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 93aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 94aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root void Cancel() { 95aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root controller_ = NULL; 96aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 97aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 98aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root void RunMenuAt(const gfx::Point& point, ui::MenuSourceType source_type) { 99aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (menu_runner_->RunMenuAt( 100aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root tab_->GetWidget(), NULL, gfx::Rect(point, gfx::Size()), 101aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root views::MenuItemView::TOPLEFT, source_type, 102aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root views::MenuRunner::HAS_MNEMONICS | 103aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root views::MenuRunner::CONTEXT_MENU) == 104aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root views::MenuRunner::MENU_DELETED) 105aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return; 106aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 107aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 108aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root // Overridden from ui::SimpleMenuModel::Delegate: 109aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root virtual bool IsCommandIdChecked(int command_id) const OVERRIDE { 110aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return false; 111aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 112aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE { 113aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return controller_->IsCommandEnabledForTab( 114c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root static_cast<TabStripModel::ContextMenuCommand>(command_id), 115c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root tab_); 116c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root } 117c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root virtual bool GetAcceleratorForCommandId( 118c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root int command_id, 119c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root ui::Accelerator* accelerator) OVERRIDE { 120c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root int browser_cmd; 121c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root return TabStripModel::ContextMenuCommandToBrowserCommand(command_id, 122c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root &browser_cmd) ? 123c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->tabstrip_->GetWidget()->GetAccelerator(browser_cmd, 124c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root accelerator) : 125c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root false; 126c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root } 127c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root virtual void CommandIdHighlighted(int command_id) OVERRIDE { 128c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->StopHighlightTabsForCommand(last_command_, tab_); 129c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root last_command_ = static_cast<TabStripModel::ContextMenuCommand>(command_id); 130c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->StartHighlightTabsForCommand(last_command_, tab_); 131c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root } 132c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE { 133c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // Executing the command destroys |this|, and can also end up destroying 134c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // |controller_|. So stop the highlights before executing the command. 135c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->tabstrip_->StopAllHighlighting(); 136c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->ExecuteCommandForTab( 137c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root static_cast<TabStripModel::ContextMenuCommand>(command_id), 138c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root tab_); 139c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root } 140c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 141c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root virtual void MenuClosed(ui::SimpleMenuModel* /*source*/) OVERRIDE { 142c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root if (controller_) 143c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root controller_->tabstrip_->StopAllHighlighting(); 144c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root } 145c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 146c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root private: 147c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root scoped_ptr<TabMenuModel> model_; 148c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root scoped_ptr<views::MenuRunner> menu_runner_; 149c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 150c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // The tab we're showing a menu for. 151c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root Tab* tab_; 152c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 153c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // A pointer back to our hosting controller, for command state information. 154c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root BrowserTabStripController* controller_; 155c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 156c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // The last command that was selected, so that we can start/stop highlighting 157c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root // appropriately as the user moves through the menu. 158c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root TabStripModel::ContextMenuCommand last_command_; 159c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 160c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents); 161c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root}; 162c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root 163c43ab99bd48be940dde4c8ee74155e0482cd1599Kenny Root//////////////////////////////////////////////////////////////////////////////// 164aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root// BrowserTabStripController, public: 165aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root 166aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny RootBrowserTabStripController::BrowserTabStripController(Browser* browser, 167aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root TabStripModel* model) 168aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root : model_(model), 169aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root tabstrip_(NULL), 170aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root browser_(browser), 171aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root hover_tab_selector_(model) { 172aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root model_->AddObserver(this); 173aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root 174aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root local_pref_registrar_.Init(g_browser_process->local_state()); 175aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root local_pref_registrar_.Add( 176aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root prefs::kTabStripLayoutType, 177aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root base::Bind(&BrowserTabStripController::UpdateLayoutType, 178aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root base::Unretained(this))); 179aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root} 180aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root 181aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny RootBrowserTabStripController::~BrowserTabStripController() { 182aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root // When we get here the TabStrip is being deleted. We need to explicitly 183aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root // cancel the menu, otherwise it may try to invoke something on the tabstrip 184aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root // from its destructor. 185aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root if (context_menu_contents_.get()) 186aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root context_menu_contents_->Cancel(); 187aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root 188aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root model_->RemoveObserver(this); 189aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root} 190aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root 191aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Rootvoid BrowserTabStripController::InitFromModel(TabStrip* tabstrip) { 192aceaabe71de0da877be36f5bfb88c7111f81fc3eKenny Root tabstrip_ = tabstrip; 193aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 194 UpdateLayoutType(); 195 196 // Walk the model, calling our insertion observer method for each item within 197 // it. 198 for (int i = 0; i < model_->count(); ++i) 199 AddTab(model_->GetWebContentsAt(i), i, model_->active_index() == i); 200} 201 202bool BrowserTabStripController::IsCommandEnabledForTab( 203 TabStripModel::ContextMenuCommand command_id, 204 Tab* tab) const { 205 int model_index = tabstrip_->GetModelIndexOfTab(tab); 206 return model_->ContainsIndex(model_index) ? 207 model_->IsContextMenuCommandEnabled(model_index, command_id) : false; 208} 209 210void BrowserTabStripController::ExecuteCommandForTab( 211 TabStripModel::ContextMenuCommand command_id, 212 Tab* tab) { 213 int model_index = tabstrip_->GetModelIndexOfTab(tab); 214 if (model_->ContainsIndex(model_index)) 215 model_->ExecuteContextMenuCommand(model_index, command_id); 216} 217 218bool BrowserTabStripController::IsTabPinned(Tab* tab) const { 219 return IsTabPinned(tabstrip_->GetModelIndexOfTab(tab)); 220} 221 222const ui::ListSelectionModel& BrowserTabStripController::GetSelectionModel() { 223 return model_->selection_model(); 224} 225 226int BrowserTabStripController::GetCount() const { 227 return model_->count(); 228} 229 230bool BrowserTabStripController::IsValidIndex(int index) const { 231 return model_->ContainsIndex(index); 232} 233 234bool BrowserTabStripController::IsActiveTab(int model_index) const { 235 return model_->active_index() == model_index; 236} 237 238int BrowserTabStripController::GetActiveIndex() const { 239 return model_->active_index(); 240} 241 242bool BrowserTabStripController::IsTabSelected(int model_index) const { 243 return model_->IsTabSelected(model_index); 244} 245 246bool BrowserTabStripController::IsTabPinned(int model_index) const { 247 return model_->ContainsIndex(model_index) && model_->IsTabPinned(model_index); 248} 249 250bool BrowserTabStripController::IsNewTabPage(int model_index) const { 251 return model_->ContainsIndex(model_index) && 252 model_->GetWebContentsAt(model_index)->GetURL() == 253 GURL(chrome::kChromeUINewTabURL); 254} 255 256void BrowserTabStripController::SelectTab(int model_index) { 257 model_->ActivateTabAt(model_index, true); 258} 259 260void BrowserTabStripController::ExtendSelectionTo(int model_index) { 261 model_->ExtendSelectionTo(model_index); 262} 263 264void BrowserTabStripController::ToggleSelected(int model_index) { 265 model_->ToggleSelectionAt(model_index); 266} 267 268void BrowserTabStripController::AddSelectionFromAnchorTo(int model_index) { 269 model_->AddSelectionFromAnchorTo(model_index); 270} 271 272void BrowserTabStripController::CloseTab(int model_index, 273 CloseTabSource source) { 274 // Cancel any pending tab transition. 275 hover_tab_selector_.CancelTabTransition(); 276 277 tabstrip_->PrepareForCloseAt(model_index, source); 278 model_->CloseWebContentsAt(model_index, 279 TabStripModel::CLOSE_USER_GESTURE | 280 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 281} 282 283void BrowserTabStripController::ShowContextMenuForTab( 284 Tab* tab, 285 const gfx::Point& p, 286 ui::MenuSourceType source_type) { 287 context_menu_contents_.reset(new TabContextMenuContents(tab, this)); 288 context_menu_contents_->RunMenuAt(p, source_type); 289} 290 291void BrowserTabStripController::UpdateLoadingAnimations() { 292 // Don't use the model count here as it's possible for this to be invoked 293 // before we've applied an update from the model (Browser::TabInsertedAt may 294 // be processed before us and invokes this). 295 for (int i = 0, tab_count = tabstrip_->tab_count(); i < tab_count; ++i) { 296 if (model_->ContainsIndex(i)) { 297 Tab* tab = tabstrip_->tab_at(i); 298 WebContents* contents = model_->GetWebContentsAt(i); 299 tab->UpdateLoadingAnimation(TabContentsNetworkState(contents)); 300 } 301 } 302} 303 304int BrowserTabStripController::HasAvailableDragActions() const { 305 return model_->delegate()->GetDragActions(); 306} 307 308void BrowserTabStripController::OnDropIndexUpdate(int index, 309 bool drop_before) { 310 // Perform a delayed tab transition if hovering directly over a tab. 311 // Otherwise, cancel the pending one. 312 if (index != -1 && !drop_before) { 313 hover_tab_selector_.StartTabTransition(index); 314 } else { 315 hover_tab_selector_.CancelTabTransition(); 316 } 317} 318 319void BrowserTabStripController::PerformDrop(bool drop_before, 320 int index, 321 const GURL& url) { 322 chrome::NavigateParams params(browser_, url, content::PAGE_TRANSITION_LINK); 323 params.tabstrip_index = index; 324 325 if (drop_before) { 326 content::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs")); 327 params.disposition = NEW_FOREGROUND_TAB; 328 } else { 329 content::RecordAction(UserMetricsAction("Tab_DropURLOnTab")); 330 params.disposition = CURRENT_TAB; 331 params.source_contents = model_->GetWebContentsAt(index); 332 } 333 params.window_action = chrome::NavigateParams::SHOW_WINDOW; 334 chrome::Navigate(¶ms); 335} 336 337bool BrowserTabStripController::IsCompatibleWith(TabStrip* other) const { 338 Profile* other_profile = 339 static_cast<BrowserTabStripController*>(other->controller())->profile(); 340 return other_profile == profile(); 341} 342 343void BrowserTabStripController::CreateNewTab() { 344 model_->delegate()->AddBlankTabAt(-1, true); 345} 346 347bool BrowserTabStripController::IsIncognito() { 348 return browser_->profile()->IsOffTheRecord(); 349} 350 351void BrowserTabStripController::LayoutTypeMaybeChanged() { 352 bool adjust_layout = false; 353 TabStripLayoutType layout_type = 354 DetermineTabStripLayout(g_browser_process->local_state(), &adjust_layout); 355 if (!adjust_layout || layout_type == tabstrip_->layout_type()) 356 return; 357 358 g_browser_process->local_state()->SetInteger( 359 prefs::kTabStripLayoutType, 360 static_cast<int>(tabstrip_->layout_type())); 361} 362 363void BrowserTabStripController::OnStartedDraggingTabs() { 364 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_); 365 if (browser_view && !immersive_reveal_lock_.get()) { 366 // The top-of-window views should be revealed while the user is dragging 367 // tabs in immersive fullscreen. The top-of-window views may not be already 368 // revealed if the user is attempting to attach a tab to a tabstrip 369 // belonging to an immersive fullscreen window. 370 immersive_reveal_lock_.reset( 371 browser_view->immersive_mode_controller()->GetRevealedLock( 372 ImmersiveModeController::ANIMATE_REVEAL_NO)); 373 } 374} 375 376void BrowserTabStripController::OnStoppedDraggingTabs() { 377 immersive_reveal_lock_.reset(); 378} 379 380//////////////////////////////////////////////////////////////////////////////// 381// BrowserTabStripController, TabStripModelObserver implementation: 382 383void BrowserTabStripController::TabInsertedAt(WebContents* contents, 384 int model_index, 385 bool is_active) { 386 DCHECK(contents); 387 DCHECK(model_->ContainsIndex(model_index)); 388 AddTab(contents, model_index, is_active); 389} 390 391void BrowserTabStripController::TabDetachedAt(WebContents* contents, 392 int model_index) { 393 // Cancel any pending tab transition. 394 hover_tab_selector_.CancelTabTransition(); 395 396 tabstrip_->RemoveTabAt(model_index); 397} 398 399void BrowserTabStripController::TabSelectionChanged( 400 TabStripModel* tab_strip_model, 401 const ui::ListSelectionModel& old_model) { 402 tabstrip_->SetSelection(old_model, model_->selection_model()); 403} 404 405void BrowserTabStripController::TabMoved(WebContents* contents, 406 int from_model_index, 407 int to_model_index) { 408 // Cancel any pending tab transition. 409 hover_tab_selector_.CancelTabTransition(); 410 411 // Pass in the TabRendererData as the pinned state may have changed. 412 TabRendererData data; 413 SetTabRendererDataFromModel(contents, to_model_index, &data, EXISTING_TAB); 414 tabstrip_->MoveTab(from_model_index, to_model_index, data); 415} 416 417void BrowserTabStripController::TabChangedAt(WebContents* contents, 418 int model_index, 419 TabChangeType change_type) { 420 if (change_type == TITLE_NOT_LOADING) { 421 tabstrip_->TabTitleChangedNotLoading(model_index); 422 // We'll receive another notification of the change asynchronously. 423 return; 424 } 425 426 SetTabDataAt(contents, model_index); 427} 428 429void BrowserTabStripController::TabReplacedAt(TabStripModel* tab_strip_model, 430 WebContents* old_contents, 431 WebContents* new_contents, 432 int model_index) { 433 SetTabDataAt(new_contents, model_index); 434} 435 436void BrowserTabStripController::TabPinnedStateChanged(WebContents* contents, 437 int model_index) { 438 // Currently none of the renderers render pinned state differently. 439} 440 441void BrowserTabStripController::TabMiniStateChanged(WebContents* contents, 442 int model_index) { 443 SetTabDataAt(contents, model_index); 444} 445 446void BrowserTabStripController::TabBlockedStateChanged(WebContents* contents, 447 int model_index) { 448 SetTabDataAt(contents, model_index); 449} 450 451void BrowserTabStripController::SetTabRendererDataFromModel( 452 WebContents* contents, 453 int model_index, 454 TabRendererData* data, 455 TabStatus tab_status) { 456 FaviconTabHelper* favicon_tab_helper = 457 FaviconTabHelper::FromWebContents(contents); 458 459 data->favicon = favicon_tab_helper->GetFavicon().AsImageSkia(); 460 data->network_state = TabContentsNetworkState(contents); 461 data->title = contents->GetTitle(); 462 data->url = contents->GetURL(); 463 data->loading = contents->IsLoading(); 464 data->crashed_status = contents->GetCrashedStatus(); 465 data->incognito = contents->GetBrowserContext()->IsOffTheRecord(); 466 data->show_icon = favicon_tab_helper->ShouldDisplayFavicon(); 467 data->mini = model_->IsMiniTab(model_index); 468 data->blocked = model_->IsTabBlocked(model_index); 469 data->app = extensions::TabHelper::FromWebContents(contents)->is_app(); 470 if (chrome::ShouldShowProjectingIndicator(contents)) 471 data->capture_state = TabRendererData::CAPTURE_STATE_PROJECTING; 472 else if (chrome::ShouldShowRecordingIndicator(contents)) 473 data->capture_state = TabRendererData::CAPTURE_STATE_RECORDING; 474 else 475 data->capture_state = TabRendererData::CAPTURE_STATE_NONE; 476 477 if (chrome::IsPlayingAudio(contents)) 478 data->audio_state = TabRendererData::AUDIO_STATE_PLAYING; 479 else 480 data->audio_state = TabRendererData::AUDIO_STATE_NONE; 481} 482 483void BrowserTabStripController::SetTabDataAt(content::WebContents* web_contents, 484 int model_index) { 485 TabRendererData data; 486 SetTabRendererDataFromModel(web_contents, model_index, &data, EXISTING_TAB); 487 tabstrip_->SetTabData(model_index, data); 488} 489 490void BrowserTabStripController::StartHighlightTabsForCommand( 491 TabStripModel::ContextMenuCommand command_id, 492 Tab* tab) { 493 if (command_id == TabStripModel::CommandCloseOtherTabs || 494 command_id == TabStripModel::CommandCloseTabsToRight) { 495 int model_index = tabstrip_->GetModelIndexOfTab(tab); 496 if (IsValidIndex(model_index)) { 497 std::vector<int> indices = 498 model_->GetIndicesClosedByCommand(model_index, command_id); 499 for (std::vector<int>::const_iterator i(indices.begin()); 500 i != indices.end(); ++i) { 501 tabstrip_->StartHighlight(*i); 502 } 503 } 504 } 505} 506 507void BrowserTabStripController::StopHighlightTabsForCommand( 508 TabStripModel::ContextMenuCommand command_id, 509 Tab* tab) { 510 if (command_id == TabStripModel::CommandCloseTabsToRight || 511 command_id == TabStripModel::CommandCloseOtherTabs) { 512 // Just tell all Tabs to stop pulsing - it's safe. 513 tabstrip_->StopAllHighlighting(); 514 } 515} 516 517void BrowserTabStripController::AddTab(WebContents* contents, 518 int index, 519 bool is_active) { 520 // Cancel any pending tab transition. 521 hover_tab_selector_.CancelTabTransition(); 522 523 TabRendererData data; 524 SetTabRendererDataFromModel(contents, index, &data, NEW_TAB); 525 tabstrip_->AddTabAt(index, data, is_active); 526} 527 528void BrowserTabStripController::UpdateLayoutType() { 529 bool adjust_layout = false; 530 TabStripLayoutType layout_type = 531 DetermineTabStripLayout(g_browser_process->local_state(), &adjust_layout); 532 tabstrip_->SetLayoutType(layout_type, adjust_layout); 533} 534