summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-13 22:11:03 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-13 22:11:03 +0000
commit5e26d9d482761e38a15f8cb987294d979bc58576 (patch)
treefb218ddc03bb4e3a3996c114c5ad3aa40a0e6914 /chrome/browser
parent7cd70c394eeaeb6a93a8e28142942b5584f01e2d (diff)
downloadchromium_src-5e26d9d482761e38a15f8cb987294d979bc58576.zip
chromium_src-5e26d9d482761e38a15f8cb987294d979bc58576.tar.gz
chromium_src-5e26d9d482761e38a15f8cb987294d979bc58576.tar.bz2
Refactors TabStrip code for better sharing between TabStrip and
SideTabStrip. I still have a bunch of cleanup to do, but this is a good checkpoint. BUG=none TEST=none Review URL: http://codereview.chromium.org/2037012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47202 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/frame/browser_view.cc8
-rw-r--r--chrome/browser/chromeos/frame/browser_view.h1
-rw-r--r--chrome/browser/tabs/tab_strip_model.h2
-rw-r--r--chrome/browser/views/extensions/extension_installed_bubble.cc8
-rw-r--r--chrome/browser/views/frame/browser_view.cc25
-rw-r--r--chrome/browser/views/tabs/base_tab_renderer.cc29
-rw-r--r--chrome/browser/views/tabs/base_tab_renderer.h80
-rw-r--r--chrome/browser/views/tabs/base_tab_strip.cc58
-rw-r--r--chrome/browser/views/tabs/base_tab_strip.h83
-rw-r--r--chrome/browser/views/tabs/browser_tab_strip_controller.cc335
-rw-r--r--chrome/browser/views/tabs/browser_tab_strip_controller.h96
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.cc75
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.h9
-rw-r--r--chrome/browser/views/tabs/side_tab.cc69
-rw-r--r--chrome/browser/views/tabs/side_tab.h39
-rw-r--r--chrome/browser/views/tabs/side_tab_strip.cc118
-rw-r--r--chrome/browser/views/tabs/side_tab_strip.h63
-rw-r--r--chrome/browser/views/tabs/side_tab_strip_model.h50
-rw-r--r--chrome/browser/views/tabs/tab.cc97
-rw-r--r--chrome/browser/views/tabs/tab.h68
-rw-r--r--chrome/browser/views/tabs/tab_renderer.cc224
-rw-r--r--chrome/browser/views/tabs/tab_renderer.h109
-rw-r--r--chrome/browser/views/tabs/tab_renderer_data.h49
-rw-r--r--chrome/browser/views/tabs/tab_strip.cc489
-rw-r--r--chrome/browser/views/tabs/tab_strip.h91
-rw-r--r--chrome/browser/views/tabs/tab_strip_controller.h71
26 files changed, 1193 insertions, 1153 deletions
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc
index 354676f..761459c 100644
--- a/chrome/browser/chromeos/frame/browser_view.cc
+++ b/chrome/browser/chromeos/frame/browser_view.cc
@@ -73,6 +73,8 @@ class Spacer : public views::View {
DISALLOW_COPY_AND_ASSIGN(Spacer);
};
+// TODO(sky): wire this back up.
+/*
// A chromeos implementation of Tab that shows the compact location bar.
class ChromeosTab : public Tab {
public:
@@ -113,6 +115,7 @@ class ChromeosTabStrip : public TabStrip {
DISALLOW_COPY_AND_ASSIGN(ChromeosTabStrip);
};
+*/
} // namespace
@@ -444,11 +447,6 @@ views::LayoutManager* BrowserView::CreateLayoutManager() const {
return new BrowserViewLayout();
}
-BaseTabStrip* BrowserView::CreateTabStrip(
- TabStripModel* tab_strip_model) {
- return new ChromeosTabStrip(tab_strip_model, this);
-}
-
void BrowserView::ChildPreferredSizeChanged(View* child) {
Layout();
SchedulePaint();
diff --git a/chrome/browser/chromeos/frame/browser_view.h b/chrome/browser/chromeos/frame/browser_view.h
index 87dc59b..49c0daa 100644
--- a/chrome/browser/chromeos/frame/browser_view.h
+++ b/chrome/browser/chromeos/frame/browser_view.h
@@ -64,7 +64,6 @@ class BrowserView : public ::BrowserView,
virtual void SetFocusToLocationBar(bool select_all);
virtual void ToggleCompactNavigationBar();
virtual views::LayoutManager* CreateLayoutManager() const;
- virtual BaseTabStrip* CreateTabStrip(TabStripModel* tab_strip_model);
virtual void ChildPreferredSizeChanged(View* child);
// views::ButtonListener overrides.
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index 71c0cbb..bbfde0d 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -103,7 +103,7 @@ class TabStripModelObserver {
virtual void TabReplacedAt(TabContents* old_contents,
TabContents* new_contents, int index) {}
- // Invoked when the mini state of a tab changes. This is not invoked if the
+ // Invoked when the pinned state of a tab changes. This is not invoked if the
// tab ends up moving as a result of the mini state changing.
// See note in TabMiniStateChanged as to how this relates to
// TabMiniStateChanged.
diff --git a/chrome/browser/views/extensions/extension_installed_bubble.cc b/chrome/browser/views/extensions/extension_installed_bubble.cc
index 4104664..29aa69a 100644
--- a/chrome/browser/views/extensions/extension_installed_bubble.cc
+++ b/chrome/browser/views/extensions/extension_installed_bubble.cc
@@ -14,6 +14,8 @@
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
+#include "chrome/browser/views/tabs/base_tab_renderer.h"
+#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/extensions/extension.h"
@@ -315,9 +317,9 @@ void ExtensionInstalledBubble::ShowInternal() {
extension_->page_action());
DCHECK(reference_view);
} else if (type_ == EXTENSION_APP) {
- TabStrip* tabstrip = browser_view->tabstrip()->AsTabStrip();
- Tab* tab = tabstrip->GetSelectedTab();
- DCHECK(tab->app());
+ BaseTabStrip* tabstrip = browser_view->tabstrip();
+ BaseTabRenderer* tab = tabstrip->GetSelectedBaseTab();
+ DCHECK(tab->data().app);
reference_view = tab;
}
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 59f013c..2ef1fe1 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -1655,27 +1655,20 @@ void BrowserView::InitTabStrip(TabStripModel* model) {
delete tabstrip_;
}
- TabStrip* tabstrip_as_tabstrip = NULL;
- BrowserTabStripController* tabstrip_controller = NULL;
-
- if (UseVerticalTabs()) {
- SideTabStrip* tabstrip = new SideTabStrip;
- tabstrip_controller = new BrowserTabStripController(model, tabstrip);
- tabstrip->SetModel(tabstrip_controller);
- tabstrip_ = tabstrip;
- } else {
- tabstrip_as_tabstrip = new TabStrip(model);
- tabstrip_ = tabstrip_as_tabstrip;
- }
+ BrowserTabStripController* tabstrip_controller =
+ new BrowserTabStripController(model);
+
+ if (UseVerticalTabs())
+ tabstrip_ = new SideTabStrip(tabstrip_controller);
+ else
+ tabstrip_ = new TabStrip(tabstrip_controller);
+
tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP));
if (browser_->extension_app() && tabstrip_->AsTabStrip())
tabstrip_->AsTabStrip()->set_new_tab_button_enabled(false);
AddChildView(tabstrip_);
- if (tabstrip_controller)
- tabstrip_controller->InitFromModel();
- else
- tabstrip_as_tabstrip->InitFromModel();
+ tabstrip_controller->InitFromModel(tabstrip_);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/views/tabs/base_tab_renderer.cc b/chrome/browser/views/tabs/base_tab_renderer.cc
new file mode 100644
index 0000000..e9f138d
--- /dev/null
+++ b/chrome/browser/views/tabs/base_tab_renderer.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/tabs/base_tab_renderer.h"
+
+BaseTabRenderer::BaseTabRenderer(TabController* controller)
+ : controller_(controller) {
+}
+
+void BaseTabRenderer::SetData(const TabRendererData& data) {
+ TabRendererData old(data_);
+ data_ = data;
+ DataChanged(old);
+ Layout();
+}
+
+void BaseTabRenderer::UpdateLoadingAnimation(
+ TabRendererData::NetworkState state) {
+ if (state == data_.network_state &&
+ state == TabRendererData::NETWORK_STATE_NONE) {
+ // If the network state is none and hasn't changed, do nothing. Otherwise we
+ // need to advance the animation frame.
+ return;
+ }
+
+ data_.network_state = state;
+ AdvanceLoadingAnimation(state);
+}
diff --git a/chrome/browser/views/tabs/base_tab_renderer.h b/chrome/browser/views/tabs/base_tab_renderer.h
new file mode 100644
index 0000000..8c80a53
--- /dev/null
+++ b/chrome/browser/views/tabs/base_tab_renderer.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_BASE_TAB_RENDERER_H_
+#define CHROME_BROWSER_VIEWS_TABS_BASE_TAB_RENDERER_H_
+
+#include "chrome/browser/views/tabs/tab_renderer_data.h"
+#include "views/view.h"
+
+class BaseTabRenderer;
+
+// Controller for tabs.
+class TabController {
+ public:
+ // Selects the tab.
+ virtual void SelectTab(BaseTabRenderer* tab) = 0;
+
+ // Closes the tab.
+ virtual void CloseTab(BaseTabRenderer* tab) = 0;
+
+ // Shows a context menu for the tab at the specified point in screen coords.
+ virtual void ShowContextMenu(BaseTabRenderer* tab, const gfx::Point& p) = 0;
+
+ // Returns true if the specified Tab is selected.
+ virtual bool IsTabSelected(const BaseTabRenderer* tab) const = 0;
+
+ // Returns true if the specified Tab is pinned.
+ virtual bool IsTabPinned(const BaseTabRenderer* tab) const = 0;
+
+ // Potentially starts a drag for the specified Tab.
+ virtual void MaybeStartDrag(BaseTabRenderer* tab,
+ const views::MouseEvent& event) = 0;
+
+ // Continues dragging a Tab.
+ virtual void ContinueDrag(const views::MouseEvent& event) = 0;
+
+ // Ends dragging a Tab. |canceled| is true if the drag was aborted in a way
+ // other than the user releasing the mouse. Returns whether the tab has been
+ // destroyed.
+ virtual bool EndDrag(bool canceled) = 0;
+
+ protected:
+ virtual ~TabController() {}
+};
+
+// Base class for tab renderers.
+class BaseTabRenderer : public views::View {
+ public:
+ explicit BaseTabRenderer(TabController* controller);
+
+ // Sets the data this tabs displays. Invokes DataChanged for subclasses to
+ // update themselves appropriately.
+ void SetData(const TabRendererData& data);
+ const TabRendererData& data() const { return data_; }
+
+ // Sets the network state. If the network state changes NetworkStateChanged is
+ // invoked.
+ virtual void UpdateLoadingAnimation(TabRendererData::NetworkState state);
+
+ protected:
+ // Invoked from SetData after |data_| has been updated to the new data.
+ virtual void DataChanged(const TabRendererData& old) {}
+
+ // Invoked if data_.network_state changes, or the network_state is not none.
+ virtual void AdvanceLoadingAnimation(TabRendererData::NetworkState state) {}
+
+ TabController* controller() const { return controller_; }
+
+ private:
+ // The controller.
+ // WARNING: this is null during detached tab dragging.
+ TabController* controller_;
+
+ TabRendererData data_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseTabRenderer);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_BASE_TAB_RENDERER_H_
diff --git a/chrome/browser/views/tabs/base_tab_strip.cc b/chrome/browser/views/tabs/base_tab_strip.cc
new file mode 100644
index 0000000..a39633b
--- /dev/null
+++ b/chrome/browser/views/tabs/base_tab_strip.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/tabs/base_tab_strip.h"
+
+#include "chrome/browser/views/tabs/tab_strip_controller.h"
+
+BaseTabStrip::BaseTabStrip(TabStripController* controller)
+ : controller_(controller) {
+}
+
+BaseTabStrip::~BaseTabStrip() {
+}
+
+void BaseTabStrip::UpdateLoadingAnimations() {
+ controller_->UpdateLoadingAnimations();
+}
+
+BaseTabRenderer* BaseTabStrip::GetSelectedBaseTab() const {
+ return GetBaseTabAtModelIndex(controller_->GetSelectedIndex());
+}
+
+int BaseTabStrip::GetModelCount() const {
+ return controller_->GetCount();
+}
+
+bool BaseTabStrip::IsValidModelIndex(int model_index) const {
+ return controller_->IsValidIndex(model_index);
+}
+
+void BaseTabStrip::SelectTab(BaseTabRenderer* tab) {
+ int model_index = GetModelIndexOfBaseTab(tab);
+ if (IsValidModelIndex(model_index))
+ controller_->SelectTab(model_index);
+}
+
+void BaseTabStrip::CloseTab(BaseTabRenderer* tab) {
+ int model_index = GetModelIndexOfBaseTab(tab);
+ if (IsValidModelIndex(model_index))
+ controller_->CloseTab(model_index);
+}
+
+void BaseTabStrip::ShowContextMenu(BaseTabRenderer* tab, const gfx::Point& p) {
+ controller_->ShowContextMenu(tab, p);
+}
+
+bool BaseTabStrip::IsTabSelected(const BaseTabRenderer* tab) const {
+ int model_index = GetModelIndexOfBaseTab(tab);
+ return IsValidModelIndex(model_index) &&
+ controller_->IsTabSelected(model_index);
+}
+
+bool BaseTabStrip::IsTabPinned(const BaseTabRenderer* tab) const {
+ int model_index = GetModelIndexOfBaseTab(tab);
+ return IsValidModelIndex(model_index) &&
+ controller_->IsTabPinned(model_index);
+}
diff --git a/chrome/browser/views/tabs/base_tab_strip.h b/chrome/browser/views/tabs/base_tab_strip.h
index fbb7612..eb3208b 100644
--- a/chrome/browser/views/tabs/base_tab_strip.h
+++ b/chrome/browser/views/tabs/base_tab_strip.h
@@ -5,14 +5,21 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_BASE_TAB_STRIP_H_
#define CHROME_BROWSER_VIEWS_TABS_BASE_TAB_STRIP_H_
+#include "base/scoped_ptr.h"
+#include "chrome/browser/views/tabs/base_tab_renderer.h"
#include "views/view.h"
class TabStrip;
+class TabStripController;
+class ThemeProvider;
-// A class that represents the common interface to the tabstrip used by classes
-// such as BrowserView etc.
-class BaseTabStrip : public views::View {
+// Base class for the view tab strip implementations.
+class BaseTabStrip : public views::View,
+ public TabController {
public:
+ explicit BaseTabStrip(TabStripController* controller);
+ virtual ~BaseTabStrip();
+
// Returns the preferred height of this TabStrip. This is based on the
// typical height of its constituent tabs.
virtual int GetPreferredHeight() = 0;
@@ -34,7 +41,7 @@ class BaseTabStrip : public views::View {
// Updates the loading animations displayed by tabs in the tabstrip to the
// next frame.
- virtual void UpdateLoadingAnimations() = 0;
+ void UpdateLoadingAnimations();
// Returns true if Tabs in this TabStrip are currently changing size or
// position.
@@ -42,7 +49,73 @@ class BaseTabStrip : public views::View {
// Returns this object as a TabStrip if it is one.
virtual TabStrip* AsTabStrip() = 0;
+
+ // Starts highlighting the tab at the specified index.
+ virtual void StartHighlight(int model_index) = 0;
+
+ // Stops all tab higlighting.
+ virtual void StopAllHighlighting() = 0;
+
+ // Returns the tab at the specified model index.
+ virtual BaseTabRenderer* GetBaseTabAtModelIndex(int model_index) const = 0;
+
+ // Returns the tab at the specified tab index.
+ virtual BaseTabRenderer* GetBaseTabAtTabIndex(int tab_index) const = 0;
+
+ // Returns the index of the specified tab in the model coordiate system, or
+ // -1 if tab is closing or not valid.
+ virtual int GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const = 0;
+
+ // Returns the number of tabs.
+ virtual int GetTabCount() const = 0;
+
+ // Returns the selected tab.
+ virtual BaseTabRenderer* GetSelectedBaseTab() const;
+
+ // Creates and returns a tab that can be used for dragging. Ownership passes
+ // to the caller.
+ virtual BaseTabRenderer* CreateTabForDragging() = 0;
+
+ // Adds a tab at the specified index.
+ virtual void AddTabAt(int model_index,
+ bool foreground,
+ const TabRendererData& data) = 0;
+
+ // Removes a tab at the specified index.
+ virtual void RemoveTabAt(int model_index) = 0;
+
+ // Selects a tab at the specified index. |old_model_index| is the selected
+ // index prior to the selection change.
+ virtual void SelectTabAt(int old_model_index, int new_model_index) = 0;
+
+ // Moves a tab.
+ virtual void MoveTab(int from_model_index, int to_model_index) = 0;
+
+ // Invoked when the title of a tab changes and the tab isn't loading.
+ virtual void TabTitleChangedNotLoading(int model_index) = 0;
+
+ // Sets the tab data at the specified model index.
+ virtual void SetTabData(int model_index, const TabRendererData& data) = 0;
+
+ // Cover methods for TabStripController method.
+ int GetModelCount() const;
+ bool IsValidModelIndex(int model_index) const;
+
+ // TabController overrides:
+ virtual void SelectTab(BaseTabRenderer* tab);
+ virtual void CloseTab(BaseTabRenderer* tab);
+ virtual void ShowContextMenu(BaseTabRenderer* tab, const gfx::Point& p);
+ virtual bool IsTabSelected(const BaseTabRenderer* tab) const;
+ virtual bool IsTabPinned(const BaseTabRenderer* tab) const;
+ virtual void MaybeStartDrag(BaseTabRenderer* tab,
+ const views::MouseEvent& event) = 0;
+ virtual void ContinueDrag(const views::MouseEvent& event) = 0;
+ virtual bool EndDrag(bool canceled) = 0;
+
+ TabStripController* controller() const { return controller_.get(); }
+
+ private:
+ scoped_ptr<TabStripController> controller_;
};
#endif // CHROME_BROWSER_VIEWS_TABS_BASE_TAB_STRIP_H_
-
diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/views/tabs/browser_tab_strip_controller.cc
index e828326..a2a8c92 100644
--- a/chrome/browser/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/views/tabs/browser_tab_strip_controller.cc
@@ -4,40 +4,70 @@
#include "chrome/browser/views/tabs/browser_tab_strip_controller.h"
+#include "base/command_line.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_menu_model.h"
-#include "chrome/browser/views/tabs/side_tab_strip.h"
+#include "chrome/browser/views/app_launcher.h"
+#include "chrome/browser/views/tabs/base_tab_strip.h"
+#include "chrome/browser/views/tabs/tab_renderer_data.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/url_constants.h"
#include "views/controls/menu/menu_2.h"
#include "views/widget/widget.h"
+static TabRendererData::NetworkState TabContentsNetworkState(
+ TabContents* contents) {
+ if (!contents || !contents->is_loading())
+ return TabRendererData::NETWORK_STATE_NONE;
+ if (contents->waiting_for_response())
+ return TabRendererData::NETWORK_STATE_WAITING;
+ return TabRendererData::NETWORK_STATE_LOADING;
+}
+
class BrowserTabStripController::TabContextMenuContents
: public menus::SimpleMenuModel::Delegate {
public:
- TabContextMenuContents(int tab_index, BrowserTabStripController* controller)
+ TabContextMenuContents(BaseTabRenderer* tab,
+ BrowserTabStripController* controller)
: ALLOW_THIS_IN_INITIALIZER_LIST(
- model_(this, controller->IsTabPinned(tab_index))),
- tab_index_(tab_index),
- controller_(controller) {
+ model_(this, controller->IsTabPinned(tab))),
+ tab_(tab),
+ controller_(controller),
+ last_command_(TabStripModel::CommandFirst) {
Build();
}
virtual ~TabContextMenuContents() {
menu_->CancelMenu();
+ if (controller_)
+ controller_->tabstrip_->StopAllHighlighting();
+ }
+
+ void Cancel() {
+ controller_ = NULL;
}
void RunMenuAt(const gfx::Point& point) {
+ BrowserTabStripController* controller = controller_;
menu_->RunMenuAt(point, views::Menu2::ALIGN_TOPLEFT);
+ // We could be gone now. Assume |this| is junk!
+ if (controller)
+ controller->tabstrip_->StopAllHighlighting();
}
// Overridden from menus::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const {
return controller_->IsCommandCheckedForTab(
static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_index_);
+ tab_);
}
virtual bool IsCommandIdEnabled(int command_id) const {
return controller_->IsCommandEnabledForTab(
static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_index_);
+ tab_);
}
virtual bool GetAcceleratorForCommandId(
int command_id,
@@ -45,10 +75,15 @@ class BrowserTabStripController::TabContextMenuContents
return controller_->tabstrip_->GetWidget()->GetAccelerator(command_id,
accelerator);
}
+ virtual void CommandIdHighlighted(int command_id) {
+ controller_->StopHighlightTabsForCommand(last_command_, tab_);
+ last_command_ = static_cast<TabStripModel::ContextMenuCommand>(command_id);
+ controller_->StartHighlightTabsForCommand(last_command_, tab_);
+ }
virtual void ExecuteCommand(int command_id) {
controller_->ExecuteCommandForTab(
static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_index_);
+ tab_);
}
private:
@@ -59,31 +94,40 @@ class BrowserTabStripController::TabContextMenuContents
TabMenuModel model_;
scoped_ptr<views::Menu2> menu_;
- // The index of the tab we are showing the context menu for.
- int tab_index_;
+ // The tab we're showing a menu for.
+ BaseTabRenderer* tab_;
// A pointer back to our hosting controller, for command state information.
BrowserTabStripController* controller_;
+ // The last command that was selected, so that we can start/stop highlighting
+ // appropriately as the user moves through the menu.
+ TabStripModel::ContextMenuCommand last_command_;
+
DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents);
};
-
////////////////////////////////////////////////////////////////////////////////
// BrowserTabStripController, public:
-BrowserTabStripController::BrowserTabStripController(TabStripModel* model,
- SideTabStrip* tabstrip)
+BrowserTabStripController::BrowserTabStripController(TabStripModel* model)
: model_(model),
- tabstrip_(tabstrip) {
+ tabstrip_(NULL) {
model_->AddObserver(this);
}
BrowserTabStripController::~BrowserTabStripController() {
+ // When we get here the TabStrip is being deleted. We need to explicitly
+ // cancel the menu, otherwise it may try to invoke something on the tabstrip
+ // from it's destructor.
+ if (context_menu_contents_.get())
+ context_menu_contents_->Cancel();
+
model_->RemoveObserver(this);
}
-void BrowserTabStripController::InitFromModel() {
+void BrowserTabStripController::InitFromModel(BaseTabStrip* tabstrip) {
+ tabstrip_ = tabstrip;
// Walk the model, calling our insertion observer method for each item within
// it.
for (int i = 0; i < model_->count(); ++i) {
@@ -93,111 +137,266 @@ void BrowserTabStripController::InitFromModel() {
}
bool BrowserTabStripController::IsCommandEnabledForTab(
- TabStripModel::ContextMenuCommand command_id, int tab_index) const {
- if (model_->ContainsIndex(tab_index))
- return model_->IsContextMenuCommandEnabled(tab_index, command_id);
- return false;
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab) const {
+ int model_index = tabstrip_->GetModelIndexOfBaseTab(tab);
+ return model_->ContainsIndex(model_index) ?
+ model_->IsContextMenuCommandEnabled(model_index, command_id) : false;
}
bool BrowserTabStripController::IsCommandCheckedForTab(
- TabStripModel::ContextMenuCommand command_id, int tab_index) const {
- // TODO(beng): move to TabStripModel, see note in IsTabPinned.
- if (command_id == TabStripModel::CommandTogglePinned)
- return false;
-
- if (model_->ContainsIndex(tab_index))
- return model_->IsContextMenuCommandChecked(tab_index, command_id);
- return false;
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab) const {
+ int model_index = tabstrip_->GetModelIndexOfBaseTab(tab);
+ return model_->ContainsIndex(model_index) ?
+ model_->IsContextMenuCommandChecked(model_index, command_id) : false;
}
void BrowserTabStripController::ExecuteCommandForTab(
- TabStripModel::ContextMenuCommand command_id, int tab_index) {
- if (model_->ContainsIndex(tab_index))
- model_->ExecuteContextMenuCommand(tab_index, command_id);
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab) {
+ int model_index = tabstrip_->GetModelIndexOfBaseTab(tab);
+ if (model_->ContainsIndex(model_index))
+ model_->ExecuteContextMenuCommand(model_index, command_id);
}
-bool BrowserTabStripController::IsTabPinned(int tab_index) {
- return model_->ContainsIndex(tab_index) ?
- model_->IsTabPinned(tab_index) : false;
+bool BrowserTabStripController::IsTabPinned(BaseTabRenderer* tab) {
+ return IsTabPinned(tabstrip_->GetModelIndexOfBaseTab(tab));
}
-////////////////////////////////////////////////////////////////////////////////
-// BrowserTabStripController, SideTabStripModel implementation:
+int BrowserTabStripController::GetCount() const {
+ return model_->count();
+}
-SkBitmap BrowserTabStripController::GetIcon(int index) const {
- return model_->GetTabContentsAt(index)->GetFavIcon();
+bool BrowserTabStripController::IsValidIndex(int index) const {
+ return model_->ContainsIndex(index);
}
-string16 BrowserTabStripController::GetTitle(int index) const {
- return model_->GetTabContentsAt(index)->GetTitle();
+int BrowserTabStripController::GetSelectedIndex() const {
+ return model_->selected_index();
}
-bool BrowserTabStripController::IsSelected(int index) const {
- return model_->selected_index() == index;
+bool BrowserTabStripController::IsTabSelected(int model_index) const {
+ return model_->selected_index() == model_index;
}
-SideTabStripModel::NetworkState
- BrowserTabStripController::GetNetworkState(int index) const {
- TabContents* contents = model_->GetTabContentsAt(index);
- if (!contents || !contents->is_loading())
- return NetworkState_None;
- if (contents->waiting_for_response())
- return NetworkState_Waiting;
- return NetworkState_Loading;
+bool BrowserTabStripController::IsTabPinned(int model_index) const {
+ return model_->ContainsIndex(model_index) && model_->IsTabPinned(model_index);
+}
+
+bool BrowserTabStripController::IsNewTabPage(int model_index) const {
+ return model_->ContainsIndex(model_index) &&
+ model_->GetTabContentsAt(model_index)->GetURL() ==
+ GURL(chrome::kChromeUINewTabURL);
}
-void BrowserTabStripController::SelectTab(int index) {
- model_->SelectTabContentsAt(index, true);
+void BrowserTabStripController::SelectTab(int model_index) {
+ model_->SelectTabContentsAt(model_index, true);
}
-void BrowserTabStripController::CloseTab(int index) {
- model_->CloseTabContentsAt(index);
+void BrowserTabStripController::CloseTab(int model_index) {
+ model_->CloseTabContentsAt(model_index);
}
-void BrowserTabStripController::ShowContextMenu(int index,
+void BrowserTabStripController::ShowContextMenu(BaseTabRenderer* tab,
const gfx::Point& p) {
- context_menu_contents_.reset(new TabContextMenuContents(index, this));
+ context_menu_contents_.reset(new TabContextMenuContents(tab, this));
context_menu_contents_->RunMenuAt(p);
}
+void BrowserTabStripController::UpdateLoadingAnimations() {
+ // Don't use the model count here as it's possible for this to be invoked
+ // before we've applied an update from the model (Browser::TabInsertedAt may
+ // be processed before us and invokes this).
+ for (int tab_index = 0, tab_count = tabstrip_->GetTabCount();
+ tab_index < tab_count; ++tab_index) {
+ BaseTabRenderer* tab = tabstrip_->GetBaseTabAtTabIndex(tab_index);
+ int model_index = tabstrip_->GetModelIndexOfBaseTab(tab);
+ if (model_->ContainsIndex(model_index)) {
+ TabContents* contents = model_->GetTabContentsAt(model_index);
+ tab->UpdateLoadingAnimation(TabContentsNetworkState(contents));
+ }
+ }
+}
+
+int BrowserTabStripController::HasAvailableDragActions() const {
+ return model_->delegate()->GetDragActions();
+}
+
+void BrowserTabStripController::PerformDrop(bool drop_before,
+ int index,
+ const GURL& url) {
+ if (drop_before) {
+ UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"),
+ model_->profile());
+
+ // Insert a new tab.
+ TabContents* contents = model_->delegate()->CreateTabContentsForURL(
+ url, GURL(), model_->profile(), PageTransition::TYPED, false, NULL);
+ model_->AddTabContents(contents, index, false,
+ PageTransition::GENERATED, true);
+ } else {
+ UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLOnTab"),
+ model_->profile());
+
+ model_->GetTabContentsAt(index)->controller().LoadURL(
+ url, GURL(), PageTransition::GENERATED);
+ model_->SelectTabContentsAt(index, true);
+ }
+}
+
+bool BrowserTabStripController::IsCompatibleWith(BaseTabStrip* other) const {
+ Profile* other_profile =
+ static_cast<BrowserTabStripController*>(other->controller())->profile();
+ return other_profile == profile();
+}
+
+void BrowserTabStripController::CreateNewTab() {
+ // TODO(jcampan): if we decide to keep the app launcher as the default
+ // behavior for the new tab button, we should add a method
+ // on the TabStripDelegate to do so.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsPanel)) {
+ NavigationController& controller =
+ model_->GetSelectedTabContents()->controller();
+ AppLauncher::ShowForNewTab(
+ Browser::GetBrowserForController(&controller, NULL), std::string());
+ return;
+ }
+ UserMetrics::RecordAction(UserMetricsAction("NewTab_Button"),
+ model_->profile());
+ model_->delegate()->AddBlankTab(true);
+}
+
////////////////////////////////////////////////////////////////////////////////
// BrowserTabStripController, TabStripModelObserver implementation:
-void BrowserTabStripController::TabInsertedAt(TabContents* contents, int index,
+void BrowserTabStripController::TabInsertedAt(TabContents* contents,
+ int model_index,
bool foreground) {
- tabstrip_->AddTabAt(index);
+ DCHECK(contents);
+ DCHECK(model_index == TabStripModel::kNoTab ||
+ model_->ContainsIndex(model_index));
+ // This tab may be attached to another browser window, we should notify
+ // renderer.
+ contents->render_view_host()->UpdateBrowserWindowId(
+ contents->controller().window_id().id());
+
+ TabRendererData data;
+ SetTabRendererDataFromModel(contents, model_index, &data);
+ tabstrip_->AddTabAt(model_index, foreground, data);
}
void BrowserTabStripController::TabDetachedAt(TabContents* contents,
- int index) {
- tabstrip_->RemoveTabAt(index);
+ int model_index) {
+ tabstrip_->RemoveTabAt(model_index);
}
void BrowserTabStripController::TabSelectedAt(TabContents* old_contents,
- TabContents* contents, int index,
+ TabContents* contents,
+ int model_index,
bool user_gesture) {
- tabstrip_->SelectTabAt(index);
+ tabstrip_->SelectTabAt(model_->GetIndexOfTabContents(old_contents),
+ model_index);
}
-void BrowserTabStripController::TabMoved(TabContents* contents, int from_index,
- int to_index) {
+void BrowserTabStripController::TabMoved(TabContents* contents,
+ int from_model_index,
+ int to_model_index) {
+ // Update the data first as the pinned state may have changed.
+ TabRendererData data;
+ SetTabRendererDataFromModel(contents, to_model_index, &data);
+ tabstrip_->SetTabData(from_model_index, data);
+
+ tabstrip_->MoveTab(from_model_index, to_model_index);
}
-void BrowserTabStripController::TabChangedAt(TabContents* contents, int index,
+void BrowserTabStripController::TabChangedAt(TabContents* contents,
+ int model_index,
TabChangeType change_type) {
- tabstrip_->UpdateTabAt(index);
+ if (change_type == TITLE_NOT_LOADING) {
+ tabstrip_->TabTitleChangedNotLoading(model_index);
+ // We'll receive another notification of the change asynchronously.
+ return;
+ }
+
+ SetTabDataAt(contents, model_index);
}
void BrowserTabStripController::TabReplacedAt(TabContents* old_contents,
TabContents* new_contents,
- int index) {
+ int model_index) {
+ SetTabDataAt(new_contents, model_index);
}
void BrowserTabStripController::TabPinnedStateChanged(TabContents* contents,
- int index) {
+ int model_index) {
+ // Currently none of the renderers render pinned state differently.
+}
+
+void BrowserTabStripController::TabMiniStateChanged(
+ TabContents* contents,
+ int model_index) {
+ SetTabDataAt(contents, model_index);
}
void BrowserTabStripController::TabBlockedStateChanged(TabContents* contents,
- int index) {
+ int model_index) {
+ SetTabDataAt(contents, model_index);
+}
+
+void BrowserTabStripController::SetTabDataAt(TabContents* contents,
+ int model_index) {
+ TabRendererData data;
+ SetTabRendererDataFromModel(contents, model_index, &data);
+ tabstrip_->SetTabData(model_index, data);
+}
+
+void BrowserTabStripController::SetTabRendererDataFromModel(
+ TabContents* contents,
+ int model_index,
+ TabRendererData* data) {
+ SkBitmap* app_icon = contents->GetExtensionAppIcon();
+ if (app_icon)
+ data->favicon = *app_icon;
+ else
+ data->favicon = contents->GetFavIcon();
+ data->network_state = TabContentsNetworkState(contents);
+ data->title = contents->GetTitle();
+ data->loading = contents->is_loading();
+ data->crashed = contents->is_crashed();
+ data->off_the_record = contents->profile()->IsOffTheRecord();
+ data->show_icon = contents->ShouldDisplayFavIcon();
+ data->mini = model_->IsMiniTab(model_index);
+ data->blocked = model_->IsTabBlocked(model_index);
+ data->phantom = model_->IsPhantomTab(model_index);
+ data->app = contents->is_app();
}
+void BrowserTabStripController::StartHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab) {
+ if (command_id == TabStripModel::CommandCloseTabsOpenedBy ||
+ command_id == TabStripModel::CommandCloseOtherTabs ||
+ command_id == TabStripModel::CommandCloseTabsToRight) {
+ int model_index = tabstrip_->GetModelIndexOfBaseTab(tab);
+ if (IsValidIndex(model_index)) {
+ std::vector<int> indices =
+ model_->GetIndicesClosedByCommand(model_index, command_id);
+ for (std::vector<int>::const_iterator i = indices.begin();
+ i != indices.end(); ++i) {
+ tabstrip_->StartHighlight(*i);
+ }
+ }
+ }
+}
+
+void BrowserTabStripController::StopHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab) {
+ if (command_id == TabStripModel::CommandCloseTabsOpenedBy ||
+ command_id == TabStripModel::CommandCloseTabsToRight ||
+ command_id == TabStripModel::CommandCloseOtherTabs) {
+ // Just tell all Tabs to stop pulsing - it's safe.
+ tabstrip_->StopAllHighlighting();
+ }
+}
diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.h b/chrome/browser/views/tabs/browser_tab_strip_controller.h
index f4a0295..c15386b 100644
--- a/chrome/browser/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/views/tabs/browser_tab_strip_controller.h
@@ -7,58 +7,94 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/views/tabs/side_tab_strip_model.h"
+#include "chrome/browser/views/tabs/tab_strip_controller.h"
-class SideTabStrip;
+class BaseTabRenderer;
+class BaseTabStrip;
-// An implementation of SideTabStripModel that sources data from
-// the TabContentses in a TabStripModel.
-class BrowserTabStripController : public SideTabStripModel,
+struct TabRendererData;
+
+// An implementation of TabStripController that sources data from the
+// TabContentses in a TabStripModel.
+class BrowserTabStripController : public TabStripController,
public TabStripModelObserver {
public:
- BrowserTabStripController(TabStripModel* model, SideTabStrip* tabstrip);
+ explicit BrowserTabStripController(TabStripModel* model);
virtual ~BrowserTabStripController();
- void InitFromModel();
+ void InitFromModel(BaseTabStrip* tabstrip);
+
+ TabStripModel* model() const { return model_; }
bool IsCommandEnabledForTab(TabStripModel::ContextMenuCommand command_id,
- int tab_index) const;
+ BaseTabRenderer* tab) const;
bool IsCommandCheckedForTab(TabStripModel::ContextMenuCommand command_id,
- int tab_index) const;
+ BaseTabRenderer* tab) const;
void ExecuteCommandForTab(TabStripModel::ContextMenuCommand command_id,
- int tab_index);
- bool IsTabPinned(int tab_index);
-
- // SideTabStripModel implementation:
- virtual SkBitmap GetIcon(int index) const;
- virtual string16 GetTitle(int index) const;
- virtual bool IsSelected(int index) const;
- virtual NetworkState GetNetworkState(int index) const;
- virtual void SelectTab(int index);
- virtual void CloseTab(int index);
- virtual void ShowContextMenu(int index, const gfx::Point& p);
+ BaseTabRenderer* tab);
+ bool IsTabPinned(BaseTabRenderer* tab);
+
+ // TabStripController implementation:
+ virtual int GetCount() const;
+ virtual bool IsValidIndex(int model_index) const;
+ virtual int GetSelectedIndex() const;
+ virtual bool IsTabSelected(int model_index) const;
+ virtual bool IsTabPinned(int model_index) const;
+ virtual bool IsNewTabPage(int model_index) const;
+ virtual void SelectTab(int model_index);
+ virtual void CloseTab(int model_index);
+ virtual void ShowContextMenu(BaseTabRenderer* tab, const gfx::Point& p);
+ virtual void UpdateLoadingAnimations();
+ virtual int HasAvailableDragActions() const;
+ virtual void PerformDrop(bool drop_before, int index, const GURL& url);
+ virtual bool IsCompatibleWith(BaseTabStrip* other) const;
+ virtual void CreateNewTab();
// TabStripModelObserver implementation:
- virtual void TabInsertedAt(TabContents* contents, int index,
+ virtual void TabInsertedAt(TabContents* contents,
+ int model_index,
bool foreground);
- virtual void TabDetachedAt(TabContents* contents, int index);
+ virtual void TabDetachedAt(TabContents* contents, int model_index);
virtual void TabSelectedAt(TabContents* old_contents,
- TabContents* contents, int index,
+ TabContents* contents,
+ int model_index,
bool user_gesture);
- virtual void TabMoved(TabContents* contents, int from_index,
- int to_index);
- virtual void TabChangedAt(TabContents* contents, int index,
+ virtual void TabMoved(TabContents* contents,
+ int from_model_index,
+ int to_model_index);
+ virtual void TabChangedAt(TabContents* contents,
+ int model_index,
TabChangeType change_type);
virtual void TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents, int index);
- virtual void TabPinnedStateChanged(TabContents* contents, int index);
- virtual void TabBlockedStateChanged(TabContents* contents, int index);
+ TabContents* new_contents,
+ int model_index);
+ virtual void TabPinnedStateChanged(TabContents* contents, int model_index);
+ virtual void TabMiniStateChanged(TabContents* contents, int model_index);
+ virtual void TabBlockedStateChanged(TabContents* contents, int model_index);
private:
class TabContextMenuContents;
+ // Invokes tabstrip_->SetTabData.
+ void SetTabDataAt(TabContents* contents, int model_index);
+
+ // Sets the TabRendererData from the TabStripModel.
+ void SetTabRendererDataFromModel(TabContents* contents,
+ int model_index,
+ TabRendererData* data);
+
+ void StartHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab);
+ void StopHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id,
+ BaseTabRenderer* tab);
+
+ Profile* profile() const { return model_->profile(); }
+
TabStripModel* model_;
- SideTabStrip* tabstrip_;
+
+ BaseTabStrip* tabstrip_;
// If non-NULL it means we're showing a menu for the tab.
scoped_ptr<TabContextMenuContents> context_menu_contents_;
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc
index 61b6686..3a4ee25 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.cc
+++ b/chrome/browser/views/tabs/dragged_tab_controller.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/tabs/browser_tab_strip_controller.h"
#include "chrome/browser/views/tabs/dragged_tab_view.h"
#include "chrome/browser/views/tabs/native_view_photobooth.h"
#include "chrome/browser/views/tabs/tab.h"
@@ -322,11 +323,11 @@ DraggedTabController::DraggedTabController(Tab* source_tab,
old_focused_view_(NULL),
in_destructor_(false),
last_move_screen_x_(0),
- mini_(source_tabstrip->model()->IsMiniTab(source_model_index_)),
- pinned_(source_tabstrip->model()->IsTabPinned(source_model_index_)),
+ mini_(source_tab->data().mini),
+ pinned_(source_tabstrip->IsTabPinned(source_tab)),
started_drag_(false) {
SetDraggedContents(
- source_tabstrip_->model()->GetTabContentsAt(source_model_index_));
+ GetModel(source_tabstrip_)->GetTabContentsAt(source_model_index_));
// Listen for Esc key presses.
MessageLoopForUI::current()->AddObserver(this);
}
@@ -653,7 +654,7 @@ void DraggedTabController::MoveAttachedTab(const gfx::Point& screen_point) {
gfx::Point dragged_view_point = GetAttachedTabDragPoint(screen_point);
- TabStripModel* attached_model = attached_tabstrip_->model();
+ TabStripModel* attached_model = GetModel(attached_tabstrip_);
int from_index = attached_model->GetIndexOfTabContents(dragged_contents_);
// Determine the horizontal move threshold. This is dependent on the width
@@ -738,7 +739,7 @@ TabStrip* DraggedTabController::GetTabStripForPoint(
return NULL;
TabStrip* other_tabstrip = browser->tabstrip()->AsTabStrip();
- if (!other_tabstrip->IsCompatibleWith(source_tabstrip_))
+ if (!other_tabstrip->controller()->IsCompatibleWith(source_tabstrip_))
return NULL;
return GetTabStripIfItContains(other_tabstrip, screen_point);
}
@@ -802,8 +803,8 @@ void DraggedTabController::Attach(TabStrip* attached_tabstrip,
gfx::Rect bounds = GetDraggedViewTabStripBounds(screen_point);
int index = GetInsertionIndexForDraggedBounds(bounds, false);
attached_tabstrip_->set_attaching_dragged_tab(true);
- attached_tabstrip_->model()->InsertTabContentsAt(index, dragged_contents_,
- true, false, pinned_);
+ GetModel(attached_tabstrip_)->InsertTabContentsAt(index, dragged_contents_,
+ true, false, pinned_);
attached_tabstrip_->set_attaching_dragged_tab(false);
tab = GetTabMatchingDraggedContents(attached_tabstrip_);
@@ -828,7 +829,8 @@ void DraggedTabController::Detach() {
dragged_contents_->set_capturing_contents(true);
// Update the Model.
- TabStripModel* attached_model = attached_tabstrip_->model();
+ TabRendererData tab_data = attached_tab_->data();
+ TabStripModel* attached_model = GetModel(attached_tabstrip_);
int index = attached_model->GetIndexOfTabContents(dragged_contents_);
DCHECK(index != -1);
attached_model->DetachTabContentsAt(index);
@@ -845,7 +847,7 @@ void DraggedTabController::Detach() {
}
// Create the dragged view.
- EnsureDraggedView();
+ EnsureDraggedView(tab_data);
view_->Attach(attached_tab_->width());
view_->Detach(photobooth_.get());
@@ -896,14 +898,14 @@ int DraggedTabController::GetInsertionIndexForDraggedBounds(
}
if (index == -1) {
if (adjusted_bounds.right() > right_tab_x)
- index = attached_tabstrip_->model()->count();
+ index = GetModel(attached_tabstrip_)->count();
else
index = 0;
}
- index = attached_tabstrip_->model()->ConstrainInsertionIndex(index, mini_);
+ index = GetModel(attached_tabstrip_)->ConstrainInsertionIndex(index, mini_);
if (is_tab_attached && mini_ &&
- index == attached_tabstrip_->model()->IndexOfFirstNonMiniTab()) {
+ index == GetModel(attached_tabstrip_)->IndexOfFirstNonMiniTab()) {
index--;
}
return index;
@@ -950,7 +952,7 @@ gfx::Point DraggedTabController::GetAttachedTabDragPoint(
Tab* DraggedTabController::GetTabMatchingDraggedContents(
TabStrip* tabstrip) const {
- int model_index = tabstrip->model()->GetIndexOfTabContents(dragged_contents_);
+ int model_index = GetModel(tabstrip)->GetIndexOfTabContents(dragged_contents_);
return model_index == TabStripModel::kNoTab ?
NULL : tabstrip->GetTabAtModelIndex(model_index);
}
@@ -1011,22 +1013,22 @@ void DraggedTabController::RevertDrag() {
// We save this here because code below will modify |attached_tabstrip_|.
bool restore_frame = attached_tabstrip_ != source_tabstrip_;
if (attached_tabstrip_) {
- int index = attached_tabstrip_->model()->GetIndexOfTabContents(
+ int index = GetModel(attached_tabstrip_)->GetIndexOfTabContents(
dragged_contents_);
if (attached_tabstrip_ != source_tabstrip_) {
// The Tab was inserted into another TabStrip. We need to put it back
// into the original one.
- attached_tabstrip_->model()->DetachTabContentsAt(index);
+ GetModel(attached_tabstrip_)->DetachTabContentsAt(index);
// TODO(beng): (Cleanup) seems like we should use Attach() for this
// somehow.
attached_tabstrip_ = source_tabstrip_;
- source_tabstrip_->model()->InsertTabContentsAt(source_model_index_,
+ GetModel(source_tabstrip_)->InsertTabContentsAt(source_model_index_,
dragged_contents_, true, false, pinned_);
} else {
// The Tab was moved within the TabStrip where the drag was initiated.
// Move it back to the starting location.
source_tabstrip_->StoppedDraggingTab(attached_tab_);
- source_tabstrip_->model()->MoveTabContentsAt(index, source_model_index_,
+ GetModel(source_tabstrip_)->MoveTabContentsAt(index, source_model_index_,
true);
}
} else {
@@ -1036,7 +1038,7 @@ void DraggedTabController::RevertDrag() {
// The Tab was detached from the TabStrip where the drag began, and has not
// been attached to any other TabStrip. We need to put it back into the
// source TabStrip.
- source_tabstrip_->model()->InsertTabContentsAt(source_model_index_,
+ GetModel(source_tabstrip_)->InsertTabContentsAt(source_model_index_,
dragged_contents_, true, false, pinned_);
}
@@ -1063,47 +1065,48 @@ void DraggedTabController::CompleteDrag() {
attached_tabstrip_->StoppedDraggingTab(attached_tab_);
} else {
if (dock_info_.type() != DockInfo::NONE) {
+ Profile* profile = GetModel(source_tabstrip_)->profile();
switch (dock_info_.type()) {
case DockInfo::LEFT_OF_WINDOW:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Left"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::RIGHT_OF_WINDOW:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Right"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::BOTTOM_OF_WINDOW:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Bottom"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::TOP_OF_WINDOW:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Top"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::MAXIMIZE:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Maximize"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::LEFT_HALF:
UserMetrics::RecordAction(UserMetricsAction("DockingWindow_LeftHalf"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::RIGHT_HALF:
UserMetrics::RecordAction(
UserMetricsAction("DockingWindow_RightHalf"),
- source_tabstrip_->model()->profile());
+ profile);
break;
case DockInfo::BOTTOM_HALF:
UserMetrics::RecordAction(
UserMetricsAction("DockingWindow_BottomHalf"),
- source_tabstrip_->model()->profile());
+ profile);
break;
default:
@@ -1126,7 +1129,7 @@ void DraggedTabController::CompleteDrag() {
window_bounds.set_x(window_bounds.x() - window_bounds.width());
}
Browser* new_browser =
- source_tabstrip_->model()->delegate()->CreateNewStripWithContents(
+ GetModel(source_tabstrip_)->delegate()->CreateNewStripWithContents(
dragged_contents_, window_bounds, dock_info_);
TabStripModel* new_model = new_browser->tabstrip_model();
new_model->SetTabPinned(new_model->GetIndexOfTabContents(dragged_contents_),
@@ -1137,13 +1140,12 @@ void DraggedTabController::CompleteDrag() {
CleanUpHiddenFrame();
}
-void DraggedTabController::EnsureDraggedView() {
+void DraggedTabController::EnsureDraggedView(const TabRendererData& data) {
if (!view_.get()) {
gfx::Rect tab_bounds;
dragged_contents_->GetContainerBounds(&tab_bounds);
- TabRenderer* renderer = new TabRenderer();
- renderer->UpdateData(dragged_contents_, false, false);
- renderer->set_mini(mini_);
+ BaseTabRenderer* renderer = source_tabstrip_->CreateTabForDragging();
+ renderer->SetData(data);
// DraggedTabView takes ownership of renderer.
view_.reset(new DraggedTabView(renderer, mouse_offset_,
tab_bounds.size(),
@@ -1172,7 +1174,7 @@ gfx::Rect DraggedTabController::GetViewScreenBounds(views::View* view) const {
int DraggedTabController::NormalizeIndexToAttachedTabStrip(int index) const {
DCHECK(attached_tabstrip_) << "Can only be called when attached!";
- TabStripModel* attached_model = attached_tabstrip_->model();
+ TabStripModel* attached_model = GetModel(attached_tabstrip_);
if (index >= attached_model->count())
return attached_model->count() - 1;
if (index == TabStripModel::kNoTab)
@@ -1201,8 +1203,8 @@ void DraggedTabController::HideFrame() {
void DraggedTabController::CleanUpHiddenFrame() {
// If the model we started dragging from is now empty, we must ask the
// delegate to close the frame.
- if (!source_tabstrip_->model()->HasNonPhantomTabs())
- source_tabstrip_->model()->delegate()->CloseFrameAfterDragSession();
+ if (!GetModel(source_tabstrip_)->HasNonPhantomTabs())
+ GetModel(source_tabstrip_)->delegate()->CloseFrameAfterDragSession();
}
void DraggedTabController::DockDisplayerDestroyed(
@@ -1248,3 +1250,8 @@ void DraggedTabController::BringWindowUnderMouseToFront() {
#endif
}
}
+
+TabStripModel* DraggedTabController::GetModel(BaseTabStrip* tabstrip) const {
+ return static_cast<BrowserTabStripController*>(tabstrip->controller())->
+ model();
+}
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.h b/chrome/browser/views/tabs/dragged_tab_controller.h
index 4e68605..f4aca80 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.h
+++ b/chrome/browser/views/tabs/dragged_tab_controller.h
@@ -15,10 +15,14 @@
namespace views {
class View;
}
+class BaseTabStrip;
class DraggedTabView;
class NativeViewPhotobooth;
class Tab;
class TabStrip;
+class TabStripModel;
+
+struct TabRendererData;
///////////////////////////////////////////////////////////////////////////////
//
@@ -199,7 +203,7 @@ class DraggedTabController : public TabContentsDelegate,
void CompleteDrag();
// Create the DraggedTabView, if it does not yet exist.
- void EnsureDraggedView();
+ void EnsureDraggedView(const TabRendererData& data);
// Utility for getting the mouse position in screen coordinates.
gfx::Point GetCursorScreenPoint() const;
@@ -222,6 +226,9 @@ class DraggedTabController : public TabContentsDelegate,
void BringWindowUnderMouseToFront();
+ // Returns the TabStripModel for the specified tabstrip.
+ TabStripModel* GetModel(BaseTabStrip* tabstrip) const;
+
// Handles registering for notifications.
NotificationRegistrar registrar_;
diff --git a/chrome/browser/views/tabs/side_tab.cc b/chrome/browser/views/tabs/side_tab.cc
index 54795fb..c134b59 100644
--- a/chrome/browser/views/tabs/side_tab.cc
+++ b/chrome/browser/views/tabs/side_tab.cc
@@ -41,10 +41,9 @@ SkBitmap* SideTab::close_button_p_ = NULL;
////////////////////////////////////////////////////////////////////////////////
// SideTab, public:
-SideTab::SideTab(SideTabModel* model)
- : model_(model),
+SideTab::SideTab(TabController* controller)
+ : BaseTabRenderer(controller),
close_button_(NULL),
- current_state_(SideTabStripModel::NetworkState_None),
loading_animation_frame_(0) {
InitClass();
@@ -64,31 +63,6 @@ SideTab::SideTab(SideTabModel* model)
SideTab::~SideTab() {
}
-void SideTab::SetNetworkState(SideTabStripModel::NetworkState state) {
- if (current_state_ != state) {
- // The waiting animation is the reverse of the loading animation, but at a
- // different rate - the following reverses and scales the animation_frame_
- // so that the frame is at an equivalent position when going from one
- // animation to the other.
- if (current_state_ == SideTabStripModel::NetworkState_Waiting &&
- current_state_ == SideTabStripModel::NetworkState_Loading) {
- loading_animation_frame_ = loading_animation_frame_count -
- (loading_animation_frame_ / waiting_to_loading_frame_count_ratio);
- }
- current_state_ = state;
- }
-
- if (current_state_ != SideTabStripModel::NetworkState_None) {
- loading_animation_frame_ = ++loading_animation_frame_ %
- ((current_state_ == SideTabStripModel::NetworkState_Waiting) ?
- waiting_animation_frame_count :
- loading_animation_frame_count);
- } else {
- loading_animation_frame_ = 0;
- }
- SchedulePaint();
-}
-
////////////////////////////////////////////////////////////////////////////////
// SideTab, AnimationDelegate implementation:
@@ -109,7 +83,7 @@ void SideTab::AnimationEnded(const Animation* animation) {
void SideTab::ButtonPressed(views::Button* sender, const views::Event& event) {
DCHECK(sender == close_button_);
- model_->CloseTab(this);
+ controller()->CloseTab(this);
}
////////////////////////////////////////////////////////////////////////////////
@@ -118,7 +92,7 @@ void SideTab::ButtonPressed(views::Button* sender, const views::Event& event) {
void SideTab::ShowContextMenu(views::View* source,
const gfx::Point& p,
bool is_mouse_gesture) {
- model_->ShowContextMenu(this, p);
+ controller()->ShowContextMenu(this, p);
}
////////////////////////////////////////////////////////////////////////////////
@@ -155,11 +129,11 @@ void SideTab::Paint(gfx::Canvas* canvas) {
canvas->drawPath(tab_shape, paint);
PaintIcon(canvas);
- canvas->DrawStringInt(UTF16ToWideHack(model_->GetTitle(this)), *font_,
+ canvas->DrawStringInt(UTF16ToWideHack(data().title), *font_,
SK_ColorBLACK, title_bounds_.x(), title_bounds_.y(),
title_bounds_.width(), title_bounds_.height());
- if (!model_->IsSelected(this) &&
+ if (!controller()->IsTabSelected(this) &&
GetThemeProvider()->ShouldUseNativeFrame()) {
// Make sure un-selected tabs are somewhat transparent.
SkPaint paint;
@@ -192,10 +166,33 @@ void SideTab::OnMouseExited(const views::MouseEvent& event) {
bool SideTab::OnMousePressed(const views::MouseEvent& event) {
if (event.IsOnlyLeftMouseButton())
- model_->SelectTab(this);
+ controller()->SelectTab(this);
return true;
}
+// TODO(sky): refactor to BaseTabRenderer.
+void SideTab::AdvanceLoadingAnimation(TabRendererData::NetworkState state) {
+ // The waiting animation is the reverse of the loading animation, but at a
+ // different rate - the following reverses and scales the animation_frame_
+ // so that the frame is at an equivalent position when going from one
+ // animation to the other.
+ if (state == TabRendererData::NETWORK_STATE_WAITING &&
+ state == TabRendererData::NETWORK_STATE_LOADING) {
+ loading_animation_frame_ = loading_animation_frame_count -
+ (loading_animation_frame_ / waiting_to_loading_frame_count_ratio);
+ }
+
+ if (state != TabRendererData::NETWORK_STATE_NONE) {
+ loading_animation_frame_ = ++loading_animation_frame_ %
+ ((state == TabRendererData::NETWORK_STATE_WAITING) ?
+ waiting_animation_frame_count :
+ loading_animation_frame_count);
+ } else {
+ loading_animation_frame_ = 0;
+ }
+ SchedulePaint();
+}
+
////////////////////////////////////////////////////////////////////////////////
// SideTab, private:
@@ -219,8 +216,8 @@ void SideTab::FillTabShapePath(gfx::Path* path) {
}
void SideTab::PaintIcon(gfx::Canvas* canvas) {
- if (current_state_ == SideTabStripModel::NetworkState_None) {
- canvas->DrawBitmapInt(model_->GetIcon(this), 0, 0, kIconSize, kIconSize,
+ if (data().network_state == TabRendererData::NETWORK_STATE_NONE) {
+ canvas->DrawBitmapInt(data().favicon, 0, 0, kIconSize, kIconSize,
icon_bounds_.x(), icon_bounds_.y(),
icon_bounds_.width(), icon_bounds_.height(), false);
} else {
@@ -230,7 +227,7 @@ void SideTab::PaintIcon(gfx::Canvas* canvas) {
void SideTab::PaintLoadingAnimation(gfx::Canvas* canvas) {
SkBitmap* frames =
- (current_state_ == SideTabStripModel::NetworkState_Waiting) ?
+ (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
waiting_animation_frames : loading_animation_frames;
int image_size = frames->height();
int image_offset = loading_animation_frame_ * image_size;
diff --git a/chrome/browser/views/tabs/side_tab.h b/chrome/browser/views/tabs/side_tab.h
index 7c0e9d6..79fbac8 100644
--- a/chrome/browser/views/tabs/side_tab.h
+++ b/chrome/browser/views/tabs/side_tab.h
@@ -6,44 +6,22 @@
#define CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_H_
#include "app/slide_animation.h"
-#include "chrome/browser/views/tabs/side_tab_strip_model.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+#include "chrome/browser/views/tabs/base_tab_renderer.h"
#include "gfx/font.h"
#include "views/controls/button/button.h"
#include "views/view.h"
class SideTab;
+class TabStripController;
-class SideTabModel {
- public:
- // Returns metadata about the specified |tab|.
- virtual string16 GetTitle(SideTab* tab) const = 0;
- virtual SkBitmap GetIcon(SideTab* tab) const = 0;
- virtual bool IsSelected(SideTab* tab) const = 0;
-
- // Selects the tab.
- virtual void SelectTab(SideTab* tab) = 0;
-
- // Closes the tab.
- virtual void CloseTab(SideTab* tab) = 0;
-
- // Shows a context menu for the tab at the specified point in screen coords.
- virtual void ShowContextMenu(SideTab* tab, const gfx::Point& p) = 0;
-};
-
-class SideTab : public views::View,
+class SideTab : public BaseTabRenderer,
public views::ContextMenuController,
public views::ButtonListener,
public AnimationDelegate {
public:
- explicit SideTab(SideTabModel* model);
+ explicit SideTab(TabController* controller);
virtual ~SideTab();
- // Sets the current network state of the tab. The tab renders different
- // animations in place of the icon when different types of network activity
- // are occurring.
- void SetNetworkState(SideTabStripModel::NetworkState state);
-
// AnimationDelegate implementation:
virtual void AnimationProgressed(const Animation* animation);
virtual void AnimationCanceled(const Animation* animation);
@@ -65,6 +43,10 @@ class SideTab : public views::View,
virtual void OnMouseExited(const views::MouseEvent& event);
virtual bool OnMousePressed(const views::MouseEvent& event);
+ protected:
+ // BaseTabRenderer overrides.
+ virtual void AdvanceLoadingAnimation(TabRendererData::NetworkState state);
+
private:
void FillTabShapePath(gfx::Path* path);
@@ -75,8 +57,6 @@ class SideTab : public views::View,
// Loads class-specific resources.
static void InitClass();
- SideTabModel* model_;
-
gfx::Rect icon_bounds_;
gfx::Rect title_bounds_;
@@ -91,9 +71,6 @@ class SideTab : public views::View,
static SkBitmap* close_button_h_;
static SkBitmap* close_button_p_;
- // The current network state for this tab.
- SideTabStripModel::NetworkState current_state_;
-
// The current index into the Animation image strip.
int loading_animation_frame_;
diff --git a/chrome/browser/views/tabs/side_tab_strip.cc b/chrome/browser/views/tabs/side_tab_strip.cc
index c7a343c..41dbc53 100644
--- a/chrome/browser/views/tabs/side_tab_strip.cc
+++ b/chrome/browser/views/tabs/side_tab_strip.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/views/tabs/side_tab_strip.h"
+#include "chrome/browser/views/tabs/side_tab.h"
#include "chrome/browser/view_ids.h"
namespace {
@@ -15,99 +16,107 @@ const int kTabStripInset = 3;
////////////////////////////////////////////////////////////////////////////////
// SideTabStrip, public:
-SideTabStrip::SideTabStrip() {
+SideTabStrip::SideTabStrip(TabStripController* controller)
+ : BaseTabStrip(controller) {
SetID(VIEW_ID_TAB_STRIP);
}
SideTabStrip::~SideTabStrip() {
}
-void SideTabStrip::SetModel(SideTabStripModel* model) {
- model_.reset(model);
+////////////////////////////////////////////////////////////////////////////////
+// SideTabStrip, BaseTabStrip implementation:
+
+int SideTabStrip::GetPreferredHeight() {
+ return 0;
}
-void SideTabStrip::AddTabAt(int index) {
- SideTab* tab = new SideTab(this);
- AddChildView(tab);
- Layout();
+void SideTabStrip::SetBackgroundOffset(const gfx::Point& offset) {
}
-void SideTabStrip::RemoveTabAt(int index) {
- View* v = GetChildViewAt(index);
- RemoveChildView(v);
- delete v;
- Layout();
+bool SideTabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
+ return GetViewForPoint(point) == this;
}
-void SideTabStrip::SelectTabAt(int index) {
- GetChildViewAt(index)->SchedulePaint();
+void SideTabStrip::SetDraggedTabBounds(int tab_index,
+ const gfx::Rect& tab_bounds) {
}
-void SideTabStrip::UpdateTabAt(int index) {
- GetChildViewAt(index)->SchedulePaint();
+bool SideTabStrip::IsDragSessionActive() const {
+ return false;
}
-////////////////////////////////////////////////////////////////////////////////
-// SideTabStrip, SideTabModel implementation:
+bool SideTabStrip::IsAnimating() const {
+ return false;
+}
-string16 SideTabStrip::GetTitle(SideTab* tab) const {
- return model_->GetTitle(GetIndexOfSideTab(tab));
+TabStrip* SideTabStrip::AsTabStrip() {
+ return NULL;
}
-SkBitmap SideTabStrip::GetIcon(SideTab* tab) const {
- return model_->GetIcon(GetIndexOfSideTab(tab));
+void SideTabStrip::StartHighlight(int model_index) {
}
-bool SideTabStrip::IsSelected(SideTab* tab) const {
- return model_->IsSelected(GetIndexOfSideTab(tab));
+void SideTabStrip::StopAllHighlighting() {
}
-void SideTabStrip::SelectTab(SideTab* tab) {
- model_->SelectTab(GetIndexOfSideTab(tab));
+BaseTabRenderer* SideTabStrip::GetBaseTabAtModelIndex(int model_index) const {
+ return static_cast<BaseTabRenderer*>(GetChildViewAt(model_index));
}
-void SideTabStrip::CloseTab(SideTab* tab) {
- model_->CloseTab(GetIndexOfSideTab(tab));
+BaseTabRenderer* SideTabStrip::GetBaseTabAtTabIndex(int tab_index) const {
+ return static_cast<BaseTabRenderer*>(GetChildViewAt(tab_index));
}
-void SideTabStrip::ShowContextMenu(SideTab* tab, const gfx::Point& p) {
- model_->ShowContextMenu(GetIndexOfSideTab(tab), p);
+int SideTabStrip::GetTabCount() const {
+ return GetChildViewCount();
}
-////////////////////////////////////////////////////////////////////////////////
-// SideTabStrip, BaseTabStrip implementation:
+BaseTabRenderer* SideTabStrip::CreateTabForDragging() {
+ return new SideTab(NULL);
+}
-int SideTabStrip::GetPreferredHeight() {
- return 0;
+int SideTabStrip::GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const {
+ return GetChildIndex(tab);
}
-void SideTabStrip::SetBackgroundOffset(const gfx::Point& offset) {
+void SideTabStrip::AddTabAt(int model_index,
+ bool foreground,
+ const TabRendererData& data) {
+ SideTab* tab = new SideTab(this);
+ AddChildView(tab);
+ Layout();
}
-bool SideTabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
- return GetViewForPoint(point) == this;
+void SideTabStrip::RemoveTabAt(int index) {
+ View* v = GetChildViewAt(index);
+ RemoveChildView(v);
+ delete v;
+ Layout();
}
-void SideTabStrip::SetDraggedTabBounds(int tab_index,
- const gfx::Rect& tab_bounds) {
+void SideTabStrip::SelectTabAt(int old_model_index, int new_model_index) {
+ GetChildViewAt(new_model_index)->SchedulePaint();
}
-bool SideTabStrip::IsDragSessionActive() const {
- return false;
+void SideTabStrip::MoveTab(int from_model_index, int to_model_index) {
}
-void SideTabStrip::UpdateLoadingAnimations() {
- int count = GetChildViewCount();
- for (int i = 0; i < count; ++i)
- GetSideTabAt(i)->SetNetworkState(model_->GetNetworkState(i));
+void SideTabStrip::TabTitleChangedNotLoading(int model_index) {
}
-bool SideTabStrip::IsAnimating() const {
- return false;
+void SideTabStrip::SetTabData(int model_index, const TabRendererData& data) {
}
-TabStrip* SideTabStrip::AsTabStrip() {
- return NULL;
+void SideTabStrip::MaybeStartDrag(BaseTabRenderer* tab,
+ const views::MouseEvent& event) {
+}
+
+void SideTabStrip::ContinueDrag(const views::MouseEvent& event) {
+}
+
+bool SideTabStrip::EndDrag(bool canceled) {
+ return false;
}
////////////////////////////////////////////////////////////////////////////////
@@ -128,14 +137,3 @@ void SideTabStrip::Layout() {
gfx::Size SideTabStrip::GetPreferredSize() {
return gfx::Size(kTabStripWidth, 0);
}
-
-////////////////////////////////////////////////////////////////////////////////
-// SideTabStrip, private:
-
-int SideTabStrip::GetIndexOfSideTab(SideTab* tab) const {
- return GetChildIndex(tab);
-}
-
-SideTab* SideTabStrip::GetSideTabAt(int index) const {
- return static_cast<SideTab*>(GetChildViewAt(index));
-}
diff --git a/chrome/browser/views/tabs/side_tab_strip.h b/chrome/browser/views/tabs/side_tab_strip.h
index 558d1a1..892004d 100644
--- a/chrome/browser/views/tabs/side_tab_strip.h
+++ b/chrome/browser/views/tabs/side_tab_strip.h
@@ -5,43 +5,15 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_H_
#define CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_H_
-#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
-#include "chrome/browser/views/tabs/side_tab.h"
-class Profile;
-class SideTabStripModel;
+struct TabRendererData;
-class SideTabStrip : public BaseTabStrip,
- public SideTabModel {
+class SideTabStrip : public BaseTabStrip {
public:
- SideTabStrip();
+ explicit SideTabStrip(TabStripController* controller);
virtual ~SideTabStrip();
- // Associate a model with this SideTabStrip. The SideTabStrip owns its model.
- void SetModel(SideTabStripModel* model);
-
- // Notifies the SideTabStrip that a tab was added in the model at |index|.
- void AddTabAt(int index);
-
- // Notifies the SideTabStrip that a tab was removed from the model at |index|.
- void RemoveTabAt(int index);
-
- // Notifies the SideTabStrip that a tab was selected in the model at |index|.
- void SelectTabAt(int index);
-
- // Notifies the SideTabStrip that the tab at |index| needs to be redisplayed
- // since some of its metadata has changed.
- void UpdateTabAt(int index);
-
- // SideTabModel implementation:
- virtual string16 GetTitle(SideTab* tab) const;
- virtual SkBitmap GetIcon(SideTab* tab) const;
- virtual bool IsSelected(SideTab* tab) const;
- virtual void SelectTab(SideTab* tab);
- virtual void CloseTab(SideTab* tab);
- virtual void ShowContextMenu(SideTab* tab, const gfx::Point& p);
-
// BaseTabStrip implementation:
virtual int GetPreferredHeight();
virtual void SetBackgroundOffset(const gfx::Point& offset);
@@ -49,23 +21,34 @@ class SideTabStrip : public BaseTabStrip,
virtual void SetDraggedTabBounds(int tab_index,
const gfx::Rect& tab_bounds);
virtual bool IsDragSessionActive() const;
- virtual void UpdateLoadingAnimations();
virtual bool IsAnimating() const;
virtual TabStrip* AsTabStrip();
+ virtual void StartHighlight(int model_index);
+ virtual void StopAllHighlighting();
+ virtual BaseTabRenderer* GetBaseTabAtModelIndex(int model_index) const;
+ virtual BaseTabRenderer* GetBaseTabAtTabIndex(int tab_index) const;
+ virtual int GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const;
+ virtual int GetTabCount() const;
+ virtual BaseTabRenderer* CreateTabForDragging();
+ virtual void AddTabAt(int model_index,
+ bool foreground,
+ const TabRendererData& data);
+ virtual void RemoveTabAt(int model_index);
+ virtual void SelectTabAt(int old_model_index, int new_model_index);
+ virtual void MoveTab(int from_model_index, int to_model_index);
+ virtual void TabTitleChangedNotLoading(int model_index);
+ virtual void SetTabData(int model_index, const TabRendererData& data);
+ virtual void MaybeStartDrag(BaseTabRenderer* tab,
+ const views::MouseEvent& event);
+ virtual void ContinueDrag(const views::MouseEvent& event);
+ virtual bool EndDrag(bool canceled);
+
// views::View overrides:
virtual void Layout();
virtual gfx::Size GetPreferredSize();
private:
- // Returns the model index of the specified |tab|.
- int GetIndexOfSideTab(SideTab* tab) const;
-
- // Returns the SideTab at the specified |index|.
- SideTab* GetSideTabAt(int index) const;
-
- scoped_ptr<SideTabStripModel> model_;
-
DISALLOW_COPY_AND_ASSIGN(SideTabStrip);
};
diff --git a/chrome/browser/views/tabs/side_tab_strip_model.h b/chrome/browser/views/tabs/side_tab_strip_model.h
deleted file mode 100644
index 835e5ba..0000000
--- a/chrome/browser/views/tabs/side_tab_strip_model.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_MODEL_H_
-#define CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_MODEL_H_
-
-#include "base/string16.h"
-
-namespace gfx {
-class Point;
-}
-class SkBitmap;
-
-// A model interface implemented by an object that can provide information
-// about SideTabs in a SideTabStrip.
-class SideTabStripModel {
- public:
- virtual ~SideTabStripModel() {}
-
- // Returns metadata about the tab at the specified index.
- virtual SkBitmap GetIcon(int index) const = 0;
- virtual string16 GetTitle(int index) const = 0;
- virtual bool IsSelected(int index) const = 0;
-
- // Different types of network activity for a tab. The NetworkState of a tab
- // may be used to alter the UI (e.g. show different kinds of loading
- // animations).
- enum NetworkState {
- NetworkState_None, // no network activity.
- NetworkState_Waiting, // waiting for a connection.
- NetworkState_Loading // connected, transferring data.
- };
-
- // Returns the NetworkState of the tab at the specified index.
- virtual NetworkState GetNetworkState(int index) const = 0;
-
- // Select the tab at the specified index in the model.
- virtual void SelectTab(int index) = 0;
-
- // Closes the tab at the specified index in the model.
- virtual void CloseTab(int index) = 0;
-
- // Shows a context menu for the tab at the specified index at the specified
- // point in screen coords.
- virtual void ShowContextMenu(int index, const gfx::Point& p) = 0;
-};
-
-#endif // CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_MODEL_H_
-
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index 03487a9..8a7b731 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -26,87 +26,11 @@ static const SkScalar kTabCapWidth = 15;
static const SkScalar kTabTopCurveWidth = 4;
static const SkScalar kTabBottomCurveWidth = 3;
-class Tab::TabContextMenuContents : public menus::SimpleMenuModel::Delegate {
- public:
- explicit TabContextMenuContents(Tab* tab)
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- model_(this, tab->delegate()->IsTabPinned(tab))),
- tab_(tab),
- last_command_(TabStripModel::CommandFirst) {
- Build();
- }
- virtual ~TabContextMenuContents() {
- menu_->CancelMenu();
- tab_->delegate()->StopAllHighlighting();
- }
-
- void RunMenuAt(const gfx::Point& point) {
- // Save a pointer to delegate before we call RunMenuAt, because it runs a
- // nested message loop that may not return until after we are deleted.
- Tab::TabDelegate* delegate = tab_->delegate();
- menu_->RunMenuAt(point, views::Menu2::ALIGN_TOPLEFT);
- // We could be gone now. Assume |this| is junk!
- if (delegate)
- delegate->StopAllHighlighting();
- }
-
- // Overridden from menus::SimpleMenuModel::Delegate:
- virtual bool IsCommandIdChecked(int command_id) const {
- return tab_ && tab_->delegate()->IsCommandCheckedForTab(
- static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_);
- }
- virtual bool IsCommandIdEnabled(int command_id) const {
- return tab_ && tab_->delegate()->IsCommandEnabledForTab(
- static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_);
- }
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) {
- return tab_->GetWidget()->GetAccelerator(command_id, accelerator);
- }
- virtual void CommandIdHighlighted(int command_id) {
- if (!tab_)
- return;
-
- tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
- last_command_ = static_cast<TabStripModel::ContextMenuCommand>(command_id);
- tab_->delegate()->StartHighlightTabsForCommand(last_command_, tab_);
- }
- virtual void ExecuteCommand(int command_id) {
- if (!tab_)
- return;
- tab_->delegate()->ExecuteCommandForTab(
- static_cast<TabStripModel::ContextMenuCommand>(command_id),
- tab_);
- }
-
- private:
- void Build() {
- menu_.reset(new views::Menu2(&model_));
- }
-
- TabMenuModel model_;
- scoped_ptr<views::Menu2> menu_;
-
- // The Tab the context menu was brought up for. Set to NULL when the menu
- // is canceled.
- Tab* tab_;
-
- // The last command that was selected, so that we can start/stop highlighting
- // appropriately as the user moves through the menu.
- TabStripModel::ContextMenuCommand last_command_;
-
- DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents);
-};
-
///////////////////////////////////////////////////////////////////////////////
// Tab, public:
-Tab::Tab(TabDelegate* delegate)
- : TabRenderer(),
- delegate_(delegate),
+Tab::Tab(TabController* controller)
+ : TabRenderer(controller),
closing_(false),
dragging_(false) {
close_button()->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_CLOSE_TAB));
@@ -122,7 +46,7 @@ Tab::~Tab() {
// Tab, TabRenderer overrides:
bool Tab::IsSelected() const {
- return delegate_->IsTabSelected(this);
+ return controller() ? controller()->IsTabSelected(this) : true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -143,15 +67,15 @@ bool Tab::OnMousePressed(const views::MouseEvent& event) {
// it was in the background.
bool just_selected = !IsSelected();
if (just_selected) {
- delegate_->SelectTab(this);
+ controller()->SelectTab(this);
}
- delegate_->MaybeStartDrag(this, event);
+ controller()->MaybeStartDrag(this, event);
}
return true;
}
bool Tab::OnMouseDragged(const views::MouseEvent& event) {
- delegate_->ContinueDrag(event);
+ controller()->ContinueDrag(event);
return true;
}
@@ -161,14 +85,14 @@ void Tab::OnMouseReleased(const views::MouseEvent& event, bool canceled) {
// In some cases, ending the drag will schedule the tab for destruction; if
// so, bail immediately, since our members are already dead and we shouldn't
// do anything else except drop the tab where it is.
- if (delegate_->EndDrag(canceled))
+ if (controller()->EndDrag(canceled))
return;
// Close tab on middle click, but only if the button is released over the tab
// (normal windows behavior is to discard presses of a UI element where the
// releases happen off the element).
if (event.IsMiddleMouseButton() && HitTest(event.location()))
- delegate_->CloseTab(this);
+ controller()->CloseTab(this);
}
bool Tab::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
@@ -204,8 +128,7 @@ bool Tab::GetAccessibleRole(AccessibilityTypes::Role* role) {
void Tab::ShowContextMenu(views::View* source,
const gfx::Point& p,
bool is_mouse_gesture) {
- context_menu_contents_.reset(new TabContextMenuContents(this));
- context_menu_contents_->RunMenuAt(p);
+ controller()->ShowContextMenu(this, p);
}
///////////////////////////////////////////////////////////////////////////////
@@ -213,7 +136,7 @@ void Tab::ShowContextMenu(views::View* source,
void Tab::ButtonPressed(views::Button* sender, const views::Event& event) {
if (sender == close_button())
- delegate_->CloseTab(this);
+ controller()->CloseTab(this);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h
index af7eb20..e5ab9b9 100644
--- a/chrome/browser/views/tabs/tab.h
+++ b/chrome/browser/views/tabs/tab.h
@@ -25,67 +25,9 @@ class Tab : public TabRenderer,
public:
static const std::string kTabClassName;
- // An interface implemented by an object that can help this Tab complete
- // various actions. The index parameter is the index of this Tab in the
- // TabRenderer::Model.
- class TabDelegate {
- public:
- // Returns true if the specified Tab is selected.
- virtual bool IsTabSelected(const Tab* tab) const = 0;
-
- // Returns true if the specified Tab is pinned.
- virtual bool IsTabPinned(const Tab* tab) const = 0;
-
- // Selects the specified Tab.
- virtual void SelectTab(Tab* tab) = 0;
-
- // Closes the specified Tab.
- virtual void CloseTab(Tab* tab) = 0;
-
- // Returns true if the specified command is enabled for the specified Tab.
- virtual bool IsCommandEnabledForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const = 0;
-
- // Returns true if the specified command is checked for the specified Tab.
- virtual bool IsCommandCheckedForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const = 0;
-
- // Executes the specified command for the specified Tab.
- virtual void ExecuteCommandForTab(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
-
- // Starts/Stops highlighting the tabs that will be affected by the
- // specified command for the specified Tab.
- virtual void StartHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
- virtual void StopHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
- virtual void StopAllHighlighting() = 0;
-
- // Potentially starts a drag for the specified Tab.
- virtual void MaybeStartDrag(Tab* tab, const views::MouseEvent& event) = 0;
-
- // Continues dragging a Tab.
- virtual void ContinueDrag(const views::MouseEvent& event) = 0;
-
- // Ends dragging a Tab. |canceled| is true if the drag was aborted in a way
- // other than the user releasing the mouse. Returns whether the tab has been
- // destroyed.
- virtual bool EndDrag(bool canceled) = 0;
-
- // Returns true if the associated TabStrip's delegate supports tab moving or
- // detaching. Used by the Frame to determine if dragging on the Tab
- // itself should move the window in cases where there's only one
- // non drag-able Tab.
- virtual bool HasAvailableDragActions() const = 0;
- };
-
- explicit Tab(TabDelegate* delegate);
+ explicit Tab(TabController* controller);
virtual ~Tab();
- // Access the delegate.
- TabDelegate* delegate() const { return delegate_; }
-
// Used to set/check whether this Tab is being animated closed.
void set_closing(bool closing) { closing_ = closing; }
bool closing() const { return closing_; }
@@ -122,20 +64,12 @@ class Tab : public TabRenderer,
// representation. Used by GetViewForPoint for hit-testing.
void MakePathForTab(gfx::Path* path) const;
- // An instance of a delegate object that can perform various actions based on
- // user gestures.
- TabDelegate* delegate_;
-
// True if the tab is being animated closed.
bool closing_;
// True if the tab is being dragged.
bool dragging_;
- // If non-null it means we're showing a menu for the tab.
- class TabContextMenuContents;
- scoped_ptr<TabContextMenuContents> context_menu_contents_;
-
DISALLOW_COPY_AND_ASSIGN(Tab);
};
diff --git a/chrome/browser/views/tabs/tab_renderer.cc b/chrome/browser/views/tabs/tab_renderer.cc
index ccf39ca..f32d718 100644
--- a/chrome/browser/views/tabs/tab_renderer.cc
+++ b/chrome/browser/views/tabs/tab_renderer.cc
@@ -17,9 +17,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "gfx/canvas.h"
#include "gfx/favicon_size.h"
@@ -270,14 +268,17 @@ class TabRenderer::FavIconCrashAnimation : public LinearAnimation,
////////////////////////////////////////////////////////////////////////////////
// TabRenderer, public:
-TabRenderer::TabRenderer()
- : animation_state_(ANIMATION_NONE),
+TabRenderer::TabRenderer(TabController* controller)
+ : BaseTabRenderer(controller),
animation_frame_(0),
throbber_disabled_(false),
showing_icon_(false),
showing_close_button_(false),
fav_icon_hiding_offset_(0),
close_button_color_(NULL),
+ render_as_new_tab_(false),
+ render_unselected_(false),
+ alpha_(1),
crash_animation_(NULL),
should_display_crashed_favicon_(false),
theme_provider_(NULL) {
@@ -321,96 +322,10 @@ ThemeProvider* TabRenderer::GetThemeProvider() {
return NULL;
}
-void TabRenderer::UpdateData(TabContents* contents,
- bool phantom,
- bool loading_only) {
- DCHECK(contents);
- if (data_.phantom != phantom || !loading_only) {
- data_.title = contents->GetTitle();
- data_.off_the_record = contents->profile()->IsOffTheRecord();
- data_.crashed = contents->is_crashed();
- data_.app = contents->is_app();
- SkBitmap* app_icon = contents->GetExtensionAppIcon();
- if (app_icon)
- data_.favicon = *app_icon;
- else
- data_.favicon = contents->GetFavIcon();
- data_.phantom = phantom;
- if (phantom) {
- data_.crashed = false; // Phantom tabs can never crash.
- StopMiniTabTitleAnimation();
- }
-
- // Sets the accessible name for the tab.
- SetAccessibleName(UTF16ToWide(data_.title));
- }
-
- // If this is an extension app and a command line flag is set,
- // then disable the throbber.
- throbber_disabled_ = data_.app &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsNoThrob);
-
- // TODO(glen): Temporary hax.
- theme_provider_ = contents->profile()->GetThemeProvider();
-
- // Loading state also involves whether we show the favicon, since that's where
- // we display the throbber.
- data_.loading = contents->is_loading();
- data_.show_icon = contents->ShouldDisplayFavIcon();
-}
-
-void TabRenderer::UpdateFromModel() {
- // Force a layout, since the tab may have grown a favicon.
- Layout();
- SchedulePaint();
-
- if (data_.crashed) {
- if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation())
- StartCrashAnimation();
- } else {
- if (IsPerformingCrashAnimation())
- StopCrashAnimation();
- ResetCrashedFavIcon();
- }
-}
-
-void TabRenderer::set_animating_mini_change(bool value) {
- data_.animating_mini_change = value;
-}
-
bool TabRenderer::IsSelected() const {
return true;
}
-void TabRenderer::ValidateLoadingAnimation(AnimationState animation_state) {
- if (throbber_disabled_)
- return;
-
- if (animation_state_ != animation_state) {
- // The waiting animation is the reverse of the loading animation, but at a
- // different rate - the following reverses and scales the animation_frame_
- // so that the frame is at an equivalent position when going from one
- // animation to the other.
- if (animation_state_ == ANIMATION_WAITING &&
- animation_state == ANIMATION_LOADING) {
- animation_frame_ = loading_animation_frame_count -
- (animation_frame_ / waiting_to_loading_frame_count_ratio);
- }
- animation_state_ = animation_state;
- }
-
- if (animation_state_ != ANIMATION_NONE) {
- animation_frame_ = ++animation_frame_ %
- ((animation_state_ == ANIMATION_WAITING) ?
- waiting_animation_frame_count :
- loading_animation_frame_count);
- } else {
- animation_frame_ = 0;
- }
-
- SchedulePaint();
-}
-
void TabRenderer::StartPulse() {
pulse_animation_->Reset();
pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
@@ -447,7 +362,7 @@ void TabRenderer::SetAnimationContainer(AnimationContainer* container) {
}
void TabRenderer::PaintIcon(gfx::Canvas* canvas) {
- if (animation_state_ != ANIMATION_NONE) {
+ if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
PaintLoadingAnimation(canvas);
} else {
canvas->save();
@@ -461,15 +376,15 @@ void TabRenderer::PaintIcon(gfx::Canvas* canvas) {
kFavIconSize, kFavIconSize,
true);
} else {
- if (!data_.favicon.isNull()) {
+ if (!data().favicon.isNull()) {
// TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch
// to using that class to render the favicon).
int x = favicon_bounds_.x();
int y = favicon_bounds_.y() + fav_icon_hiding_offset_;
- int size = data_.favicon.width();
- canvas->DrawBitmapInt(data_.favicon, 0, 0,
- data_.favicon.width(),
- data_.favicon.height(),
+ int size = data().favicon.width();
+ canvas->DrawBitmapInt(data().favicon, 0, 0,
+ data().favicon.width(),
+ data().favicon.height(),
x, y, size, size,
true);
}
@@ -514,7 +429,7 @@ int TabRenderer::GetMiniWidth() {
// TabRenderer, protected:
std::wstring TabRenderer::GetTitle() const {
- return UTF16ToWideHack(data_.title);
+ return UTF16ToWideHack(data().title);
}
void TabRenderer::OnMouseEntered(const views::MouseEvent& e) {
@@ -527,11 +442,66 @@ void TabRenderer::OnMouseExited(const views::MouseEvent& e) {
hover_animation_->Hide();
}
+void TabRenderer::DataChanged(const TabRendererData& old) {
+ if (data().phantom)
+ StopMiniTabTitleAnimation();
+
+ // Sets the accessible name for the tab.
+ SetAccessibleName(UTF16ToWide(data().title));
+
+ if (data().blocked != old.blocked) {
+ if (data().blocked)
+ StartPulse();
+ else
+ StopPulse();
+ }
+
+ // If this is an extension app and a command line flag is set,
+ // then disable the throbber.
+ throbber_disabled_ = data().app &&
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsNoThrob);
+
+ if (data().crashed) {
+ if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation())
+ StartCrashAnimation();
+ } else {
+ if (IsPerformingCrashAnimation())
+ StopCrashAnimation();
+ ResetCrashedFavIcon();
+ }
+}
+
+void TabRenderer::AdvanceLoadingAnimation(TabRendererData::NetworkState state) {
+ if (throbber_disabled_)
+ return;
+
+ // The waiting animation is the reverse of the loading animation, but at a
+ // different rate - the following reverses and scales the animation_frame_ so
+ // that the frame is at an equivalent position when going from one animation
+ // to the other.
+ if (state == TabRendererData::NETWORK_STATE_WAITING &&
+ state == TabRendererData::NETWORK_STATE_LOADING) {
+ animation_frame_ = loading_animation_frame_count -
+ (animation_frame_ / waiting_to_loading_frame_count_ratio);
+ }
+
+ if (state != TabRendererData::NETWORK_STATE_NONE) {
+ animation_frame_ = ++animation_frame_ %
+ ((state == TabRendererData::NETWORK_STATE_WAITING) ?
+ waiting_animation_frame_count :
+ loading_animation_frame_count);
+ } else {
+ animation_frame_ = 0;
+ }
+
+ SchedulePaint();
+}
+
////////////////////////////////////////////////////////////////////////////////
// TabRenderer, views::View overrides:
void TabRenderer::Paint(gfx::Canvas* canvas) {
- if (data_.render_as_new_tab) {
+ if (render_as_new_tab_) {
if (base::i18n::IsRTL()) {
canvas->TranslateInt(width(), 0);
canvas->ScaleInt(-1, 1);
@@ -542,11 +512,11 @@ void TabRenderer::Paint(gfx::Canvas* canvas) {
// Don't paint if we're narrower than we can render correctly. (This should
// only happen during animations).
- if (width() < GetMinimumUnselectedSize().width() && !mini())
+ if (width() < GetMinimumUnselectedSize().width() && !data().mini)
return;
// See if the model changes whether the icons should be painted.
- const bool show_icon = ShouldShowIcon() && !phantom();
+ const bool show_icon = ShouldShowIcon() && !data().phantom;
const bool show_close_button = ShouldShowCloseBox();
if (show_icon != showing_icon_ ||
show_close_button != showing_close_button_)
@@ -559,7 +529,7 @@ void TabRenderer::Paint(gfx::Canvas* canvas) {
BrowserThemeProvider::COLOR_TAB_TEXT :
BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT);
- if (!mini() || width() > kMiniTabRendererAsNormalTabWidth)
+ if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth)
PaintTitle(title_color, canvas);
if (show_icon)
@@ -589,7 +559,7 @@ void TabRenderer::Layout() {
if (showing_icon_) {
// Use the size of the favicon as apps use a bigger favicon size.
int favicon_size =
- !data_.favicon.empty() ? data_.favicon.width() : kFavIconSize;
+ !data().favicon.empty() ? data().favicon.width() : kFavIconSize;
int favicon_top = kTopPadding + content_height / 2 - favicon_size / 2;
int favicon_left = lb.x();
if (favicon_size != kFavIconSize) {
@@ -598,8 +568,7 @@ void TabRenderer::Layout() {
}
favicon_bounds_.SetRect(favicon_left, favicon_top,
favicon_size, favicon_size);
- if ((mini() || data_.animating_mini_change) &&
- width() < kMiniTabRendererAsNormalTabWidth) {
+ if (data().mini && width() < kMiniTabRendererAsNormalTabWidth) {
// Adjust the location of the favicon when transitioning from a normal
// tab to a mini-tab.
int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth();
@@ -636,7 +605,7 @@ void TabRenderer::Layout() {
int title_left = favicon_bounds_.right() + kFavIconTitleSpacing;
int title_top = kTopPadding + (content_height - title_font_height) / 2;
// Size the Title text to fill the remaining space.
- if (!mini() || width() >= kMiniTabRendererAsNormalTabWidth) {
+ if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) {
// If the user has big fonts, the title will appear rendered too far down
// on the y-axis if we use the regular top padding, so we need to adjust it
// so that the text appears centered.
@@ -694,9 +663,9 @@ void TabRenderer::AnimationEnded(const Animation* animation) {
void TabRenderer::PaintTitle(SkColor title_color, gfx::Canvas* canvas) {
// Paint the Title.
- string16 title = data_.title;
+ string16 title = data().title;
if (title.empty()) {
- title = data_.loading ?
+ title = data().loading ?
l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
TabContents::GetDefaultTitle();
} else {
@@ -787,7 +756,7 @@ void TabRenderer::PaintInactiveTabBackgroundWithTitleChange(
}
void TabRenderer::PaintInactiveTabBackground(gfx::Canvas* canvas) {
- bool is_otr = data_.off_the_record;
+ bool is_otr = data().off_the_record;
// The tab image needs to be lined up with the background image
// so that it feels partially transparent. These offsets represent the tab
@@ -807,10 +776,10 @@ void TabRenderer::PaintInactiveTabBackground(gfx::Canvas* canvas) {
SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(tab_id);
// App tabs are drawn slightly differently (as nano tabs).
- TabImage* tab_image = data_.app ? &tab_active_nano : &tab_active;
- TabImage* tab_inactive_image = data_.app ? &tab_inactive_nano :
+ TabImage* tab_image = data().app ? &tab_active_nano : &tab_active;
+ TabImage* tab_inactive_image = data().app ? &tab_inactive_nano :
&tab_inactive;
- TabImage* alpha = data_.app ? &tab_alpha_nano : &tab_alpha;
+ TabImage* alpha = data().app ? &tab_alpha_nano : &tab_alpha;
// If the theme is providing a custom background image, then its top edge
// should be at the top of the tab. Otherwise, we assume that the background
@@ -872,8 +841,8 @@ void TabRenderer::PaintActiveTabBackground(gfx::Canvas* canvas) {
SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);
// App tabs are drawn slightly differently (as nano tabs).
- TabImage* tab_image = data_.app ? &tab_active_nano : &tab_active;
- TabImage* alpha = data_.app ? &tab_alpha_nano : &tab_alpha;
+ TabImage* tab_image = data().app ? &tab_active_nano : &tab_active;
+ TabImage* alpha = data().app ? &tab_alpha_nano : &tab_alpha;
// Draw left edge.
SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
@@ -907,8 +876,9 @@ void TabRenderer::PaintActiveTabBackground(gfx::Canvas* canvas) {
}
void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) {
- SkBitmap* frames = (animation_state_ == ANIMATION_WAITING) ?
- waiting_animation_frames : loading_animation_frames;
+ SkBitmap* frames =
+ (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
+ waiting_animation_frames : loading_animation_frames;
int image_size = frames->height();
int image_offset = animation_frame_ * image_size;
int dst_y = (height() - image_size) / 2;
@@ -917,7 +887,7 @@ void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) {
// loading animation also needs to be mirrored if the View's UI layout is
// right-to-left.
int dst_x;
- if (mini()) {
+ if (data().mini) {
dst_x = favicon_bounds_.x();
if (favicon_bounds_.width() != kFavIconSize)
dst_x += (favicon_bounds_.width() - kFavIconSize) / 2;
@@ -934,7 +904,7 @@ void TabRenderer::PaintLoadingAnimation(gfx::Canvas* canvas) {
}
void TabRenderer::PaintAsNewTab(gfx::Canvas* canvas) {
- bool is_otr = data_.off_the_record;
+ bool is_otr = data().off_the_record;
// The tab image needs to be lined up with the background image
// so that it feels partially transparent. These offsets represent the tab
@@ -981,9 +951,9 @@ int TabRenderer::IconCapacity() const {
}
bool TabRenderer::ShouldShowIcon() const {
- if (mini() && height() >= GetMinimumUnselectedSize().height())
+ if (data().mini && height() >= GetMinimumUnselectedSize().height())
return true;
- if (!data_.show_icon) {
+ if (!data().show_icon) {
return false;
} else if (IsSelected()) {
// The selected tab clips favicon before close button.
@@ -995,12 +965,12 @@ bool TabRenderer::ShouldShowIcon() const {
bool TabRenderer::ShouldShowCloseBox() const {
// The selected tab never clips close button.
- return !mini() && (IsSelected() || IconCapacity() >= 3);
+ return !data().mini && (IsSelected() || IconCapacity() >= 3);
}
double TabRenderer::GetThrobValue() {
- if (data_.alpha != 1)
- return data_.alpha;
+ if (alpha_ != 1)
+ return alpha_;
if (pulse_animation_->is_animating())
return pulse_animation_->GetCurrentValue() * kHoverOpacity;
@@ -1090,13 +1060,3 @@ void TabRenderer::LoadTabImages() {
new_tab_mask = rb.GetBitmapNamed(IDR_TAB_ALPHA_NEW_TAB);
new_tab_shadow = rb.GetBitmapNamed(IDR_TAB_NEW_TAB_SHADOW);
}
-
-void TabRenderer::SetBlocked(bool blocked) {
- if (data_.blocked == blocked)
- return;
- data_.blocked = blocked;
- if (blocked)
- StartPulse();
- else
- StopPulse();
-}
diff --git a/chrome/browser/views/tabs/tab_renderer.h b/chrome/browser/views/tabs/tab_renderer.h
index 2ae8be99..7247b50 100644
--- a/chrome/browser/views/tabs/tab_renderer.h
+++ b/chrome/browser/views/tabs/tab_renderer.h
@@ -6,17 +6,14 @@
#define CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_H_
#include "app/animation.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "base/string16.h"
+#include "chrome/browser/views/tabs/base_tab_renderer.h"
#include "gfx/point.h"
#include "views/controls/button/image_button.h"
-#include "views/view.h"
class AnimationContainer;
class MultiAnimation;
class SlideAnimation;
-class TabContents;
class ThrobAnimation;
///////////////////////////////////////////////////////////////////////////////
@@ -26,18 +23,11 @@ class ThrobAnimation;
// A View that renders a Tab, either in a TabStrip or in a DraggedTabView.
//
///////////////////////////////////////////////////////////////////////////////
-class TabRenderer : public views::View,
+class TabRenderer : public BaseTabRenderer,
public views::ButtonListener,
public AnimationDelegate {
public:
- // Possible animation states.
- enum AnimationState {
- ANIMATION_NONE,
- ANIMATION_WAITING,
- ANIMATION_LOADING
- };
-
- TabRenderer();
+ explicit TabRenderer(TabController* controller);
virtual ~TabRenderer();
// Sizes the renderer to the size of the new tab images. This is used
@@ -49,53 +39,21 @@ class TabRenderer : public views::View,
void ViewHierarchyChanged(bool is_add, View* parent, View* child);
ThemeProvider* GetThemeProvider();
- // Updates the data the Tab uses to render itself from the specified
- // TabContents.
- //
- // See TabStripModel::TabChangedAt documentation for what loading_only means.
- void UpdateData(TabContents* contents, bool phantom, bool loading_only);
-
- // Sets the blocked state of the tab.
- void SetBlocked(bool blocked);
- bool blocked() const { return data_.blocked; }
-
- // Sets the mini-state of the tab.
- void set_mini(bool mini) { data_.mini = mini; }
- bool mini() const { return data_.mini; }
-
- // Sets the mini-state of the tab.
- void set_app(bool app) { data_.app = app; }
- bool app() const { return data_.app; }
-
- // Sets the phantom state of the tab.
- void set_phantom(bool phantom) { data_.phantom = phantom; }
- bool phantom() const { return data_.phantom; }
-
// Used during new tab animation to force the tab to render a new tab like
// animation.
- void set_render_as_new_tab(bool value) { data_.render_as_new_tab = value; }
+ void set_render_as_new_tab(bool value) { render_as_new_tab_ = value; }
// Sets the alpha value to render the tab at. This is used during the new
// tab animation.
- void set_alpha(double value) { data_.alpha = value; }
+ void set_alpha(double value) { alpha_ = value; }
// Forces the tab to render unselected even though it is selected.
- void set_render_unselected(bool value) { data_.render_unselected = value; }
- bool render_unselected() const { return data_.render_unselected; }
-
- // Are we in the process of animating a mini tab state change on this tab?
- void set_animating_mini_change(bool value);
-
- // Updates the display to reflect the contents of this TabRenderer's model.
- void UpdateFromModel();
+ void set_render_unselected(bool value) { render_unselected_ = value; }
+ bool render_unselected() const { return render_unselected_; }
// Returns true if the Tab is selected, false otherwise.
virtual bool IsSelected() const;
- // Advance the Loading Animation to the next frame, or hide the animation if
- // the tab isn't loading.
- void ValidateLoadingAnimation(AnimationState animation_state);
-
// Starts/Stops a pulse animation.
void StartPulse();
void StopPulse();
@@ -155,6 +113,10 @@ class TabRenderer : public views::View,
virtual void ButtonPressed(views::Button* sender,
const views::Event& event) {}
+ // BaseTabRenderer overrides:
+ virtual void DataChanged(const TabRendererData& old);
+ virtual void AdvanceLoadingAnimation(TabRendererData::NetworkState state);
+
private:
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
@@ -210,9 +172,6 @@ class TabRenderer : public views::View,
// The offset used to paint the inactive background image.
gfx::Point background_offset_;
- // Current state of the animation.
- AnimationState animation_state_;
-
// The current index into the Animation image strip.
int animation_frame_;
@@ -233,42 +192,6 @@ class TabRenderer : public views::View,
// Animation used when the title of an inactive mini tab changes.
scoped_ptr<MultiAnimation> mini_title_animation_;
- // Model data. We store this here so that we don't need to ask the underlying
- // model, which is tricky since instances of this object can outlive the
- // corresponding objects in the underlying model.
- struct TabData {
- TabData()
- : loading(false),
- crashed(false),
- off_the_record(false),
- show_icon(true),
- mini(false),
- blocked(false),
- animating_mini_change(false),
- phantom(false),
- app(false),
- render_as_new_tab(false),
- render_unselected(false),
- alpha(1) {
- }
-
- SkBitmap favicon;
- string16 title;
- bool loading;
- bool crashed;
- bool off_the_record;
- bool show_icon;
- bool mini;
- bool blocked;
- bool animating_mini_change;
- bool phantom;
- bool app;
- bool render_as_new_tab;
- bool render_unselected;
- double alpha;
- };
- TabData data_;
-
struct TabImage {
SkBitmap* image_l;
SkBitmap* image_c;
@@ -298,6 +221,15 @@ class TabRenderer : public views::View,
// The current color of the close button.
SkColor close_button_color_;
+ // See description above setter.
+ bool render_as_new_tab_;
+
+ // See description above setter.
+ bool render_unselected_;
+
+ // See description above setter.
+ double alpha_;
+
// The animation object used to swap the favicon with the sad tab icon.
class FavIconCrashAnimation;
FavIconCrashAnimation* crash_animation_;
@@ -308,7 +240,6 @@ class TabRenderer : public views::View,
scoped_refptr<AnimationContainer> container_;
- static void InitClass();
static bool initialized_;
DISALLOW_COPY_AND_ASSIGN(TabRenderer);
diff --git a/chrome/browser/views/tabs/tab_renderer_data.h b/chrome/browser/views/tabs/tab_renderer_data.h
new file mode 100644
index 0000000..7cbaa18
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_renderer_data.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_DATA_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_DATA_H_
+
+#include <string>
+
+#include "base/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+// Wraps the state needed by the renderers.
+struct TabRendererData {
+ // Different types of network activity for a tab. The NetworkState of a tab
+ // may be used to alter the UI (e.g. show different kinds of loading
+ // animations).
+ enum NetworkState {
+ NETWORK_STATE_NONE, // no network activity.
+ NETWORK_STATE_WAITING, // waiting for a connection.
+ NETWORK_STATE_LOADING, // connected, transferring data.
+ };
+
+ TabRendererData()
+ : network_state(NETWORK_STATE_NONE),
+ loading(false),
+ crashed(false),
+ off_the_record(false),
+ show_icon(true),
+ mini(false),
+ blocked(false),
+ phantom(false),
+ app(false) {
+ }
+
+ SkBitmap favicon;
+ NetworkState network_state;
+ string16 title;
+ bool loading;
+ bool crashed;
+ bool off_the_record;
+ bool show_icon;
+ bool mini;
+ bool blocked;
+ bool phantom;
+ bool app;
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_DATA_H_
diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc
index 5681a22..79a1399 100644
--- a/chrome/browser/views/tabs/tab_strip.cc
+++ b/chrome/browser/views/tabs/tab_strip.cc
@@ -7,34 +7,24 @@
#include "app/animation_container.h"
#include "app/drag_drop_types.h"
#include "app/l10n_util.h"
-#include "app/os_exchange_data.h"
#include "app/resource_bundle.h"
#include "app/slide_animation.h"
-#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/app_launcher.h"
#include "chrome/browser/views/tabs/dragged_tab_controller.h"
#include "chrome/browser/views/tabs/tab.h"
-#include "chrome/common/chrome_switches.h"
+#include "chrome/browser/views/tabs/tab_strip_controller.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
#include "gfx/canvas.h"
#include "gfx/path.h"
#include "gfx/size.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/image_view.h"
-#include "views/painter.h"
#include "views/widget/default_theme_provider.h"
#include "views/widget/root_view.h"
#include "views/window/non_client_view.h"
@@ -267,8 +257,8 @@ const int TabStrip::mini_to_non_mini_gap_ = 3;
// static
const int TabStrip::extra_gap_for_nano_ = 10;
-TabStrip::TabStrip(TabStripModel* model)
- : model_(model),
+TabStrip::TabStrip(TabStripController* controller)
+ : BaseTabStrip(controller),
resize_layout_factory_(this),
added_as_message_loop_observer_(false),
needs_resize_layout_(false),
@@ -289,8 +279,6 @@ TabStrip::~TabStrip() {
// delete the tabs.
StopAnimating(false);
- model_->RemoveObserver(this);
-
// TODO(beng): remove this if it doesn't work to fix the TabSelectedAt bug.
drag_controller_.reset(NULL);
@@ -304,10 +292,6 @@ TabStrip::~TabStrip() {
RemoveAllChildViews(true);
}
-bool TabStrip::CanProcessInputEvents() const {
- return !IsAnimating();
-}
-
void TabStrip::DestroyDragController() {
if (IsDragSessionActive())
drag_controller_.reset(NULL);
@@ -319,10 +303,6 @@ gfx::Rect TabStrip::GetIdealBounds(int tab_data_index) {
return tab_data_[tab_data_index].ideal_bounds;
}
-Tab* TabStrip::GetSelectedTab() const {
- return GetTabAtModelIndex(model()->selected_index());
-}
-
void TabStrip::InitTabStripButtons() {
newtab_button_ = new NewTabButton(this);
if (browser_defaults::kSizeTabButtonToTopOfTabStrip) {
@@ -334,23 +314,10 @@ void TabStrip::InitTabStripButtons() {
AddChildView(newtab_button_);
}
-bool TabStrip::IsCompatibleWith(TabStrip* other) const {
- return model_->profile() == other->model()->profile();
-}
-
gfx::Rect TabStrip::GetNewTabButtonBounds() {
return newtab_button_->bounds();
}
-void TabStrip::InitFromModel() {
- // Walk the model, calling our insertion observer method for each item within
- // it.
- for (int i = 0; i < model_->count(); ++i) {
- TabInsertedAt(model_->GetTabContentsAt(i), i,
- i == model_->selected_index());
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// TabStrip, BaseTabStrip implementation:
@@ -395,23 +362,6 @@ bool TabStrip::IsDragSessionActive() const {
return drag_controller_.get() != NULL;
}
-void TabStrip::UpdateLoadingAnimations() {
- for (int i = 0, model_index = 0; i < GetTabCount(); ++i) {
- Tab* current_tab = GetTabAtTabDataIndex(i);
- if (!current_tab->closing()) {
- TabContents* contents = model_->GetTabContentsAt(model_index);
- if (!contents || !contents->is_loading()) {
- current_tab->ValidateLoadingAnimation(Tab::ANIMATION_NONE);
- } else if (contents->waiting_for_response()) {
- current_tab->ValidateLoadingAnimation(Tab::ANIMATION_WAITING);
- } else {
- current_tab->ValidateLoadingAnimation(Tab::ANIMATION_LOADING);
- }
- model_index++;
- }
- }
-}
-
bool TabStrip::IsAnimating() const {
return bounds_animator_.IsAnimating() || new_tab_timer_.IsRunning();
}
@@ -420,6 +370,125 @@ TabStrip* TabStrip::AsTabStrip() {
return this;
}
+void TabStrip::AddTabAt(int model_index,
+ bool foreground,
+ const TabRendererData& data) {
+ Tab* tab = CreateTab();
+ tab->SetAnimationContainer(animation_container_.get());
+ tab->SetData(data);
+
+ TabData d = { tab, gfx::Rect() };
+ tab_data_.insert(tab_data_.begin() +
+ ModelIndexToTabDataIndex(model_index), d);
+
+ AddChildView(tab);
+
+ // Don't animate the first tab, it looks weird, and don't animate anything
+ // if the containing window isn't visible yet.
+ if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) {
+ if (!IsDragSessionActive() && !attaching_dragged_tab_ &&
+ ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) {
+ StartInsertTabAnimationAtEnd();
+ } else {
+ StartInsertTabAnimation(model_index);
+ }
+ } else {
+ Layout();
+ }
+}
+
+void TabStrip::RemoveTabAt(int model_index) {
+ int model_count = GetModelCount();
+ if (model_index != model_count && model_count > 0) {
+ Tab* last_tab = GetTabAtModelIndex(model_count - 1);
+ // Limit the width available to the TabStrip for laying out Tabs, so that
+ // Tabs are not resized until a later time (when the mouse pointer leaves
+ // the TabStrip).
+ available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab);
+ needs_resize_layout_ = true;
+ AddMessageLoopObserver();
+ } else if (model_count) {
+ Tab* last_tab = GetTabAtModelIndex(model_count);
+ // Limit the width available to the TabStrip for laying out Tabs, so that
+ // Tabs are not resized until a later time (when the mouse pointer leaves
+ // the TabStrip).
+ available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab);
+ needs_resize_layout_ = true;
+ AddMessageLoopObserver();
+ }
+
+ StartRemoveTabAnimation(model_index);
+}
+
+void TabStrip::SelectTabAt(int old_model_index, int new_model_index) {
+ // We have "tiny tabs" if the tabs are so tiny that the unselected ones are
+ // a different size to the selected ones.
+ bool tiny_tabs = current_unselected_width_ != current_selected_width_;
+ if (!IsAnimating() && (!needs_resize_layout_ || tiny_tabs)) {
+ Layout();
+ } else {
+ SchedulePaint();
+ }
+
+ if (old_model_index >= 0) {
+ GetTabAtTabDataIndex(ModelIndexToTabDataIndex(old_model_index))->
+ StopMiniTabTitleAnimation();
+ }
+}
+
+void TabStrip::MoveTab(int from_model_index, int to_model_index) {
+ StartMoveTabAnimation(from_model_index, to_model_index);
+}
+
+void TabStrip::TabTitleChangedNotLoading(int model_index) {
+ Tab* tab = GetTabAtModelIndex(model_index);
+ if (tab->data().mini && !tab->IsSelected())
+ tab->StartMiniTabTitleAnimation();
+}
+
+void TabStrip::SetTabData(int model_index, const TabRendererData& data) {
+ Tab* tab = GetTabAtModelIndex(model_index);
+ bool mini_state_changed = tab->data().mini != data.mini;
+ tab->SetData(data);
+ tab->SchedulePaint();
+
+ if (mini_state_changed) {
+ if (GetWindow() && GetWindow()->IsVisible())
+ StartMiniTabAnimation();
+ else
+ Layout();
+ }
+}
+
+void TabStrip::StartHighlight(int model_index) {
+ GetTabAtModelIndex(model_index)->StartPulse();
+}
+
+void TabStrip::StopAllHighlighting() {
+ for (int i = 0; i < GetTabCount(); ++i)
+ GetTabAtTabDataIndex(i)->StopPulse();
+}
+
+BaseTabRenderer* TabStrip::GetBaseTabAtModelIndex(int model_index) const {
+ return GetTabAtModelIndex(model_index);
+}
+
+BaseTabRenderer* TabStrip::GetBaseTabAtTabIndex(int tab_index) const {
+ return GetTabAtTabDataIndex(tab_index);
+}
+
+int TabStrip::GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const {
+ return GetModelIndexOfTab(static_cast<const Tab*>(tab));
+}
+
+BaseTabRenderer* TabStrip::CreateTabForDragging() {
+ Tab* tab = new Tab(NULL);
+ // Make sure the dragged tab shares our theme provider. We need to explicitly
+ // do this as during dragging there isn't a theme provider.
+ tab->SetThemeProvider(GetThemeProvider());
+ return tab;
+}
+
///////////////////////////////////////////////////////////////////////////////
// TabStrip, views::View overrides:
@@ -437,7 +506,7 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode);
for (int i = tab_count - 1; i >= 0; --i) {
Tab* tab = GetTabAtTabDataIndex(i);
- if (tab->phantom())
+ if (tab->data().phantom)
tab->ProcessPaint(canvas);
}
canvas->restore();
@@ -447,7 +516,7 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode);
for (int i = tab_count - 1; i >= 0; --i) {
Tab* tab = GetTabAtTabDataIndex(i);
- if (tab->phantom()) {
+ if (tab->data().phantom) {
canvas->save();
canvas->ClipRectInt(tab->MirroredX(), tab->y(), tab->width(),
tab->height());
@@ -463,19 +532,21 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
Tab* dragging_tab = NULL;
+ int model_count = GetModelCount();
+
for (int i = tab_count - 1; i >= 0; --i) {
Tab* tab = GetTabAtTabDataIndex(i);
// We must ask the _Tab's_ model, not ourselves, because in some situations
// the model will be different to this object, e.g. when a Tab is being
// removed after its TabContents has been destroyed.
- if (!tab->phantom()) {
+ if (!tab->data().phantom) {
if (tab->dragging()) {
dragging_tab = tab;
} else if (!tab->IsSelected()) {
- if (tab->render_unselected() && model_->count() > 1) {
+ if (tab->render_unselected() && model_count > 1) {
// See comment above kNetTabAnimationSelectedOffset as to why we do
// this.
- Tab* last_tab = GetTabAtModelIndex(model_->count() - 2);
+ Tab* last_tab = GetTabAtModelIndex(model_count - 2);
canvas->save();
int clip_x = last_tab->bounds().right() + kNetTabSelectedOffset;
int clip_width = width() - clip_x;
@@ -596,25 +667,7 @@ int TabStrip::OnPerformDrop(const DropTargetEvent& event) {
if (!event.GetData().GetURLAndTitle(&url, &title) || !url.is_valid())
return DragDropTypes::DRAG_NONE;
- if (drop_before) {
- UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"),
- model_->profile());
-
- // Insert a new tab.
- TabContents* contents =
- model_->delegate()->CreateTabContentsForURL(
- url, GURL(), model_->profile(), PageTransition::TYPED, false,
- NULL);
- model_->AddTabContents(contents, drop_index, false,
- PageTransition::GENERATED, true);
- } else {
- UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLOnTab"),
- model_->profile());
-
- model_->GetTabContentsAt(drop_index)->controller().LoadURL(
- url, GURL(), PageTransition::GENERATED);
- model_->SelectTabContentsAt(drop_index, true);
- }
+ controller()->PerformDrop(drop_before, drop_index, url);
return GetDropEffect(event);
}
@@ -655,6 +708,15 @@ void TabStrip::ThemeChanged() {
LoadNewTabButtonImage();
}
+void TabStrip::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
+ AnimationType last_type = animation_type_;
+
+ ResetAnimationState(false);
+
+ if (!cancelling_animation_ && last_type == ANIMATION_NEW_TAB_2)
+ NewTabAnimation2Done();
+}
+
Tab* TabStrip::CreateTab() {
return new Tab(this);
}
@@ -678,233 +740,27 @@ void TabStrip::OnMouseReleased(const views::MouseEvent& event,
}
///////////////////////////////////////////////////////////////////////////////
-// TabStrip, TabStripModelObserver implementation:
-
-void TabStrip::TabInsertedAt(TabContents* contents,
- int model_index,
- bool foreground) {
- DCHECK(contents);
- DCHECK(model_index == TabStripModel::kNoTab ||
- model_->ContainsIndex(model_index));
- // This tab may be attached to another browser window, we should notify
- // renderer.
- contents->render_view_host()->UpdateBrowserWindowId(
- contents->controller().window_id().id());
-
- Tab* tab = CreateTab();
-
- TabData d = { tab, gfx::Rect() };
- tab_data_.insert(tab_data_.begin() +
- ModelIndexToTabDataIndex(model_index), d);
- tab->UpdateData(contents, model_->IsPhantomTab(model_index), false);
- tab->set_mini(model_->IsMiniTab(model_index));
- tab->set_app(model_->IsAppTab(model_index));
- tab->SetBlocked(model_->IsTabBlocked(model_index));
- tab->SetAnimationContainer(animation_container_.get());
-
- AddChildView(tab);
-
- // Don't animate the first tab, it looks weird, and don't animate anything
- // if the containing window isn't visible yet.
- if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) {
- if (!IsDragSessionActive() && !attaching_dragged_tab_ &&
- ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) {
- StartInsertTabAnimationAtEnd();
- } else {
- StartInsertTabAnimation(model_index);
- }
- } else {
- Layout();
- }
-}
-
-void TabStrip::TabDetachedAt(TabContents* contents, int model_index) {
- StartRemoveTabAnimation(model_index);
-}
-
-void TabStrip::TabSelectedAt(TabContents* old_contents,
- TabContents* new_contents,
- int model_index,
- bool user_gesture) {
- // We have "tiny tabs" if the tabs are so tiny that the unselected ones are
- // a different size to the selected ones.
- bool tiny_tabs = current_unselected_width_ != current_selected_width_;
- if (!IsAnimating() && (!needs_resize_layout_ || tiny_tabs)) {
- Layout();
- } else {
- SchedulePaint();
- }
-
- int old_model_index = model_->GetIndexOfTabContents(old_contents);
- if (old_model_index >= 0) {
- GetTabAtTabDataIndex(ModelIndexToTabDataIndex(old_model_index))->
- StopMiniTabTitleAnimation();
- }
-}
-
-void TabStrip::TabMoved(TabContents* contents,
- int from_model_index,
- int to_model_index) {
- StartMoveTabAnimation(from_model_index, to_model_index);
-}
-
-void TabStrip::TabChangedAt(TabContents* contents,
- int model_index,
- TabChangeType change_type) {
- // Index is in terms of the model. Need to make sure we adjust that index in
- // case we have an animation going.
- Tab* tab = GetTabAtModelIndex(model_index);
- if (change_type == TITLE_NOT_LOADING) {
- if (tab->mini() && !tab->IsSelected())
- tab->StartMiniTabTitleAnimation();
- // We'll receive another notification of the change asynchronously.
- return;
- }
- tab->UpdateData(contents, model_->IsPhantomTab(model_index),
- change_type == LOADING_ONLY);
- tab->UpdateFromModel();
-}
-
-void TabStrip::TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents,
- int model_index) {
- TabChangedAt(new_contents, model_index, ALL);
-}
-
-void TabStrip::TabMiniStateChanged(TabContents* contents, int model_index) {
- GetTabAtModelIndex(model_index)->set_mini(
- model_->IsMiniTab(model_index));
- // Don't animate if the window isn't visible yet. The window won't be visible
- // when dragging a mini-tab to a new window.
- if (GetWindow() && GetWindow()->IsVisible())
- StartMiniTabAnimation();
- else
- Layout();
-}
-
-void TabStrip::TabBlockedStateChanged(TabContents* contents, int model_index) {
- GetTabAtModelIndex(model_index)->SetBlocked(
- model_->IsTabBlocked(model_index));
-}
-
-///////////////////////////////////////////////////////////////////////////////
// TabStrip, Tab::Delegate implementation:
-bool TabStrip::IsTabSelected(const Tab* tab) const {
+bool TabStrip::IsTabSelected(const BaseTabRenderer* btr) const {
+ const Tab* tab = static_cast<const Tab*>(btr);
if (tab->closing() || tab->render_unselected())
return false;
- return GetModelIndexOfTab(tab) == model_->selected_index();
+ return BaseTabStrip::IsTabSelected(btr);
}
-bool TabStrip::IsTabPinned(const Tab* tab) const {
+bool TabStrip::IsTabPinned(const BaseTabRenderer* btr) const {
+ const Tab* tab = static_cast<const Tab*>(btr);
if (tab->closing())
return false;
- return model_->IsTabPinned(GetModelIndexOfTab(tab));
-}
-
-void TabStrip::SelectTab(Tab* tab) {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index))
- model_->SelectTabContentsAt(model_index, true);
-}
-
-void TabStrip::CloseTab(Tab* tab) {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index)) {
- TabContents* contents = model_->GetTabContentsAt(model_index);
- if (contents)
- UserMetrics::RecordAction(UserMetricsAction("CloseTab_Mouse"),
- contents->profile());
- if (model_index + 1 != model_->count() && model_->count() > 1) {
- Tab* last_tab = GetTabAtModelIndex(model_->count() - 2);
- // Limit the width available to the TabStrip for laying out Tabs, so that
- // Tabs are not resized until a later time (when the mouse pointer leaves
- // the TabStrip).
- available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab);
- needs_resize_layout_ = true;
- AddMessageLoopObserver();
- } else if (model_->count() > 1) {
- Tab* last_tab = GetTabAtModelIndex(model_->count() - 1);
- // Limit the width available to the TabStrip for laying out Tabs, so that
- // Tabs are not resized until a later time (when the mouse pointer leaves
- // the TabStrip).
- available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab);
- needs_resize_layout_ = true;
- AddMessageLoopObserver();
- }
- // Note that the next call might not close the tab (because of unload
- // hanlders or if the delegate veto the close).
- model_->CloseTabContentsAt(model_index);
- }
-}
-
-bool TabStrip::IsCommandEnabledForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index))
- return model_->IsContextMenuCommandEnabled(model_index, command_id);
- return false;
-}
-
-bool TabStrip::IsCommandCheckedForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index))
- return model_->IsContextMenuCommandChecked(model_index, command_id);
- return false;
-}
-
-void TabStrip::ExecuteCommandForTab(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index))
- model_->ExecuteContextMenuCommand(model_index, command_id);
+ return BaseTabStrip::IsTabPinned(tab);
}
-void TabStrip::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
- AnimationType last_type = animation_type_;
-
- ResetAnimationState(false);
-
- if (!cancelling_animation_ && last_type == ANIMATION_NEW_TAB_2)
- NewTabAnimation2Done();
-}
-
-void TabStrip::StartHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) {
- if (command_id == TabStripModel::CommandCloseTabsOpenedBy ||
- command_id == TabStripModel::CommandCloseOtherTabs ||
- command_id == TabStripModel::CommandCloseTabsToRight) {
- int model_index = GetModelIndexOfTab(tab);
- if (model_->ContainsIndex(model_index)) {
- std::vector<int> indices =
- model_->GetIndicesClosedByCommand(model_index, command_id);
- for (std::vector<int>::const_iterator i = indices.begin();
- i != indices.end(); ++i) {
- GetTabAtModelIndex(*i)->StartPulse();
- }
- }
- }
-}
-
-void TabStrip::StopHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab) {
- if (command_id == TabStripModel::CommandCloseTabsOpenedBy ||
- command_id == TabStripModel::CommandCloseTabsToRight ||
- command_id == TabStripModel::CommandCloseOtherTabs) {
- // Just tell all Tabs to stop pulsing - it's safe.
- StopAllHighlighting();
- }
-}
-
-void TabStrip::StopAllHighlighting() {
- for (int i = 0; i < GetTabCount(); ++i)
- GetTabAtTabDataIndex(i)->StopPulse();
-}
-
-void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) {
+void TabStrip::MaybeStartDrag(BaseTabRenderer* btr,
+ const views::MouseEvent& event) {
+ Tab* tab = static_cast<Tab*>(btr);
// Don't accidentally start any drag operations during animations if the
// mouse is down... during an animation tabs are being resized automatically,
// so the View system can misinterpret this easily if the mouse is down that
@@ -912,7 +768,7 @@ void TabStrip::MaybeStartDrag(Tab* tab, const views::MouseEvent& event) {
if (IsAnimating() || tab->closing() || !HasAvailableDragActions())
return;
int model_index = GetModelIndexOfTab(tab);
- if (!model_->ContainsIndex(model_index)) {
+ if (!IsValidModelIndex(model_index)) {
CHECK(false);
return;
}
@@ -944,28 +800,15 @@ bool TabStrip::EndDrag(bool canceled) {
}
bool TabStrip::HasAvailableDragActions() const {
- return model_->delegate()->GetDragActions() != 0;
+ return controller()->HasAvailableDragActions() != 0;
}
///////////////////////////////////////////////////////////////////////////////
// TabStrip, views::BaseButton::ButtonListener implementation:
void TabStrip::ButtonPressed(views::Button* sender, const views::Event& event) {
- if (sender == newtab_button_) {
- // TODO(jcampan): if we decide to keep the app launcher as the default
- // behavior for the new tab button, we should add a method
- // on the TabStripDelegate to do so.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsPanel)) {
- NavigationController& controller =
- model_->GetSelectedTabContents()->controller();
- AppLauncher::ShowForNewTab(
- Browser::GetBrowserForController(&controller, NULL), std::string());
- return;
- }
- UserMetrics::RecordAction(UserMetricsAction("NewTab_Button"),
- model_->profile());
- model_->delegate()->AddBlankTab(true);
- }
+ if (sender == newtab_button_)
+ controller()->CreateNewTab();
}
///////////////////////////////////////////////////////////////////////////////
@@ -1029,7 +872,6 @@ void TabStrip::DidProcessEvent(GdkEvent* event) {
void TabStrip::Init() {
SetID(VIEW_ID_TAB_STRIP);
- model_->AddObserver(this);
newtab_button_bounds_.SetRect(0, 0, kNewTabButtonWidth, kNewTabButtonHeight);
if (browser_defaults::kSizeTabButtonToTopOfTabStrip) {
newtab_button_bounds_.set_height(
@@ -1412,9 +1254,9 @@ void TabStrip::GenerateIdealBounds() {
for (int i = 0; i < tab_count; ++i) {
if (!tab_data_[i].tab->closing()) {
++non_closing_tab_count;
- if (tab_data_[i].tab->mini())
+ if (tab_data_[i].tab->data().mini)
mini_tab_count++;
- if (tab_data_[i].tab->app())
+ if (tab_data_[i].tab->data().app)
nano_tab_count++;
}
}
@@ -1435,7 +1277,7 @@ void TabStrip::GenerateIdealBounds() {
if (!tab_data_[i].tab->closing()) {
Tab* tab = GetTabAtTabDataIndex(i);
double tab_width = unselected;
- if (tab->mini()) {
+ if (tab->data().mini) {
tab_width = Tab::GetMiniWidth();
} else {
if (last_was_mini) {
@@ -1453,7 +1295,7 @@ void TabStrip::GenerateIdealBounds() {
gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x,
tab_height);
tab_x = end_of_tab + kTabHOffset;
- last_was_mini = tab->mini();
+ last_was_mini = tab->data().mini;
}
}
@@ -1534,9 +1376,8 @@ void TabStrip::AnimateToIdealBounds() {
bool TabStrip::ShouldStartIntertTabAnimationAtEnd(int model_index,
bool foreground) {
- return foreground && (model_index + 1 == model_->count()) &&
- (model_->GetTabContentsAt(model_index)->GetURL() ==
- GURL(chrome::kChromeUINewTabURL));
+ return foreground && (model_index + 1 == GetModelCount()) &&
+ controller()->IsNewTabPage(model_index);
}
void TabStrip::StartResizeLayoutAnimation() {
@@ -1555,7 +1396,7 @@ void TabStrip::StartInsertTabAnimationAtEnd() {
GenerateIdealBounds();
- int tab_data_index = ModelIndexToTabDataIndex(model_->count() - 1);
+ int tab_data_index = ModelIndexToTabDataIndex(GetModelCount() - 1);
Tab* tab = tab_data_[tab_data_index].tab;
tab->SizeToNewTabButtonImages();
tab->SetBounds(newtab_button_->x() +
@@ -1624,15 +1465,10 @@ void TabStrip::StartMoveTabAnimation(int from_model_index,
tab_data_.erase(tab_data_.begin() + from_tab_data_index);
TabData data = {tab, gfx::Rect()};
- tab->set_mini(model_->IsMiniTab(to_model_index));
- tab->set_app(model_->IsAppTab(to_model_index));
- tab->SetBlocked(model_->IsTabBlocked(to_model_index));
int to_tab_data_index = ModelIndexToTabDataIndex(to_model_index);
tab_data_.insert(tab_data_.begin() + to_tab_data_index, data);
- if (tab->phantom() != model_->IsPhantomTab(to_model_index))
- tab->set_phantom(!tab->phantom());
GenerateIdealBounds();
AnimateToIdealBounds();
@@ -1679,7 +1515,6 @@ void TabStrip::ResetAnimationState(bool stop_new_tab_timer) {
// Reset the animation state of each tab.
for (int i = 0, count = GetTabCount(); i < count; ++i) {
Tab* tab = GetTabAtTabDataIndex(i);
- tab->set_animating_mini_change(false);
tab->set_render_as_new_tab(false);
tab->set_render_unselected(false);
tab->set_alpha(1);
@@ -1689,7 +1524,7 @@ void TabStrip::ResetAnimationState(bool stop_new_tab_timer) {
int TabStrip::GetMiniTabCount() const {
int mini_count = 0;
for (size_t i = 0; i < tab_data_.size(); ++i) {
- if (tab_data_[i].tab->mini())
+ if (tab_data_[i].tab->data().mini)
mini_count++;
else
return mini_count;
@@ -1700,7 +1535,7 @@ int TabStrip::GetMiniTabCount() const {
int TabStrip::GetNanoTabCount() const {
int nano_count = 0;
for (size_t i = 0; i < tab_data_.size(); ++i) {
- if (tab_data_[i].tab->app())
+ if (tab_data_[i].tab->data().app)
nano_count++;
else
return nano_count;
@@ -1750,7 +1585,7 @@ void TabStrip::HandleGlobalMouseMoveEvent() {
bool TabStrip::HasPhantomTabs() const {
for (int i = 0; i < GetTabCount(); ++i) {
- if (GetTabAtTabDataIndex(i)->phantom())
+ if (GetTabAtTabDataIndex(i)->data().phantom)
return true;
}
return false;
diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h
index 5279dd0..d803a25 100644
--- a/chrome/browser/views/tabs/tab_strip.h
+++ b/chrome/browser/views/tabs/tab_strip.h
@@ -11,7 +11,6 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/timer.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "chrome/browser/views/tabs/tab.h"
#include "gfx/point.h"
@@ -20,8 +19,6 @@
#include "views/controls/button/image_button.h"
class DraggedTabController;
-class ScopedMouseCloseWidthCalculator;
-class TabStripModel;
namespace views {
class ImageView;
@@ -46,23 +43,13 @@ class WidgetWin;
//
///////////////////////////////////////////////////////////////////////////////
class TabStrip : public BaseTabStrip,
- public TabStripModelObserver,
- public Tab::TabDelegate,
public views::ButtonListener,
public MessageLoopForUI::Observer,
public views::BoundsAnimatorObserver {
public:
- explicit TabStrip(TabStripModel* model);
+ explicit TabStrip(TabStripController* controller);
virtual ~TabStrip();
- // Returns true if the TabStrip can accept input events. This returns false
- // when the TabStrip is animating to a new state and as such the user should
- // not be allowed to interact with the TabStrip.
- bool CanProcessInputEvents() const;
-
- // Accessors for the model and individual Tabs.
- TabStripModel* model() const { return model_; }
-
// Set whether the new tab button is enabled.
void set_new_tab_button_enabled(bool enabled) {
new_tab_button_enabled_ = enabled;
@@ -79,24 +66,12 @@ class TabStrip : public BaseTabStrip,
// Retrieves the ideal bounds for the Tab at the specified index.
gfx::Rect GetIdealBounds(int tab_data_index);
- // Returns the currently selected tab.
- Tab* GetSelectedTab() const;
-
// Creates the new tab button.
void InitTabStripButtons();
- // Return true if this tab strip is compatible with the provided tab strip.
- // Compatible tab strips can transfer tabs during drag and drop.
- bool IsCompatibleWith(TabStrip* other) const;
-
// Returns the bounds of the new tab button.
gfx::Rect GetNewTabButtonBounds();
- // Populates the BaseTabStrip implementation from its model. This is primarily
- // useful when switching between display types and there are existing tabs.
- // Upon initial creation the TabStrip is empty.
- void InitFromModel();
-
// BaseTabStrip implementation:
virtual int GetPreferredHeight();
virtual void SetBackgroundOffset(const gfx::Point& offset);
@@ -104,9 +79,22 @@ class TabStrip : public BaseTabStrip,
virtual void SetDraggedTabBounds(int tab_index,
const gfx::Rect& tab_bounds);
virtual bool IsDragSessionActive() const;
- virtual void UpdateLoadingAnimations();
virtual bool IsAnimating() const;
virtual TabStrip* AsTabStrip();
+ virtual void AddTabAt(int model_index,
+ bool foreground,
+ const TabRendererData& data);
+ virtual void RemoveTabAt(int model_index);
+ virtual void SelectTabAt(int old_model_index, int new_model_index);
+ virtual void MoveTab(int from_model_index, int to_model_index);
+ virtual void TabTitleChangedNotLoading(int model_index);
+ virtual void SetTabData(int model_index, const TabRendererData& data);
+ virtual void StartHighlight(int model_index);
+ virtual void StopAllHighlighting();
+ virtual BaseTabRenderer* GetBaseTabAtModelIndex(int model_index) const;
+ virtual BaseTabRenderer* GetBaseTabAtTabIndex(int tab_index) const;
+ virtual int GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const;
+ virtual BaseTabRenderer* CreateTabForDragging();
// views::View overrides:
virtual void PaintChildren(gfx::Canvas* canvas);
@@ -138,44 +126,11 @@ class TabStrip : public BaseTabStrip,
virtual void OnMouseReleased(const views::MouseEvent& event,
bool canceled);
- // TabStripModelObserver implementation:
- virtual void TabInsertedAt(TabContents* contents,
- int model_index,
- bool foreground);
- virtual void TabDetachedAt(TabContents* contents, int model_index);
- virtual void TabSelectedAt(TabContents* old_contents,
- TabContents* contents,
- int model_index,
- bool user_gesture);
- virtual void TabMoved(TabContents* contents,
- int from_model_index,
- int to_model_index);
- virtual void TabChangedAt(TabContents* contents,
- int model_index,
- TabChangeType change_type);
- virtual void TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents,
- int model_index);
- virtual void TabMiniStateChanged(TabContents* contents, int model_index);
- virtual void TabBlockedStateChanged(TabContents* contents, int model_index);
-
- // Tab::Delegate implementation:
- virtual bool IsTabSelected(const Tab* tab) const;
- virtual bool IsTabPinned(const Tab* tab) const;
- virtual void SelectTab(Tab* tab);
- virtual void CloseTab(Tab* tab);
- virtual bool IsCommandEnabledForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const;
- virtual bool IsCommandCheckedForTab(
- TabStripModel::ContextMenuCommand command_id, const Tab* tab) const;
- virtual void ExecuteCommandForTab(
- TabStripModel::ContextMenuCommand command_id, Tab* tab);
- virtual void StartHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab);
- virtual void StopHighlightTabsForCommand(
- TabStripModel::ContextMenuCommand command_id, Tab* tab);
- virtual void StopAllHighlighting();
- virtual void MaybeStartDrag(Tab* tab, const views::MouseEvent& event);
+ // TabController overrides.
+ virtual bool IsTabSelected(const BaseTabRenderer* btr) const;
+ virtual bool IsTabPinned(const BaseTabRenderer* btr) const;
+ virtual void MaybeStartDrag(BaseTabRenderer* btr,
+ const views::MouseEvent& event);
virtual void ContinueDrag(const views::MouseEvent& event);
virtual bool EndDrag(bool canceled);
virtual bool HasAvailableDragActions() const;
@@ -265,7 +220,6 @@ class TabStrip : public BaseTabStrip,
gfx::Rect ideal_bounds;
};
- TabStrip();
void Init();
// Set the images for the new tab button.
@@ -288,7 +242,7 @@ class TabStrip : public BaseTabStrip,
// WARNING: this is the number of tabs displayed by the tabstrip, which if
// an animation is ongoing is not necessarily the same as the number of tabs
// in the model.
- int GetTabCount() const;
+ virtual int GetTabCount() const;
// Returns the number of mini-tabs.
int GetMiniTabCount() const;
@@ -428,9 +382,6 @@ class TabStrip : public BaseTabStrip,
// -- Member Variables ------------------------------------------------------
- // Our model.
- TabStripModel* model_;
-
// A factory that is used to construct a delayed callback to the
// ResizeLayoutTabsNow method.
ScopedRunnableMethodFactory<TabStrip> resize_layout_factory_;
diff --git a/chrome/browser/views/tabs/tab_strip_controller.h b/chrome/browser/views/tabs/tab_strip_controller.h
new file mode 100644
index 0000000..90cd87c
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_strip_controller.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_
+
+#include <vector>
+
+class BaseTabRenderer;
+class BaseTabStrip;
+class GURL;
+
+namespace gfx {
+class Point;
+}
+
+// Model/Controller for the TabStrip.
+// NOTE: All indices used by this class are in model coordinates.
+class TabStripController {
+ public:
+ virtual ~TabStripController() {}
+
+ // Returns the number of tabs in the model.
+ virtual int GetCount() const = 0;
+
+ // Returns true if |index| is a valid model index.
+ virtual bool IsValidIndex(int index) const = 0;
+
+ // Returns the selected index, in terms of the model.
+ virtual int GetSelectedIndex() const = 0;
+
+ // Returns true if the selected index is selected.
+ virtual bool IsTabSelected(int index) const = 0;
+
+ // Returns true if the selected index is pinned.
+ virtual bool IsTabPinned(int index) const = 0;
+
+ // Returns true if the selected index is the new tab page.
+ virtual bool IsNewTabPage(int index) const = 0;
+
+ // Select the tab at the specified index in the model.
+ virtual void SelectTab(int index) = 0;
+
+ // Closes the tab at the specified index in the model.
+ virtual void CloseTab(int index) = 0;
+
+ // Shows a context menu for the tab at the specified point in screen coords.
+ virtual void ShowContextMenu(BaseTabRenderer* tab, const gfx::Point& p) = 0;
+
+ // Updates the loading animations of all the tabs.
+ virtual void UpdateLoadingAnimations() = 0;
+
+ // Returns true if the associated TabStrip's delegate supports tab moving or
+ // detaching. Used by the Frame to determine if dragging on the Tab
+ // itself should move the window in cases where there's only one
+ // non drag-able Tab.
+ virtual int HasAvailableDragActions() const = 0;
+
+ // Performans a drop at the specified location.
+ virtual void PerformDrop(bool drop_before, int index, const GURL& url) = 0;
+
+ // Return true if this tab strip is compatible with the provided tab strip.
+ // Compatible tab strips can transfer tabs during drag and drop.
+ virtual bool IsCompatibleWith(BaseTabStrip* other) const = 0;
+
+ // Creates the new tab.
+ virtual void CreateNewTab() = 0;
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_