diff options
35 files changed, 342 insertions, 63 deletions
diff --git a/app/app_base.gypi b/app/app_base.gypi index 802a0d2..c89dcb8 100644 --- a/app/app_base.gypi +++ b/app/app_base.gypi @@ -185,9 +185,6 @@ 'conditions': [ ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { 'dependencies': [ - # font_gtk.cc uses fontconfig. - # TODO(evanm): I think this is wrong; it should just use GTK. - '../build/linux/system.gyp:fontconfig', '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:x11', ], diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index bd50e67..5abde69 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4596,6 +4596,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_TAB_CXMENU_BOOKMARK_ALL_TABS" desc="In Title Case: The label of the tab context menu item for creating a bookmark folder containing an entry for each open tab."> Bookmark all tabs... </message> + <message name="IDS_TAB_CXMENU_USE_VERTICAL_TABS" desc="Use the vertical tab strip"> + Use side tabs + </message> </if> <if expr="pp_ifdef('use_titlecase')"> <message name="IDS_TAB_CXMENU_NEWTAB" desc="In Title Case: The label of the 'New Tab' Tab context menu item."> diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 73913c2..0bcc571 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -194,6 +194,7 @@ Browser::Browser(Type type, Profile* profile) encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, profile_->GetPrefs(), NULL); + use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this); } Browser::~Browser() { @@ -1632,7 +1633,7 @@ void Browser::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true); prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true); prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true); - prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, true); + prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false); prefs->RegisterBooleanPref(prefs::kEnableTranslate, true); } @@ -2063,6 +2064,15 @@ void Browser::BookmarkAllTabs() { BookmarkEditor::SHOW_TREE, NULL); } +bool Browser::UseVerticalTabs() const { + return use_vertical_tabs_.GetValue(); +} + +void Browser::ToggleUseVerticalTabs() { + use_vertical_tabs_.SetValue(!UseVerticalTabs()); + window()->ToggleTabStripMode(); +} + /////////////////////////////////////////////////////////////////////////////// // Browser, TabStripModelObserver implementation: diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 9d81731..2ce763d 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -603,6 +603,8 @@ class Browser : public TabStripModelDelegate, virtual bool CanCloseContentsAt(int index); virtual bool CanBookmarkAllTabs() const; virtual void BookmarkAllTabs(); + virtual bool UseVerticalTabs() const; + virtual void ToggleUseVerticalTabs(); // Overridden from TabStripModelObserver: virtual void TabInsertedAt(TabContents* contents, @@ -946,6 +948,9 @@ class Browser : public TabStripModelDelegate, // from a TabContents. Currently, only one pending action is allowed. WebAppAction pending_web_app_action_; + // Tracks the display mode of the tabstrip. + mutable BooleanPrefMember use_vertical_tabs_; + DISALLOW_COPY_AND_ASSIGN(Browser); }; diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index e0d7001..142ebf9 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -307,6 +307,9 @@ class BrowserWindow { virtual void Copy() = 0; virtual void Paste() = 0; + // Switches between available tabstrip display modes. + virtual void ToggleTabStripMode() = 0; + // Construct a BrowserWindow implementation for the specified |browser|. static BrowserWindow* CreateBrowserWindow(Browser* browser); diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h index 753a645..bc3a294 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.h +++ b/chrome/browser/cocoa/browser_window_cocoa.h @@ -103,6 +103,7 @@ class BrowserWindowCocoa : public BrowserWindow, virtual void Cut(); virtual void Copy(); virtual void Paste(); + virtual void ToggleTabStripMode(); // Overridden from NotificationObserver virtual void Observe(NotificationType type, diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index 186ec86..eb4c81f 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -529,6 +529,10 @@ void BrowserWindowCocoa::Paste() { [NSApp sendAction:@selector(paste:) to:nil from:nil]; } +void BrowserWindowCocoa::ToggleTabStripMode() { + NOTIMPLEMENTED(); +} + void BrowserWindowCocoa::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm index 82cea8e..aef454f 100644 --- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm +++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm @@ -63,6 +63,8 @@ class TestTabStripDelegate : public TabStripModelDelegate { virtual bool CanBookmarkAllTabs() const { return false; } virtual void BookmarkAllTabs() {} + virtual bool UseVerticalTabs() const { return false; } + virtual void ToggleUseVerticalTabs() {} }; class TabStripControllerTest : public CocoaTest { diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index e31d564..eebd745 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -1054,6 +1054,10 @@ void BrowserWindowGtk::Paste() { DoCutCopyPaste(this, &RenderViewHost::Paste, "paste-clipboard"); } +void BrowserWindowGtk::ToggleTabStripMode() { + NOTIMPLEMENTED(); +} + void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() { new DownloadInProgressDialogGtk(browser()); } diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index 53e58cc..24e0c7f 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -121,6 +121,7 @@ class BrowserWindowGtk : public BrowserWindow, virtual void Cut(); virtual void Copy(); virtual void Paste(); + virtual void ToggleTabStripMode(); // Overridden from NotificationObserver: virtual void Observe(NotificationType type, diff --git a/chrome/browser/tab_menu_model.cc b/chrome/browser/tab_menu_model.cc index d2b38ce..8791728 100644 --- a/chrome/browser/tab_menu_model.cc +++ b/chrome/browser/tab_menu_model.cc @@ -41,4 +41,9 @@ void TabMenuModel::Build() { AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB); AddItemWithStringId(TabStripModel::CommandBookmarkAllTabs, IDS_TAB_CXMENU_BOOKMARK_ALL_TABS); +#if defined(OS_WIN) + AddSeparator(); + AddCheckItemWithStringId(TabStripModel::CommandUseVerticalTabs, + IDS_TAB_CXMENU_USE_VERTICAL_TABS); +#endif } diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index b5095a2..b8c52b2 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -574,11 +574,25 @@ bool TabStripModel::IsContextMenuCommandEnabled( return delegate_->CanRestoreTab(); case CommandTogglePinned: return true; - case CommandBookmarkAllTabs: { + case CommandBookmarkAllTabs: return delegate_->CanBookmarkAllTabs(); - } + case CommandUseVerticalTabs: + return true; + default: + NOTREACHED(); + } + return false; +} + +bool TabStripModel::IsContextMenuCommandChecked( + int context_index, + ContextMenuCommand command_id) const { + switch (command_id) { + case CommandUseVerticalTabs: + return delegate()->UseVerticalTabs(); default: NOTREACHED(); + break; } return false; } @@ -655,6 +669,14 @@ void TabStripModel::ExecuteContextMenuCommand( delegate_->BookmarkAllTabs(); break; } + case CommandUseVerticalTabs: { + UserMetrics::RecordAction( + UserMetricsAction("TabContextMenu_UseVerticalTabs"), + profile_); + + delegate()->ToggleUseVerticalTabs(); + break; + } default: NOTREACHED(); } diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h index 427fb6e..90b4419 100644 --- a/chrome/browser/tabs/tab_strip_model.h +++ b/chrome/browser/tabs/tab_strip_model.h @@ -223,6 +223,12 @@ class TabStripModelDelegate { // Creates a bookmark folder containing a bookmark for all open tabs. virtual void BookmarkAllTabs() = 0; + + // Returns true if the vertical tabstrip presentation should be used. + virtual bool UseVerticalTabs() const = 0; + + // Toggles the use of the vertical tabstrip. + virtual void ToggleUseVerticalTabs() = 0; }; //////////////////////////////////////////////////////////////////////////////// @@ -547,6 +553,7 @@ class TabStripModel : public NotificationObserver { CommandRestoreTab, CommandTogglePinned, CommandBookmarkAllTabs, + CommandUseVerticalTabs, CommandLast }; @@ -554,6 +561,10 @@ class TabStripModel : public NotificationObserver { bool IsContextMenuCommandEnabled(int context_index, ContextMenuCommand command_id) const; + // Returns true if the specified command is checked. + bool IsContextMenuCommandChecked(int context_index, + ContextMenuCommand command_id) const; + // Performs the action associated with the specified command for the given // TabStripModel index |context_index|. void ExecuteContextMenuCommand(int context_index, diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc index 451cc81..44c56e6 100644 --- a/chrome/browser/tabs/tab_strip_model_unittest.cc +++ b/chrome/browser/tabs/tab_strip_model_unittest.cc @@ -71,6 +71,8 @@ class TabStripDummyDelegate : public TabStripModelDelegate { virtual bool CanCloseContentsAt(int index) { return can_close_ ; } virtual bool CanBookmarkAllTabs() const { return false; } virtual void BookmarkAllTabs() {} + virtual bool UseVerticalTabs() const { return false; } + virtual void ToggleUseVerticalTabs() {} private: // A dummy TabContents we give to callers that expect us to actually build a diff --git a/chrome/browser/views/frame/browser_frame.h b/chrome/browser/views/frame/browser_frame.h index fd94d51..392200d 100644 --- a/chrome/browser/views/frame/browser_frame.h +++ b/chrome/browser/views/frame/browser_frame.h @@ -41,10 +41,6 @@ class BrowserFrame { // construction. virtual views::Window* GetWindow() = 0; - // Notification that the tab strip has been created. This should let the - // BrowserRootView know about it so it can enable drag and drop. - virtual void TabStripCreated(BaseTabStrip* tabstrip) = 0; - // Determine the distance of the left edge of the minimize button from the // left edge of the window. Used in our Non-Client View's Layout. virtual int GetMinimizeButtonOffset() const = 0; @@ -74,6 +70,10 @@ class BrowserFrame { // calls this method _after_ the TabStrip has painted itself so the shadow is // rendered above the tabs. virtual void PaintTabStripShadow(gfx::Canvas* canvas) = 0; + + // Notifies the frame that the tab strip display mode changed so it can update + // its frame treatment if necessary. + virtual void TabStripDisplayModeChanged() = 0; }; #endif // CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_ diff --git a/chrome/browser/views/frame/browser_frame_gtk.cc b/chrome/browser/views/frame/browser_frame_gtk.cc index ef6f5a1..67804b0 100644 --- a/chrome/browser/views/frame/browser_frame_gtk.cc +++ b/chrome/browser/views/frame/browser_frame_gtk.cc @@ -102,9 +102,6 @@ views::Window* BrowserFrameGtk::GetWindow() { return this; } -void BrowserFrameGtk::TabStripCreated(BaseTabStrip* tabstrip) { -} - int BrowserFrameGtk::GetMinimizeButtonOffset() const { NOTIMPLEMENTED(); return 0; @@ -139,6 +136,9 @@ views::View* BrowserFrameGtk::GetFrameView() const { void BrowserFrameGtk::PaintTabStripShadow(gfx::Canvas* canvas) { } +void BrowserFrameGtk::TabStripDisplayModeChanged() { +} + ThemeProvider* BrowserFrameGtk::GetThemeProvider() const { return profile_->GetThemeProvider(); } diff --git a/chrome/browser/views/frame/browser_frame_gtk.h b/chrome/browser/views/frame/browser_frame_gtk.h index 93330c1..f8e8f2a 100644 --- a/chrome/browser/views/frame/browser_frame_gtk.h +++ b/chrome/browser/views/frame/browser_frame_gtk.h @@ -28,7 +28,6 @@ class BrowserFrameGtk : public BrowserFrame, // Overridden from BrowserFrame: virtual views::Window* GetWindow(); - virtual void TabStripCreated(BaseTabStrip* tabstrip); virtual int GetMinimizeButtonOffset() const; virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const; virtual void UpdateThrobber(bool running); @@ -37,6 +36,7 @@ class BrowserFrameGtk : public BrowserFrame, virtual bool AlwaysUseNativeFrame() const; virtual views::View* GetFrameView() const; virtual void PaintTabStripShadow(gfx::Canvas* canvas); + virtual void TabStripDisplayModeChanged(); // Overridden from views::Widget: virtual ThemeProvider* GetThemeProvider() const; diff --git a/chrome/browser/views/frame/browser_frame_win.cc b/chrome/browser/views/frame/browser_frame_win.cc index 0092fa7..c9ed058 100644 --- a/chrome/browser/views/frame/browser_frame_win.cc +++ b/chrome/browser/views/frame/browser_frame_win.cc @@ -72,9 +72,6 @@ views::Window* BrowserFrameWin::GetWindow() { return this; } -void BrowserFrameWin::TabStripCreated(BaseTabStrip* tabstrip) { -} - int BrowserFrameWin::GetMinimizeButtonOffset() const { TITLEBARINFOEX titlebar_info; titlebar_info.cbSize = sizeof(TITLEBARINFOEX); @@ -130,6 +127,14 @@ void BrowserFrameWin::PaintTabStripShadow(gfx::Canvas* canvas) { browser_frame_view_->PaintTabStripShadow(canvas); } +void BrowserFrameWin::TabStripDisplayModeChanged() { + UpdateDWMFrame(); + // We need to relayout only after the window frame has had a chance to update + // the size/position of its controls (e.g. minimize/maximize/close) so that + // the tabstrip can layout at its correct bounds. + GetRootView()->Layout(); +} + /////////////////////////////////////////////////////////////////////////////// // BrowserFrame, views::WindowWin overrides: @@ -300,7 +305,7 @@ void BrowserFrameWin::UpdateDWMFrame() { // In maximized mode, we only have a titlebar strip of glass, no side/bottom // borders. if (!browser_view_->IsFullscreen()) { - if (browser_view_->UsingSideTabs()) { + if (browser_view_->UseVerticalTabs()) { margins.cxLeftWidth += GetBoundsForTabStrip(browser_view_->tabstrip()).right(); margins.cyTopHeight += GetSystemMetrics(SM_CYSIZEFRAME); @@ -316,7 +321,7 @@ void BrowserFrameWin::UpdateDWMFrame() { DwmExtendFrameIntoClientArea(GetNativeView(), &margins); DWORD window_style = GetWindowLong(GWL_STYLE); - if (browser_view_->UsingSideTabs()) { + if (browser_view_->UseVerticalTabs()) { if (window_style & WS_CAPTION) SetWindowLong(GWL_STYLE, window_style & ~WS_CAPTION); } else { diff --git a/chrome/browser/views/frame/browser_frame_win.h b/chrome/browser/views/frame/browser_frame_win.h index d928f93..42e8974 100644 --- a/chrome/browser/views/frame/browser_frame_win.h +++ b/chrome/browser/views/frame/browser_frame_win.h @@ -37,7 +37,6 @@ class BrowserFrameWin : public BrowserFrame, public views::WindowWin { // BrowserFrame implementation. virtual views::Window* GetWindow(); - virtual void TabStripCreated(BaseTabStrip* tabstrip); virtual int GetMinimizeButtonOffset() const; virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const; virtual void UpdateThrobber(bool running); @@ -46,6 +45,7 @@ class BrowserFrameWin : public BrowserFrame, public views::WindowWin { virtual bool AlwaysUseNativeFrame() const; virtual views::View* GetFrameView() const; virtual void PaintTabStripShadow(gfx::Canvas* canvas); + virtual void TabStripDisplayModeChanged(); protected: // Overridden from views::WindowWin: diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index f96964a..e295160 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -523,8 +523,8 @@ bool BrowserView::IsTabStripVisible() const { return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); } -bool BrowserView::UsingSideTabs() const { - return SideTabStrip::Visible(browser_->profile()); +bool BrowserView::UseVerticalTabs() const { + return browser_->tabstrip_model()->delegate()->UseVerticalTabs(); } bool BrowserView::IsOffTheRecord() const { @@ -1203,6 +1203,11 @@ void BrowserView::Paste() { false, false); } +void BrowserView::ToggleTabStripMode() { + InitTabStrip(browser_->tabstrip_model()); + frame_->TabStripDisplayModeChanged(); +} + /////////////////////////////////////////////////////////////////////////////// // BrowserView, BrowserWindowTesting implementation: @@ -1606,13 +1611,32 @@ views::LayoutManager* BrowserView::CreateLayoutManager() const { return new BrowserViewLayout; } -BaseTabStrip* BrowserView::CreateTabStrip(TabStripModel* model) { - if (UsingSideTabs()) { +void BrowserView::InitTabStrip(TabStripModel* model) { +// Throw away the existing tabstrip if we're switching display modes. + if (tabstrip_) { + tabstrip_->GetParent()->RemoveChildView(tabstrip_); + delete tabstrip_; + } + + TabStrip* tabstrip_as_tabstrip = NULL; + BrowserTabStripController* tabstrip_controller = NULL; + + if (UseVerticalTabs()) { SideTabStrip* tabstrip = new SideTabStrip; - tabstrip->SetModel(new BrowserTabStripController(model, tabstrip)); - return tabstrip; + tabstrip_controller = new BrowserTabStripController(model, tabstrip); + tabstrip->SetModel(tabstrip_controller); + tabstrip_ = tabstrip; + } else { + tabstrip_as_tabstrip = new TabStrip(model); + tabstrip_ = tabstrip_as_tabstrip; } - return new TabStrip(model); + tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP)); + AddChildView(tabstrip_); + + if (tabstrip_controller) + tabstrip_controller->InitFromModel(); + else + tabstrip_as_tabstrip->InitFromModel(); } /////////////////////////////////////////////////////////////////////////////// @@ -1639,10 +1663,7 @@ void BrowserView::Init() { LoadAccelerators(); SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); - tabstrip_ = CreateTabStrip(browser_->tabstrip_model()); - tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP)); - AddChildView(tabstrip_); - frame_->TabStripCreated(tabstrip_); + InitTabStrip(browser_->tabstrip_model()); toolbar_ = new ToolbarView(browser_.get()); AddChildView(toolbar_); diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 1e5b361..0ed69d0 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -155,7 +155,7 @@ class BrowserView : public BrowserBubbleHost, bool IsTabStripVisible() const; // Returns true if the vertical tabstrip is in use. - bool UsingSideTabs() const; + bool UseVerticalTabs() const; // Returns true if the profile associated with this Browser window is // off the record. @@ -321,6 +321,7 @@ class BrowserView : public BrowserBubbleHost, virtual void Cut(); virtual void Copy(); virtual void Paste(); + virtual void ToggleTabStripMode(); // Overridden from BrowserWindowTesting: virtual BookmarkBarView* GetBookmarkBarView() const; @@ -394,9 +395,10 @@ class BrowserView : public BrowserBubbleHost, // override to implemnet different layout pocily. virtual views::LayoutManager* CreateLayoutManager() const; - // Returns a new TabStrip for the browser view. A subclass may - // override to return a different TabStrip implementation. - virtual BaseTabStrip* CreateTabStrip(TabStripModel* tab_strip_model); + // Initializes a new TabStrip for the browser view. This can be performed + // multiple times over the life of the browser, and is run when the display + // mode for the tabstrip changes from horizontal to vertical. + void InitTabStrip(TabStripModel* tab_strip_model); // Browser window related initializations. virtual void Init(); diff --git a/chrome/browser/views/frame/browser_view_layout.cc b/chrome/browser/views/frame/browser_view_layout.cc index 2b0f2e0..94d3911 100644 --- a/chrome/browser/views/frame/browser_view_layout.cc +++ b/chrome/browser/views/frame/browser_view_layout.cc @@ -285,7 +285,7 @@ int BrowserViewLayout::LayoutTabStrip() { gfx::Rect layout_bounds = browser_view_->frame()->GetBoundsForTabStrip(tabstrip_); - if (browser_view_->UsingSideTabs()) { + if (browser_view_->UseVerticalTabs()) { vertical_layout_rect_.Inset( layout_bounds.right() - kBrowserViewTabStripHorizontalOverlap, 0, 0, 0); } else { @@ -301,7 +301,7 @@ int BrowserViewLayout::LayoutTabStrip() { layout_bounds.set_origin(tabstrip_origin); tabstrip_->SetVisible(true); tabstrip_->SetBounds(layout_bounds); - return browser_view_->UsingSideTabs() ? 0 : layout_bounds.bottom(); + return browser_view_->UseVerticalTabs() ? 0 : layout_bounds.bottom(); } int BrowserViewLayout::LayoutToolbar(int top) { @@ -309,7 +309,7 @@ int BrowserViewLayout::LayoutToolbar(int top) { bool visible = browser_view_->IsToolbarVisible(); toolbar_->location_bar()->SetFocusable(visible); int y = 0; - if (!browser_view_->UsingSideTabs()) { + if (!browser_view_->UseVerticalTabs()) { y = top - ((visible && browser_view_->IsTabStripVisible()) ? kToolbarTabStripVerticalOverlap : 0); diff --git a/chrome/browser/views/frame/glass_browser_frame_view.cc b/chrome/browser/views/frame/glass_browser_frame_view.cc index 9a665f7..6648b91 100644 --- a/chrome/browser/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/views/frame/glass_browser_frame_view.cc @@ -77,7 +77,7 @@ GlassBrowserFrameView::~GlassBrowserFrameView() { gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip( BaseTabStrip* tabstrip) const { - if (browser_view_->UsingSideTabs()) { + if (browser_view_->UseVerticalTabs()) { gfx::Size ps = tabstrip->GetPreferredSize(); return gfx::Rect(0, NonClientTopBorderHeight(), ps.width(), browser_view_->height()); @@ -114,7 +114,8 @@ void GlassBrowserFrameView::UpdateThrobber(bool running) { } void GlassBrowserFrameView::PaintTabStripShadow(gfx::Canvas* canvas) { - if (!browser_view_->UILayoutIsRightToLeft()) + if (!browser_view_->UILayoutIsRightToLeft() || + !browser_view_->UseVerticalTabs()) return; ThemeProvider* tp = GetThemeProvider(); @@ -237,7 +238,7 @@ int GlassBrowserFrameView::NonClientTopBorderHeight() const { // We'd like to use FrameBorderThickness() here, but the maximized Aero glass // frame has a 0 frame border around most edges and a CXSIZEFRAME-thick border // at the top (see AeroGlassFrame::OnGetMinMaxInfo()). - const int kRestoredHeight = browser_view_->UsingSideTabs() ? + const int kRestoredHeight = browser_view_->UseVerticalTabs() ? -2 : kNonClientRestoredExtraThickness; return GetSystemMetrics(SM_CXSIZEFRAME) + (browser_view_->IsMaximized() ? -kTabstripTopShadowThickness : kRestoredHeight); @@ -256,7 +257,7 @@ void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { // Draw the toolbar background, setting src_y of the paint to the tab // strip height as the toolbar background begins at the top of the tabs. - int src_y = browser_view_->UsingSideTabs() + int src_y = browser_view_->UseVerticalTabs() ? TabRenderer::GetMinimumUnselectedSize().height() : browser_view_->GetTabStripHeight() - 1; canvas->TileImageInt(*theme_toolbar, 0, src_y, @@ -333,7 +334,7 @@ void GlassBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) { tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height(); gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height()); - if (browser_view_->UsingSideTabs()) { + if (browser_view_->UseVerticalTabs()) { client_area_bounds.Inset( GetBoundsForTabStrip(browser_view_->tabstrip()).width() - 4, 0, 0, 0); } diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/views/tabs/browser_tab_strip_controller.cc index 343ee09..da30f47 100644 --- a/chrome/browser/views/tabs/browser_tab_strip_controller.cc +++ b/chrome/browser/views/tabs/browser_tab_strip_controller.cc @@ -5,7 +5,68 @@ #include "chrome/browser/views/tabs/browser_tab_strip_controller.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 "views/controls/menu/menu_2.h" +#include "views/widget/widget.h" + +class BrowserTabStripController::TabContextMenuContents + : public menus::SimpleMenuModel::Delegate { + public: + TabContextMenuContents(int tab_index, BrowserTabStripController* controller) + : ALLOW_THIS_IN_INITIALIZER_LIST(model_(this)), + tab_index_(tab_index), + controller_(controller) { + Build(); + } + virtual ~TabContextMenuContents() { + menu_->CancelMenu(); + } + + void RunMenuAt(const gfx::Point& point) { + menu_->RunMenuAt(point, views::Menu2::ALIGN_TOPLEFT); + } + + // Overridden from menus::SimpleMenuModel::Delegate: + virtual bool IsCommandIdChecked(int command_id) const { + return controller_->IsCommandCheckedForTab( + static_cast<TabStripModel::ContextMenuCommand>(command_id), + tab_index_); + } + virtual bool IsCommandIdEnabled(int command_id) const { + return controller_->IsCommandEnabledForTab( + static_cast<TabStripModel::ContextMenuCommand>(command_id), + tab_index_); + } + virtual bool GetAcceleratorForCommandId( + int command_id, + menus::Accelerator* accelerator) { + return controller_->tabstrip_->GetWidget()->GetAccelerator(command_id, + accelerator); + } + virtual void ExecuteCommand(int command_id) { + controller_->ExecuteCommandForTab( + static_cast<TabStripModel::ContextMenuCommand>(command_id), + tab_index_); + } + + private: + void Build() { + menu_.reset(new views::Menu2(&model_)); + } + + TabMenuModel model_; + scoped_ptr<views::Menu2> menu_; + + // The index of the tab we are showing the context menu for. + int tab_index_; + + // A pointer back to our hosting controller, for command state information. + BrowserTabStripController* controller_; + + DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents); +}; + //////////////////////////////////////////////////////////////////////////////// // BrowserTabStripController, public: @@ -18,6 +79,40 @@ BrowserTabStripController::BrowserTabStripController(TabStripModel* model, } BrowserTabStripController::~BrowserTabStripController() { + model_->RemoveObserver(this); +} + +void BrowserTabStripController::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()); + } +} + +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; +} + +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; +} + +void BrowserTabStripController::ExecuteCommandForTab( + TabStripModel::ContextMenuCommand command_id, int tab_index) { + if (model_->ContainsIndex(tab_index)) + model_->ExecuteContextMenuCommand(tab_index, command_id); } //////////////////////////////////////////////////////////////////////////////// @@ -53,6 +148,13 @@ void BrowserTabStripController::CloseTab(int index) { model_->CloseTabContentsAt(index); } +void BrowserTabStripController::ShowContextMenu(int index, + const gfx::Point& p) { + if (!context_menu_contents_.get()) + context_menu_contents_.reset(new TabContextMenuContents(index, this)); + context_menu_contents_->RunMenuAt(p); +} + //////////////////////////////////////////////////////////////////////////////// // BrowserTabStripController, TabStripModelObserver implementation: diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.h b/chrome/browser/views/tabs/browser_tab_strip_controller.h index e127659..c50fcdb 100644 --- a/chrome/browser/views/tabs/browser_tab_strip_controller.h +++ b/chrome/browser/views/tabs/browser_tab_strip_controller.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_VIEWS_TABS_BROWSER_TAB_STRIP_CONTROLLER_H_ #define CHROME_BROWSER_VIEWS_TABS_BROWSER_TAB_STRIP_CONTROLLER_H_ +#include "base/scoped_ptr.h" + #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/views/tabs/side_tab_strip_model.h" @@ -18,6 +20,15 @@ class BrowserTabStripController : public SideTabStripModel, BrowserTabStripController(TabStripModel* model, SideTabStrip* tabstrip); virtual ~BrowserTabStripController(); + void InitFromModel(); + + bool IsCommandEnabledForTab(TabStripModel::ContextMenuCommand command_id, + int tab_index) const; + bool IsCommandCheckedForTab(TabStripModel::ContextMenuCommand command_id, + int tab_index) const; + void ExecuteCommandForTab(TabStripModel::ContextMenuCommand command_id, + int tab_index); + // SideTabStripModel implementation: virtual SkBitmap GetIcon(int index) const; virtual string16 GetTitle(int index) const; @@ -25,6 +36,7 @@ class BrowserTabStripController : public SideTabStripModel, 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); // TabStripModelObserver implementation: virtual void TabInsertedAt(TabContents* contents, int index, @@ -43,9 +55,14 @@ class BrowserTabStripController : public SideTabStripModel, virtual void TabBlockedStateChanged(TabContents* contents, int index); private: + class TabContextMenuContents; + TabStripModel* model_; SideTabStrip* tabstrip_; + // If non-NULL it means we're showing a menu for the tab. + scoped_ptr<TabContextMenuContents> context_menu_contents_; + DISALLOW_COPY_AND_ASSIGN(BrowserTabStripController); }; diff --git a/chrome/browser/views/tabs/side_tab.cc b/chrome/browser/views/tabs/side_tab.cc index 9c45dd2..dfa18e1 100644 --- a/chrome/browser/views/tabs/side_tab.cc +++ b/chrome/browser/views/tabs/side_tab.cc @@ -57,6 +57,8 @@ SideTab::SideTab(SideTabModel* model) hover_animation_.reset(new SlideAnimation(this)); hover_animation_->SetSlideDuration(kHoverDurationMs); + + SetContextMenuController(this); } SideTab::~SideTab() { @@ -111,6 +113,15 @@ void SideTab::ButtonPressed(views::Button* sender, const views::Event& event) { } //////////////////////////////////////////////////////////////////////////////// +// SideTab, views::ContextMenuController implementation: + +void SideTab::ShowContextMenu(views::View* source, + const gfx::Point& p, + bool is_mouse_gesture) { + model_->ShowContextMenu(this, p); +} + +//////////////////////////////////////////////////////////////////////////////// // SideTab, views::View overrides: void SideTab::Layout() { @@ -120,14 +131,19 @@ void SideTab::Layout() { gfx::Size ps = close_button_->GetPreferredSize(); int close_y = (height() - ps.height()) / 2; - close_button_->SetBounds(width() - ps.width() - close_y, close_y, ps.width(), - ps.height()); + close_button_->SetBounds( + std::max(0, width() - ps.width() - close_y), + close_y, + ps.width(), + ps.height()); int title_y = (height() - font_->height()) / 2; int title_x = icon_bounds_.right() + kIconTitleSpacing; - title_bounds_.SetRect(title_x, title_y, - close_button_->x() - kTitleCloseSpacing - title_x, - font_->height()); + title_bounds_.SetRect( + title_x, + title_y, + std::max(0, close_button_->x() - kTitleCloseSpacing - title_x), + font_->height()); } void SideTab::Paint(gfx::Canvas* canvas) { diff --git a/chrome/browser/views/tabs/side_tab.h b/chrome/browser/views/tabs/side_tab.h index b267d5a..7c0e9d6 100644 --- a/chrome/browser/views/tabs/side_tab.h +++ b/chrome/browser/views/tabs/side_tab.h @@ -26,9 +26,13 @@ class SideTabModel { // 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, + public views::ContextMenuController, public views::ButtonListener, public AnimationDelegate { public: @@ -48,6 +52,11 @@ class SideTab : public views::View, // views::ButtonListener implementation: virtual void ButtonPressed(views::Button* sender, const views::Event& event); + // views::ContextMenuController implementation: + virtual void ShowContextMenu(views::View* source, + const gfx::Point& p, + bool is_mouse_gesture); + // views::View Overrides: virtual void Layout(); virtual void Paint(gfx::Canvas* canvas); diff --git a/chrome/browser/views/tabs/side_tab_strip.cc b/chrome/browser/views/tabs/side_tab_strip.cc index 7ef38d6..0a0df4f 100644 --- a/chrome/browser/views/tabs/side_tab_strip.cc +++ b/chrome/browser/views/tabs/side_tab_strip.cc @@ -38,12 +38,6 @@ bool SideTabStrip::Available() { switches::kEnableVerticalTabs); } -// static -bool SideTabStrip::Visible(Profile* profile) { - return Available() && - profile->GetPrefs()->GetBoolean(prefs::kUseVerticalTabs); -} - void SideTabStrip::AddTabAt(int index) { SideTab* tab = new SideTab(this); AddChildView(tab); @@ -88,6 +82,10 @@ void SideTabStrip::CloseTab(SideTab* tab) { model_->CloseTab(GetIndexOfSideTab(tab)); } +void SideTabStrip::ShowContextMenu(SideTab* tab, const gfx::Point& p) { + model_->ShowContextMenu(GetIndexOfSideTab(tab), p); +} + //////////////////////////////////////////////////////////////////////////////// // SideTabStrip, BaseTabStrip implementation: diff --git a/chrome/browser/views/tabs/side_tab_strip.h b/chrome/browser/views/tabs/side_tab_strip.h index 71b704a..b1716ba 100644 --- a/chrome/browser/views/tabs/side_tab_strip.h +++ b/chrome/browser/views/tabs/side_tab_strip.h @@ -25,10 +25,6 @@ class SideTabStrip : public BaseTabStrip, // command line flag that allows the SideTabStrip to be optionally shown. static bool Available(); - // Whether or not the vertical tabstrip is shown. Only valid if Available() - // returns true. - static bool Visible(Profile* profile); - // Notifies the SideTabStrip that a tab was added in the model at |index|. void AddTabAt(int index); @@ -48,6 +44,7 @@ class SideTabStrip : public BaseTabStrip, 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(); diff --git a/chrome/browser/views/tabs/side_tab_strip_model.h b/chrome/browser/views/tabs/side_tab_strip_model.h index a456c36..835e5ba 100644 --- a/chrome/browser/views/tabs/side_tab_strip_model.h +++ b/chrome/browser/views/tabs/side_tab_strip_model.h @@ -7,12 +7,17 @@ #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; @@ -35,6 +40,10 @@ class SideTabStripModel { // 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 3f3da3f..caea302 100644 --- a/chrome/browser/views/tabs/tab.cc +++ b/chrome/browser/views/tabs/tab.cc @@ -51,9 +51,9 @@ class Tab::TabContextMenuContents : public menus::SimpleMenuModel::Delegate { // Overridden from menus::SimpleMenuModel::Delegate: virtual bool IsCommandIdChecked(int command_id) const { - if (!tab_ || command_id != TabStripModel::CommandTogglePinned) - return false; - return tab_->delegate()->IsTabPinned(tab_); + return tab_ && tab_->delegate()->IsCommandCheckedForTab( + static_cast<TabStripModel::ContextMenuCommand>(command_id), + tab_); } virtual bool IsCommandIdEnabled(int command_id) const { return tab_ && tab_->delegate()->IsCommandEnabledForTab( diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h index 79b08f2..2276239 100644 --- a/chrome/browser/views/tabs/tab.h +++ b/chrome/browser/views/tabs/tab.h @@ -46,6 +46,10 @@ class Tab : public TabRenderer, 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; diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index 56bf512..68fc477 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -253,8 +253,7 @@ TabStrip::TabStrip(TabStripModel* model) } TabStrip::~TabStrip() { - // TODO(beng): (1031854) Restore this line once XPFrame/VistaFrame are dead. - // model_->RemoveObserver(this); + model_->RemoveObserver(this); // TODO(beng): remove this if it doesn't work to fix the TabSelectedAt bug. drag_controller_.reset(NULL); @@ -329,6 +328,15 @@ 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: @@ -848,6 +856,18 @@ bool TabStrip::IsCommandEnabledForTab( return false; } +bool TabStrip::IsCommandCheckedForTab( + TabStripModel::ContextMenuCommand command_id, const Tab* tab) const { + // TODO(beng): move to TabStripModel, see note in IsTabPinned. + if (command_id == TabStripModel::CommandTogglePinned) + return IsTabPinned(tab); + + int index = GetModelIndexOfTab(tab); + if (model_->ContainsIndex(index)) + return model_->IsContextMenuCommandChecked(index, command_id); + return false; +} + void TabStrip::ExecuteCommandForTab( TabStripModel::ContextMenuCommand command_id, Tab* tab) { int model_index = GetModelIndexOfTab(tab); diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h index e1cbfda..dbb3d97 100644 --- a/chrome/browser/views/tabs/tab_strip.h +++ b/chrome/browser/views/tabs/tab_strip.h @@ -83,6 +83,11 @@ class TabStrip : public BaseTabStrip, // 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); @@ -149,6 +154,8 @@ class TabStrip : public BaseTabStrip, 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( diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h index c81ff1c..371513a 100644 --- a/chrome/test/test_browser_window.h +++ b/chrome/test/test_browser_window.h @@ -100,6 +100,7 @@ class TestBrowserWindow : public BrowserWindow { virtual void Cut() { } virtual void Copy() { } virtual void Paste() { } + virtual void ToggleTabStripMode() { } protected: virtual void DestroyBrowser() {} |