summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-28 22:45:40 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-28 22:45:40 +0000
commitecc523f661dd66ab6dafa276971c84f491f2521e (patch)
treebf6bbe6619420fb19210ed99f31ac385614137b9
parent19e300520d7474d430e2bb904a564253fe66a547 (diff)
downloadchromium_src-ecc523f661dd66ab6dafa276971c84f491f2521e.zip
chromium_src-ecc523f661dd66ab6dafa276971c84f491f2521e.tar.gz
chromium_src-ecc523f661dd66ab6dafa276971c84f491f2521e.tar.bz2
Create a TabHandler object to decouple Browser from TabStripModel API.
Currently it's just a pass-through so everything still works while I begin to move stuff out of Browser down into it. BUG=none TEST=existing unittests. Review URL: http://codereview.chromium.org/3412041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60860 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser.cc235
-rw-r--r--chrome/browser/browser.h59
-rw-r--r--chrome/browser/tabs/default_tab_handler.cc198
-rw-r--r--chrome/browser/tabs/default_tab_handler.h88
-rw-r--r--chrome/browser/tabs/tab_handler.h36
-rw-r--r--chrome/chrome_browser.gypi3
6 files changed, 488 insertions, 131 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 783ff7e..1d2c82f 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -182,7 +182,8 @@ Browser::Browser(Type type, Profile* profile)
: type_(type),
profile_(profile),
window_(NULL),
- tabstrip_model_(new TabStripModel(this, profile)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ tab_handler_(TabHandler::CreateTabHandler(this))),
command_updater_(this),
toolbar_model_(this),
chrome_updater_factory_(this),
@@ -195,8 +196,6 @@ Browser::Browser(Type type, Profile* profile)
last_blocked_command_disposition_(CURRENT_TAB),
pending_web_app_action_(NONE),
extension_app_(NULL) {
- tabstrip_model_->AddObserver(this);
-
registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
@@ -247,10 +246,6 @@ Browser::Browser(Type type, Profile* profile)
}
Browser::~Browser() {
- // The tab strip should not have any significant tabs at this point.
- DCHECK(!tabstrip_model_->HasNonPhantomTabs());
- tabstrip_model_->RemoveObserver(this);
-
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->RemoveObserver(this);
@@ -693,7 +688,8 @@ SkBitmap Browser::GetCurrentPageIcon() const {
}
string16 Browser::GetWindowTitleForCurrentTab() const {
- TabContents* contents = tabstrip_model_->GetSelectedTabContents();
+ TabContents* contents =
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents();
string16 title;
// |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
@@ -816,40 +812,40 @@ void Browser::InProgressDownloadResponse(bool cancel_downloads) {
// Browser, TabStripModel pass-thrus:
int Browser::tab_count() const {
- return tabstrip_model_->count();
+ return tab_handler_->GetTabStripModel()->count();
}
int Browser::selected_index() const {
- return tabstrip_model_->selected_index();
+ return tab_handler_->GetTabStripModel()->selected_index();
}
int Browser::GetIndexOfController(
const NavigationController* controller) const {
- return tabstrip_model_->GetIndexOfController(controller);
+ return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
}
TabContents* Browser::GetTabContentsAt(int index) const {
- return tabstrip_model_->GetTabContentsAt(index);
+ return tab_handler_->GetTabStripModel()->GetTabContentsAt(index);
}
TabContents* Browser::GetSelectedTabContents() const {
- return tabstrip_model_->GetSelectedTabContents();
+ return tab_handler_->GetTabStripModel()->GetSelectedTabContents();
}
void Browser::SelectTabContentsAt(int index, bool user_gesture) {
- tabstrip_model_->SelectTabContentsAt(index, user_gesture);
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, user_gesture);
}
void Browser::CloseAllTabs() {
- tabstrip_model_->CloseAllTabs();
+ tab_handler_->GetTabStripModel()->CloseAllTabs();
}
////////////////////////////////////////////////////////////////////////////////
// Browser, Tab adding/showing functions:
int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
- return (tabstrip_model_->insertion_policy() == TabStripModel::INSERT_AFTER) ?
- tab_count() : relative_index;
+ return (tab_handler_->GetTabStripModel()->insertion_policy() ==
+ TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
}
TabContents* Browser::AddTabWithURL(const GURL& url,
@@ -868,7 +864,8 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
contents = CreateTabContentsForURL(url_to_load, referrer, profile_,
transition, false, instance);
contents->SetExtensionAppById(extension_app_id);
- tabstrip_model_->AddTabContents(contents, index, transition, add_types);
+ tab_handler_->GetTabStripModel()->AddTabContents(contents, index,
+ transition, add_types);
// TODO(sky): figure out why this is needed. Without it we seem to get
// failures in startup tests.
// By default, content believes it is not hidden. When adding contents
@@ -899,7 +896,7 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
TabContents* Browser::AddTab(TabContents* tab_contents,
PageTransition::Type type) {
- tabstrip_model_->AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
tab_contents, -1, type, TabStripModel::ADD_SELECTED);
return tab_contents;
}
@@ -939,18 +936,19 @@ TabContents* Browser::AddRestoredTab(
SessionStorageNamespace* session_storage_namespace) {
TabContents* new_tab = new TabContents(
profile(), NULL, MSG_ROUTING_NONE,
- tabstrip_model_->GetSelectedTabContents(), session_storage_namespace);
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(),
+ session_storage_namespace);
new_tab->SetExtensionAppById(extension_app_id);
new_tab->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
bool really_pin =
(pin && tab_index == tabstrip_model()->IndexOfFirstNonMiniTab());
- tabstrip_model_->InsertTabContentsAt(
+ tab_handler_->GetTabStripModel()->InsertTabContentsAt(
tab_index, new_tab,
select ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE);
if (really_pin)
- tabstrip_model_->SetTabPinned(tab_index, true);
+ tab_handler_->GetTabStripModel()->SetTabPinned(tab_index, true);
if (select) {
window_->Activate();
} else {
@@ -978,14 +976,15 @@ void Browser::ReplaceRestoredTab(
const std::string& extension_app_id,
SessionStorageNamespace* session_storage_namespace) {
TabContents* replacement = new TabContents(profile(), NULL,
- MSG_ROUTING_NONE, tabstrip_model_->GetSelectedTabContents(),
+ MSG_ROUTING_NONE,
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(),
session_storage_namespace);
replacement->SetExtensionAppById(extension_app_id);
replacement->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
- tabstrip_model_->ReplaceNavigationControllerAt(
- tabstrip_model_->selected_index(),
+ tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt(
+ tab_handler_->GetTabStripModel()->selected_index(),
&replacement->controller());
}
@@ -1013,11 +1012,12 @@ void Browser::ShowSingletonTab(const GURL& url) {
&reverse_on_redirect);
// See if we already have a tab with the given URL and select it if so.
- for (int i = 0; i < tabstrip_model_->count(); i++) {
- TabContents* tc = tabstrip_model_->GetTabContentsAt(i);
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = 0; i < model->count(); i++) {
+ TabContents* tc = model->GetTabContentsAt(i);
if (CompareURLsIgnoreRef(tc->GetURL(), url) ||
CompareURLsIgnoreRef(tc->GetURL(), rewritten_url)) {
- tabstrip_model_->SelectTabContentsAt(i, false);
+ model->SelectTabContentsAt(i, false);
return;
}
}
@@ -1107,7 +1107,7 @@ TabContents* Browser::GetOrCloneTabForDisposition(
TabContents* current_tab = GetSelectedTabContents();
if (ShouldOpenNewTabForWindowDisposition(disposition)) {
current_tab = current_tab->Clone();
- tabstrip_model_->AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
current_tab, -1, PageTransition::LINK,
disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE);
@@ -1116,7 +1116,7 @@ TabContents* Browser::GetOrCloneTabForDisposition(
}
void Browser::UpdateTabStripModelInsertionPolicy() {
- tabstrip_model_->SetInsertionPolicy(UseVerticalTabs() ?
+ tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
}
@@ -1301,8 +1301,8 @@ void Browser::CloseTab() {
UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
profile_);
if (CanCloseTab()) {
- tabstrip_model_->CloseTabContentsAt(
- tabstrip_model_->selected_index(),
+ tab_handler_->GetTabStripModel()->CloseTabContentsAt(
+ tab_handler_->GetTabStripModel()->selected_index(),
TabStripModel::CLOSE_USER_GESTURE |
TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
}
@@ -1310,12 +1310,12 @@ void Browser::CloseTab() {
void Browser::SelectNextTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
- tabstrip_model_->SelectNextTab();
+ tab_handler_->GetTabStripModel()->SelectNextTab();
}
void Browser::SelectPreviousTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
- tabstrip_model_->SelectPreviousTab();
+ tab_handler_->GetTabStripModel()->SelectPreviousTab();
}
void Browser::OpenTabpose() {
@@ -1334,25 +1334,25 @@ void Browser::OpenTabpose() {
void Browser::MoveTabNext() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
- tabstrip_model_->MoveTabNext();
+ tab_handler_->GetTabStripModel()->MoveTabNext();
}
void Browser::MoveTabPrevious() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
- tabstrip_model_->MoveTabPrevious();
+ tab_handler_->GetTabStripModel()->MoveTabPrevious();
}
void Browser::SelectNumberedTab(int index) {
if (index < tab_count()) {
UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"),
profile_);
- tabstrip_model_->SelectTabContentsAt(index, true);
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, true);
}
}
void Browser::SelectLastTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
- tabstrip_model_->SelectLastTab();
+ tab_handler_->GetTabStripModel()->SelectLastTab();
}
void Browser::DuplicateTab() {
@@ -1386,8 +1386,9 @@ void Browser::WriteCurrentURLToClipboard() {
void Browser::ConvertPopupToTabbedBrowser() {
UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_);
- int tab_strip_index = tabstrip_model_->selected_index();
- TabContents* contents = tabstrip_model_->DetachTabContentsAt(tab_strip_index);
+ int tab_strip_index = tab_handler_->GetTabStripModel()->selected_index();
+ TabContents* contents =
+ tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index);
Browser* browser = Browser::Create(profile_);
browser->tabstrip_model()->AppendTabContents(contents, true);
browser->window()->Show();
@@ -1760,8 +1761,9 @@ void Browser::ShowOptionsTab(const std::string& sub_page) {
GURL url(chrome::kChromeUISettingsURL + sub_page);
// See if there is already an options tab open that we can use.
- for (int i = 0; i < tabstrip_model_->count(); i++) {
- TabContents* tc = tabstrip_model_->GetTabContentsAt(i);
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = 0; i < model->count(); i++) {
+ TabContents* tc = model->GetTabContentsAt(i);
const GURL& tab_url = tc->GetURL();
if (tab_url.scheme() == url.scheme() && tab_url.host() == url.host()) {
@@ -1771,7 +1773,7 @@ void Browser::ShowOptionsTab(const std::string& sub_page) {
// URL in the address bar, but security policy doesn't allow that.
OpenURLAtIndex(tc, url, GURL(), CURRENT_TAB, PageTransition::GENERATED,
-1, -1);
- tabstrip_model_->SelectTabContentsAt(i, false);
+ model->SelectTabContentsAt(i, false);
return;
}
}
@@ -1996,11 +1998,29 @@ void Browser::RegisterUserPrefs(PrefService* prefs) {
}
// static
+bool Browser::RunUnloadEventsHelper(TabContents* contents) {
+ // If the TabContents is not connected yet, then there's no unload
+ // handler we can fire even if the TabContents has an unload listener.
+ // One case where we hit this is in a tab that has an infinite loop
+ // before load.
+ if (TabHasUnloadListener(contents)) {
+ // If the page has unload listeners, then we tell the renderer to fire
+ // them. Once they have fired, we'll get a message back saying whether
+ // to proceed closing the page or not, which sends us back to this method
+ // with the HasUnloadListener bit cleared.
+ contents->render_view_host()->FirePageBeforeUnload(false);
+ return true;
+ }
+ return false;
+}
+
+// static
Browser* Browser::GetBrowserForController(
const NavigationController* controller, int* index_result) {
BrowserList::const_iterator it;
for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
- int index = (*it)->tabstrip_model_->GetIndexOfController(controller);
+ int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController(
+ controller);
if (index != TabStripModel::kNoTab) {
if (index_result)
*index_result = index;
@@ -2225,6 +2245,14 @@ int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, PageNavigator implementation:
+void Browser::OpenURL(const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ OpenURLFromTab(NULL, url, referrer, disposition, transition);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
void Browser::ExecuteCommand(int id) {
@@ -2232,6 +2260,17 @@ void Browser::ExecuteCommand(int id) {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, TabHandlerDelegate implementation:
+
+Profile* Browser::GetProfile() const {
+ return profile();
+}
+
+Browser* Browser::AsBrowser() {
+ return this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, TabStripModelDelegate implementation:
TabContents* Browser::AddBlankTab(bool foreground) {
@@ -2287,7 +2326,8 @@ void Browser::ContinueDraggingDetachedTab(TabContents* contents,
}
int Browser::GetDragActions() const {
- return TAB_TEAROFF_ACTION | (tab_count() > 1 ? TAB_MOVE_ACTION : 0);
+ return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
+ TabStripModelDelegate::TAB_MOVE_ACTION : 0);
}
TabContents* Browser::CreateTabContentsForURL(
@@ -2295,7 +2335,8 @@ TabContents* Browser::CreateTabContentsForURL(
PageTransition::Type transition, bool defer_load,
SiteInstance* instance) const {
TabContents* contents = new TabContents(profile, instance,
- MSG_ROUTING_NONE, tabstrip_model_->GetSelectedTabContents(), NULL);
+ MSG_ROUTING_NONE,
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(), NULL);
if (!defer_load) {
// Load the initial URL before adding the new tab contents to the tab strip
@@ -2321,11 +2362,13 @@ void Browser::DuplicateContentsAt(int index) {
// If this is a tabbed browser, just create a duplicate tab inside the same
// window next to the tab being duplicated.
new_contents = contents->Clone();
- pinned = tabstrip_model_->IsTabPinned(index);
+ pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
int add_types = TabStripModel::ADD_SELECTED |
TabStripModel::ADD_INHERIT_GROUP |
(pinned ? TabStripModel::ADD_PINNED : 0);
- tabstrip_model_->InsertTabContentsAt(index + 1, new_contents, add_types);
+ tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
+ new_contents,
+ add_types);
} else {
Browser* browser = NULL;
if (type_ & TYPE_APP) {
@@ -2397,7 +2440,7 @@ bool Browser::CanReloadContents(TabContents* source) const {
bool Browser::CanCloseContentsAt(int index) {
if (!CanCloseTab())
return false;
- if (tabstrip_model_->count() > 1)
+ if (tab_handler_->GetTabStripModel()->count() > 1)
return true;
// We are closing the last tab for this browser. Make sure to check for
// in-progress downloads.
@@ -2525,9 +2568,9 @@ void Browser::TabSelectedAt(TabContents* old_contents,
// exist, the change will be picked up by sessions when created.
if (profile_->HasSessionService()) {
SessionService* session_service = profile_->GetSessionService();
- if (session_service && !tabstrip_model_->closing_all()) {
+ if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) {
session_service->SetSelectedTabInWindow(
- session_id(), tabstrip_model_->selected_index());
+ session_id(), tab_handler_->GetTabStripModel()->selected_index());
}
}
}
@@ -2544,7 +2587,7 @@ void Browser::TabReplacedAt(TabContents* old_contents,
TabContents* new_contents, int index) {
TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
TabInsertedAt(new_contents, index,
- (index == tabstrip_model_->selected_index()));
+ (index == tab_handler_->GetTabStripModel()->selected_index()));
int entry_count = new_contents->controller().entry_count();
if (entry_count > 0) {
@@ -2563,7 +2606,7 @@ void Browser::TabPinnedStateChanged(TabContents* contents, int index) {
session_service->SetPinnedState(
session_id(),
GetTabContentsAt(index)->controller().session_id(),
- tabstrip_model_->IsTabPinned(index));
+ tab_handler_->GetTabStripModel()->IsTabPinned(index));
}
}
@@ -2581,14 +2624,6 @@ void Browser::TabStripEmpty() {
}
///////////////////////////////////////////////////////////////////////////////
-// Browser, PageNavigator implementation:
-void Browser::OpenURL(const GURL& url, const GURL& referrer,
- WindowOpenDisposition disposition,
- PageTransition::Type transition) {
- OpenURLFromTab(NULL, url, referrer, disposition, transition);
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Browser, TabContentsDelegate implementation:
void Browser::OpenURLFromTab(TabContents* source,
@@ -2624,7 +2659,8 @@ void Browser::AddNewContents(TabContents* source,
// If this is a window with no tabstrip, we can only have one tab so we need
// to process this in tabbed browser window.
if (!CanSupportWindowFeature(FEATURE_TABSTRIP) &&
- tabstrip_model_->count() > 0 && disposition != NEW_WINDOW &&
+ tab_handler_->GetTabStripModel()->count() > 0 &&
+ disposition != NEW_WINDOW &&
disposition != NEW_POPUP) {
Browser* b = GetOrCreateTabbedBrowser(profile_);
DCHECK(b);
@@ -2650,7 +2686,7 @@ void Browser::AddNewContents(TabContents* source,
initial_pos, user_gesture);
browser->window()->Show();
} else if (disposition != SUPPRESS_OPEN) {
- tabstrip_model_->AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
new_contents, -1, PageTransition::LINK,
disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE);
@@ -2658,8 +2694,8 @@ void Browser::AddNewContents(TabContents* source,
}
void Browser::ActivateContents(TabContents* contents) {
- tabstrip_model_->SelectTabContentsAt(
- tabstrip_model_->GetIndexOfTabContents(contents), false);
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), false);
window_->Activate();
}
@@ -2668,7 +2704,8 @@ void Browser::DeactivateContents(TabContents* contents) {
}
void Browser::LoadingStateChanged(TabContents* source) {
- window_->UpdateLoadingAnimations(tabstrip_model_->TabsAreLoading());
+ window_->UpdateLoadingAnimations(
+ tab_handler_->GetTabStripModel()->TabsAreLoading());
window_->UpdateTitleBar();
if (source == GetSelectedTabContents()) {
@@ -2707,12 +2744,12 @@ void Browser::CloseContents(TabContents* source) {
return;
}
- int index = tabstrip_model_->GetIndexOfTabContents(source);
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseContents called for tab not in our strip";
return;
}
- tabstrip_model_->CloseTabContentsAt(
+ tab_handler_->GetTabStripModel()->CloseTabContentsAt(
index,
TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
}
@@ -2726,9 +2763,9 @@ void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
}
void Browser::DetachContents(TabContents* source) {
- int index = tabstrip_model_->GetIndexOfTabContents(source);
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source);
if (index >= 0)
- tabstrip_model_->DetachTabContentsAt(index);
+ tab_handler_->GetTabStripModel()->DetachTabContentsAt(index);
}
bool Browser::IsPopup(const TabContents* source) const {
@@ -3082,8 +3119,9 @@ void Browser::Observe(NotificationType type,
// Close any tabs from the unloaded extension.
Extension* extension = Details<Extension>(details).ptr();
- for (int i = tabstrip_model_->count() - 1; i >= 0; --i) {
- TabContents* tc = tabstrip_model_->GetTabContentsAt(i);
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = model->count() - 1; i >= 0; --i) {
+ TabContents* tc = model->GetTabContentsAt(i);
if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
tc->GetURL().host() == extension->id()) {
CloseTabContents(tc);
@@ -3203,12 +3241,13 @@ void Browser::HideMatchPreview() {
void Browser::CommitMatchPreview(TabContents* preview_contents) {
TabContents* tab_contents = match_preview_->tab_contents();
- int index = tabstrip_model_->GetIndexOfTabContents(tab_contents);
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(
+ tab_contents);
DCHECK_NE(-1, index);
preview_contents->controller().CopyStateFromAndPrune(
tab_contents->controller());
// TabStripModel takes ownership of preview_contents.
- tabstrip_model_->ReplaceTabContentsAt(
+ tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
index,
preview_contents,
TabStripModelObserver::REPLACE_MATCH_PREVIEW);
@@ -3474,8 +3513,9 @@ void Browser::ScheduleUIUpdate(const TabContents* source,
// Update the loading state synchronously. This is so the throbber will
// immediately start/stop, which gives a more snappy feel. We want to do
// this for any tab so they start & stop quickly.
- tabstrip_model_->UpdateTabContentsStateAt(
- tabstrip_model_->GetIndexOfController(&source->controller()),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfController(
+ &source->controller()),
TabStripModelObserver::LOADING_ONLY);
// The status bubble needs to be updated during INVALIDATE_LOAD too, but
// we do that asynchronously by not stripping INVALIDATE_LOAD from
@@ -3487,8 +3527,9 @@ void Browser::ScheduleUIUpdate(const TabContents* source,
// we need to process the update synchronously. This state only matters for
// the TabStripModel, so we notify the TabStripModel now and notify others
// asynchronously.
- tabstrip_model_->UpdateTabContentsStateAt(
- tabstrip_model_->GetIndexOfController(&source->controller()),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfController(
+ &source->controller()),
TabStripModelObserver::TITLE_NOT_LOADING);
}
@@ -3564,8 +3605,8 @@ void Browser::ProcessPendingUIUpdates() {
// Updates that don't depend upon the selected state go here.
if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) {
- tabstrip_model_->UpdateTabContentsStateAt(
- tabstrip_model_->GetIndexOfTabContents(contents),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents),
TabStripModelObserver::ALL);
}
@@ -3610,9 +3651,10 @@ void Browser::SyncHistoryWithTabs(int index) {
if (contents) {
session_service->SetTabIndexInWindow(
session_id(), contents->controller().session_id(), i);
- session_service->SetPinnedState(session_id(),
- contents->controller().session_id(),
- tabstrip_model_->IsTabPinned(i));
+ session_service->SetPinnedState(
+ session_id(),
+ contents->controller().session_id(),
+ tab_handler_->GetTabStripModel()->IsTabPinned(i));
}
}
}
@@ -3897,7 +3939,7 @@ void Browser::OpenURLAtIndex(TabContents* source,
&browser);
browser->window()->Show();
} else if ((disposition == CURRENT_TAB) && current_tab) {
- tabstrip_model_->TabNavigating(current_tab, transition);
+ tab_handler_->GetTabStripModel()->TabNavigating(current_tab, transition);
bool user_initiated = (PageTransition::StripQualifier(transition) ==
PageTransition::AUTO_BOOKMARK);
@@ -4017,15 +4059,17 @@ void Browser::TabDetachedAtImpl(TabContents* contents, int index,
// Save what the user's currently typed.
window_->GetLocationBar()->SaveStateToContents(contents);
- if (!tabstrip_model_->closing_all())
+ if (!tab_handler_->GetTabStripModel()->closing_all())
SyncHistoryWithTabs(0);
}
contents->set_delegate(NULL);
RemoveScheduledUpdatesFor(contents);
- if (find_bar_controller_.get() && index == tabstrip_model_->selected_index())
+ if (find_bar_controller_.get() &&
+ index == tab_handler_->GetTabStripModel()->selected_index()) {
find_bar_controller_->ChangeTabContents(NULL);
+ }
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
Source<TabContents>(contents));
@@ -4054,23 +4098,6 @@ void Browser::RegisterAppPrefs(const std::string& app_name) {
prefs->RegisterDictionaryPref(window_pref.c_str());
}
-// static
-bool Browser::RunUnloadEventsHelper(TabContents* contents) {
- // If the TabContents is not connected yet, then there's no unload
- // handler we can fire even if the TabContents has an unload listener.
- // One case where we hit this is in a tab that has an infinite loop
- // before load.
- if (TabHasUnloadListener(contents)) {
- // If the page has unload listeners, then we tell the renderer to fire
- // them. Once they have fired, we'll get a message back saying whether
- // to proceed closing the page or not, which sends us back to this method
- // with the HasUnloadListener bit cleared.
- contents->render_view_host()->FirePageBeforeUnload(false);
- return true;
- }
- return false;
-}
-
void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
!service->entries().empty());
@@ -4098,7 +4125,7 @@ bool Browser::OpenMatchPreview(WindowOpenDisposition disposition) {
TabContents* preview_contents = match_preview()->ReleasePreviewContents(
MatchPreview::COMMIT_PRESSED_ENTER);
preview_contents->controller().PruneAllButActive();
- tabstrip_model_->AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
preview_contents,
-1,
match_preview()->last_transition_type(),
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 27e8db0..695d353 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -23,8 +23,9 @@
#include "chrome/browser/sessions/tab_restore_service_observer.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
-#include "chrome/browser/tabs/tab_strip_model_delegate.h"
-#include "chrome/browser/tabs/tab_strip_model_observer.h"
+#include "chrome/browser/tabs/tab_handler.h"
+#include "chrome/browser/tabs/tab_strip_model_delegate.h" // TODO(beng): remove
+#include "chrome/browser/tabs/tab_strip_model_observer.h" // TODO(beng): remove
#include "chrome/browser/tab_contents/match_preview_delegate.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -50,8 +51,7 @@ namespace gfx {
class Point;
}
-class Browser : public TabStripModelDelegate,
- public TabStripModelObserver,
+class Browser : public TabHandlerDelegate,
public TabContentsDelegate,
public PageNavigator,
public CommandUpdater::CommandUpdaterDelegate,
@@ -316,7 +316,8 @@ class Browser : public TabStripModelDelegate,
// TabStripModel pass-thrus /////////////////////////////////////////////////
TabStripModel* tabstrip_model() const {
- return const_cast<TabStripModel*>(tabstrip_model_.get());
+ // TODO(beng): remove this accessor. It violates google style.
+ return tab_handler_->GetTabStripModel();
}
int tab_count() const;
@@ -566,6 +567,9 @@ class Browser : public TabStripModelDelegate,
static void RegisterPrefs(PrefService* prefs);
static void RegisterUserPrefs(PrefService* prefs);
+ // Helper function to run unload listeners on a TabContents.
+ static bool RunUnloadEventsHelper(TabContents* contents);
+
// Returns the Browser which contains the tab with the given
// NavigationController, also filling in |index| (if valid) with the tab's
// index in the tab strip.
@@ -610,7 +614,7 @@ class Browser : public TabStripModelDelegate,
// Interface implementations ////////////////////////////////////////////////
- // Overridden from PageNavigator
+ // Overridden from PageNavigator:
virtual void OpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition);
@@ -618,28 +622,13 @@ class Browser : public TabStripModelDelegate,
// Overridden from CommandUpdater::CommandUpdaterDelegate:
virtual void ExecuteCommand(int id);
- // Helper function to run unload listeners on a TabContents.
- static bool RunUnloadEventsHelper(TabContents* contents);
-
- // TabRestoreServiceObserver /////////////////////////////////////////////////
+ // Overridden from TabRestoreServiceObserver:
virtual void TabRestoreServiceChanged(TabRestoreService* service);
virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
- private:
- FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups);
-
- // Used to describe why a tab is being detached. This is used by
- // TabDetachedAtImpl.
- enum DetachType {
- // Result of TabDetachedAt.
- DETACH_TYPE_DETACH,
-
- // Result of TabReplacedAt.
- DETACH_TYPE_REPLACE,
-
- // Result of the tab strip not having any significant tabs.
- DETACH_TYPE_EMPTY
- };
+ // Overridden from TabHandlerDelegate:
+ virtual Profile* GetProfile() const;
+ virtual Browser* AsBrowser();
// Overridden from TabStripModelDelegate:
virtual TabContents* AddBlankTab(bool foreground);
@@ -694,6 +683,22 @@ class Browser : public TabStripModelDelegate,
virtual void TabPinnedStateChanged(TabContents* contents, int index);
virtual void TabStripEmpty();
+ private:
+ FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups);
+
+ // Used to describe why a tab is being detached. This is used by
+ // TabDetachedAtImpl.
+ enum DetachType {
+ // Result of TabDetachedAt.
+ DETACH_TYPE_DETACH,
+
+ // Result of TabReplacedAt.
+ DETACH_TYPE_REPLACE,
+
+ // Result of the tab strip not having any significant tabs.
+ DETACH_TYPE_EMPTY
+ };
+
// Overridden from TabContentsDelegate:
virtual void OpenURLFromTab(TabContents* source,
const GURL& url,
@@ -977,8 +982,8 @@ class Browser : public TabStripModelDelegate,
// This Browser's window.
BrowserWindow* window_;
- // This Browser's TabStripModel.
- scoped_ptr<TabStripModel> tabstrip_model_;
+ // This Browser's current TabHandler.
+ scoped_ptr<TabHandler> tab_handler_;
// The CommandUpdater that manages the browser window commands.
CommandUpdater command_updater_;
diff --git a/chrome/browser/tabs/default_tab_handler.cc b/chrome/browser/tabs/default_tab_handler.cc
new file mode 100644
index 0000000..5149173
--- /dev/null
+++ b/chrome/browser/tabs/default_tab_handler.cc
@@ -0,0 +1,198 @@
+// 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/tabs/default_tab_handler.h"
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultTabHandler, public:
+
+DefaultTabHandler::DefaultTabHandler(TabHandlerDelegate* delegate)
+ : delegate_(delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ model_(new TabStripModel(this, delegate->GetProfile()))) {
+ model_->AddObserver(this);
+}
+
+DefaultTabHandler::~DefaultTabHandler() {
+ // The tab strip should not have any significant tabs at this point.
+ DCHECK(!model_->HasNonPhantomTabs());
+ model_->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultTabHandler, TabHandler implementation:
+
+TabStripModel* DefaultTabHandler::GetTabStripModel() const {
+ return model_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultTabHandler, TabStripModelDelegate implementation:
+
+TabContents* DefaultTabHandler::AddBlankTab(bool foreground) {
+ return delegate_->AsBrowser()->AddBlankTab(foreground);
+}
+
+TabContents* DefaultTabHandler::AddBlankTabAt(int index, bool foreground) {
+ return delegate_->AsBrowser()->AddBlankTabAt(index, foreground);
+}
+
+Browser* DefaultTabHandler::CreateNewStripWithContents(
+ TabContents* detached_contents,
+ const gfx::Rect& window_bounds,
+ const DockInfo& dock_info,
+ bool maximize) {
+ return delegate_->AsBrowser()->CreateNewStripWithContents(detached_contents,
+ window_bounds,
+ dock_info,
+ maximize);
+}
+
+void DefaultTabHandler::ContinueDraggingDetachedTab(
+ TabContents* contents,
+ const gfx::Rect& window_bounds,
+ const gfx::Rect& tab_bounds) {
+ delegate_->AsBrowser()->ContinueDraggingDetachedTab(contents,
+ window_bounds,
+ tab_bounds);
+}
+
+int DefaultTabHandler::GetDragActions() const {
+ return delegate_->AsBrowser()->GetDragActions();
+}
+
+TabContents* DefaultTabHandler::CreateTabContentsForURL(
+ const GURL& url,
+ const GURL& referrer,
+ Profile* profile,
+ PageTransition::Type transition,
+ bool defer_load,
+ SiteInstance* instance) const {
+ return delegate_->AsBrowser()->CreateTabContentsForURL(url,
+ referrer,
+ profile,
+ transition,
+ defer_load,
+ instance);
+}
+
+bool DefaultTabHandler::CanDuplicateContentsAt(int index) {
+ return delegate_->AsBrowser()->CanDuplicateContentsAt(index);
+}
+
+void DefaultTabHandler::DuplicateContentsAt(int index) {
+ delegate_->AsBrowser()->DuplicateContentsAt(index);
+}
+
+void DefaultTabHandler::CloseFrameAfterDragSession() {
+ delegate_->AsBrowser()->CloseFrameAfterDragSession();
+}
+
+void DefaultTabHandler::CreateHistoricalTab(TabContents* contents) {
+ delegate_->AsBrowser()->CreateHistoricalTab(contents);
+}
+
+bool DefaultTabHandler::RunUnloadListenerBeforeClosing(TabContents* contents) {
+ return delegate_->AsBrowser()->RunUnloadListenerBeforeClosing(contents);
+}
+
+bool DefaultTabHandler::CanCloseContentsAt(int index) {
+ return delegate_->AsBrowser()->CanCloseContentsAt(index);
+}
+
+bool DefaultTabHandler::CanBookmarkAllTabs() const {
+ return delegate_->AsBrowser()->CanBookmarkAllTabs();
+}
+
+void DefaultTabHandler::BookmarkAllTabs() {
+ delegate_->AsBrowser()->BookmarkAllTabs();
+}
+
+bool DefaultTabHandler::CanCloseTab() const {
+ return delegate_->AsBrowser()->CanCloseTab();
+}
+
+void DefaultTabHandler::ToggleUseVerticalTabs() {
+ delegate_->AsBrowser()->ToggleUseVerticalTabs();
+}
+
+bool DefaultTabHandler::CanRestoreTab() {
+ return delegate_->AsBrowser()->CanRestoreTab();
+}
+
+void DefaultTabHandler::RestoreTab() {
+ delegate_->AsBrowser()->RestoreTab();
+}
+
+bool DefaultTabHandler::LargeIconsPermitted() const {
+ return delegate_->AsBrowser()->LargeIconsPermitted();
+}
+
+bool DefaultTabHandler::UseVerticalTabs() const {
+ return delegate_->AsBrowser()->UseVerticalTabs();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DefaultTabHandler, TabStripModelObserver implementation:
+
+void DefaultTabHandler::TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground) {
+ delegate_->AsBrowser()->TabInsertedAt(contents, index, foreground);
+}
+
+void DefaultTabHandler::TabClosingAt(TabContents* contents, int index) {
+ delegate_->AsBrowser()->TabClosingAt(contents, index);
+}
+
+void DefaultTabHandler::TabDetachedAt(TabContents* contents, int index) {
+ delegate_->AsBrowser()->TabDetachedAt(contents, index);
+}
+
+void DefaultTabHandler::TabDeselectedAt(TabContents* contents, int index) {
+ delegate_->AsBrowser()->TabDeselectedAt(contents, index);
+}
+
+void DefaultTabHandler::TabSelectedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ bool user_gesture) {
+ delegate_->AsBrowser()->TabSelectedAt(old_contents,
+ new_contents,
+ index,
+ user_gesture);
+}
+
+void DefaultTabHandler::TabMoved(TabContents* contents,
+ int from_index,
+ int to_index) {
+ delegate_->AsBrowser()->TabMoved(contents, from_index, to_index);
+}
+
+void DefaultTabHandler::TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index) {
+ delegate_->AsBrowser()->TabReplacedAt(old_contents, new_contents, index);
+}
+
+void DefaultTabHandler::TabPinnedStateChanged(TabContents* contents,
+ int index) {
+ delegate_->AsBrowser()->TabPinnedStateChanged(contents, index);
+}
+
+void DefaultTabHandler::TabStripEmpty() {
+ delegate_->AsBrowser()->TabStripEmpty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TabHandler, public:
+
+// static
+TabHandler* TabHandler::CreateTabHandler(TabHandlerDelegate* delegate) {
+ return new DefaultTabHandler(delegate);
+}
+
diff --git a/chrome/browser/tabs/default_tab_handler.h b/chrome/browser/tabs/default_tab_handler.h
new file mode 100644
index 0000000..8a2af16
--- /dev/null
+++ b/chrome/browser/tabs/default_tab_handler.h
@@ -0,0 +1,88 @@
+// 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_TABS_DEFAULT_TAB_HANDLER_H_
+#define CHROME_BROWSER_TABS_DEFAULT_TAB_HANDLER_H_
+#pragma once
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/tabs/tab_handler.h"
+#include "chrome/browser/tabs/tab_strip_model_delegate.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
+
+// A TabHandler implementation that interacts with the default TabStripModel.
+// The intent is that the TabStripModel API is contained at this level, and
+// never propagates beyond to the Browser.
+class DefaultTabHandler : public TabHandler,
+ public TabStripModelDelegate,
+ public TabStripModelObserver {
+ public:
+ explicit DefaultTabHandler(TabHandlerDelegate* delegate);
+ virtual ~DefaultTabHandler();
+
+ // Overridden from TabHandler:
+ virtual TabStripModel* GetTabStripModel() const;
+
+ // Overridden from TabStripModelDelegate:
+ virtual TabContents* AddBlankTab(bool foreground);
+ virtual TabContents* AddBlankTabAt(int index, bool foreground);
+ virtual Browser* CreateNewStripWithContents(TabContents* detached_contents,
+ const gfx::Rect& window_bounds,
+ const DockInfo& dock_info,
+ bool maximize);
+ virtual void ContinueDraggingDetachedTab(TabContents* contents,
+ const gfx::Rect& window_bounds,
+ const gfx::Rect& tab_bounds);
+ virtual int GetDragActions() const;
+ virtual TabContents* CreateTabContentsForURL(const GURL& url,
+ const GURL& referrer,
+ Profile* profile,
+ PageTransition::Type transition,
+ bool defer_load,
+ SiteInstance* instance) const;
+ virtual bool CanDuplicateContentsAt(int index);
+ virtual void DuplicateContentsAt(int index);
+ virtual void CloseFrameAfterDragSession();
+ virtual void CreateHistoricalTab(TabContents* contents);
+ virtual bool RunUnloadListenerBeforeClosing(TabContents* contents);
+ virtual bool CanCloseContentsAt(int index);
+ virtual bool CanBookmarkAllTabs() const;
+ virtual void BookmarkAllTabs();
+ virtual bool CanCloseTab() const;
+ virtual void ToggleUseVerticalTabs();
+ virtual bool CanRestoreTab();
+ virtual void RestoreTab();
+ virtual bool LargeIconsPermitted() const;
+ virtual bool UseVerticalTabs() const;
+
+ // Overridden from TabStripModelObserver:
+ virtual void TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground);
+ virtual void TabClosingAt(TabContents* contents, int index);
+ virtual void TabDetachedAt(TabContents* contents, int index);
+ virtual void TabDeselectedAt(TabContents* contents, int index);
+ virtual void TabSelectedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ bool user_gesture);
+ virtual void TabMoved(TabContents* contents,
+ int from_index,
+ int to_index);
+ virtual void TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index);
+ virtual void TabPinnedStateChanged(TabContents* contents, int index);
+ virtual void TabStripEmpty();
+
+ private:
+ TabHandlerDelegate* delegate_;
+
+ scoped_ptr<TabStripModel> model_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultTabHandler);
+};
+
+#endif // CHROME_BROWSER_TABS_DEFAULT_TAB_HANDLER_H_
+
diff --git a/chrome/browser/tabs/tab_handler.h b/chrome/browser/tabs/tab_handler.h
new file mode 100644
index 0000000..e67aece
--- /dev/null
+++ b/chrome/browser/tabs/tab_handler.h
@@ -0,0 +1,36 @@
+// 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_TABS_TAB_HANDLER_H_
+#define CHROME_BROWSER_TABS_TAB_HANDLER_H_
+#pragma once
+
+class Browser;
+class Profile;
+class TabStripModel;
+
+class TabHandlerDelegate {
+ public:
+ virtual Profile* GetProfile() const = 0;
+
+ // TODO(beng): remove once decoupling with Browser is complete.
+ virtual Browser* AsBrowser() = 0;
+};
+
+// An interface implemented by an object that can perform tab related
+// functionality for a Browser. This functionality includes mapping individual
+// TabContentses into indices for an index-based tab organization scheme for
+// example.
+class TabHandler {
+ public:
+ // Creates a TabHandler implementation and returns it, transferring ownership
+ // to the caller.
+ static TabHandler* CreateTabHandler(TabHandlerDelegate* delegate);
+
+ // TODO(beng): remove once decoupling with Browser is complete.
+ virtual TabStripModel* GetTabStripModel() const = 0;
+};
+
+#endif // CHROME_BROWSER_TABS_TAB_HANDLER_H_
+
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 7575488..6bbe52d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2755,10 +2755,13 @@
'browser/tab_contents/web_drop_target_win.h',
'browser/tab_menu_model.cc',
'browser/tab_menu_model.h',
+ 'browser/tabs/default_tab_handler.cc',
+ 'browser/tabs/default_tab_handler.h',
'browser/tabs/pinned_tab_codec.cc',
'browser/tabs/pinned_tab_codec.h',
'browser/tabs/pinned_tab_service.cc',
'browser/tabs/pinned_tab_service.h',
+ 'browser/tabs/tab_handler.h',
'browser/tabs/tab_strip_model.cc',
'browser/tabs/tab_strip_model.h',
'browser/tabs/tab_strip_model_delegate.h',