diff options
20 files changed, 199 insertions, 21 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index a59e90c..d87fbbe 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4668,6 +4668,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_TAB_CXMENU_UNPIN_TAB" desc="The label of the tab context menu item for unpinning a tab."> Unpin tab </message> + <message name="IDS_TAB_CXMENU_SHOW_TOOLBAR" desc="The label of the tab context menu item for showing the toolbar of an app tab."> + Show toolbar + </message> + <message name="IDS_TAB_CXMENU_HIDE_TOOLBAR" desc="The label of the tab context menu item for hiding the toolbar of an app tab."> + Hide toolbar + </message> <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> @@ -4703,6 +4709,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_TAB_CXMENU_UNPIN_TAB" desc="The label of the tab context menu item for unpinning a tab."> Unpin Tab </message> + <message name="IDS_TAB_CXMENU_SHOW_TOOLBAR" desc="The label of the tab context menu item for showing the toolbar of an app tab."> + Show Toolbar + </message> + <message name="IDS_TAB_CXMENU_HIDE_TOOLBAR" desc="The label of the tab context menu item for hiding the toolbar of an app tab."> + Hide Toolbar + </message> <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> diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 4a19f77..b3ad0d3 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -2318,6 +2318,10 @@ void Browser::ToggleUseVerticalTabs() { UseVerticalTabsChanged(); } +void Browser::SetToolbarVisibility(bool visible) { + window()->SetToolbarCollapsedMode(!visible); +} + /////////////////////////////////////////////////////////////////////////////// // Browser, TabStripModelObserver implementation: @@ -2402,10 +2406,7 @@ void Browser::TabSelectedAt(TabContents* old_contents, } } - // For TYPE_EXTENSION_APP we're always collapsed. For other windows, it - // depends on whether the tab is an app tab. - if (type_ != TYPE_EXTENSION_APP) - window()->SetToolbarCollapsedMode(new_contents->is_app()); + window()->SetToolbarCollapsedMode(!tabstrip_model_.IsToolbarVisible(index)); } void Browser::TabMoved(TabContents* contents, diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index bc9815e..d67cf4a 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -660,6 +660,7 @@ class Browser : public TabStripModelDelegate, virtual void ToggleUseVerticalTabs(); virtual bool CanRestoreTab(); virtual void RestoreTab(); + virtual void SetToolbarVisibility(bool visible); // Overridden from TabStripModelObserver: virtual void TabInsertedAt(TabContents* contents, diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm index 5440067..3450814 100644 --- a/chrome/browser/cocoa/tab_controller.mm +++ b/chrome/browser/cocoa/tab_controller.mm @@ -127,7 +127,7 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { contextMenuDelegate_.reset( new TabControllerInternal::MenuDelegate(target_, self)); contextMenuModel_.reset(new TabMenuModel(contextMenuDelegate_.get(), - [self pinned])); + [self pinned], false, true)); contextMenuController_.reset( [[MenuController alloc] initWithModel:contextMenuModel_.get() useWithPopUpButtonCell:NO]); diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm index 2a161ab..61b0837 100644 --- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm +++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm @@ -67,6 +67,8 @@ class TestTabStripDelegate : public TabStripModelDelegate { virtual bool UseVerticalTabs() const { return false; } virtual void ToggleUseVerticalTabs() {} + + virtual void SetToolbarVisibility(bool value) {} }; class TabStripControllerTest : public CocoaTest { diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index bfa5c7c..e73b2f6 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -35,6 +35,9 @@ const wchar_t kPrefVersion[] = L"manifest.version"; // Indicates if an extension is blacklisted: const wchar_t kPrefBlacklist[] = L"blacklist"; +// Indicates whether the toolbar should be shown on app tabs. +const wchar_t kPrefAppTabToolbars[] = L"app_tab_toolbars"; + // Indicates whether to show an install warning when the user enables. const wchar_t kExtensionDidEscalatePermissions[] = L"install_warning_on_enable"; @@ -589,8 +592,8 @@ static ExtensionInfo* GetInstalledExtensionInfoImpl( } int state_value; if (!ext->GetInteger(kPrefState, &state_value)) { - LOG(WARNING) << "Missing state pref for extension " << *extension_id; - NOTREACHED(); + // This can legitimately happen if we store preferences for component + // extensions. return NULL; } if (state_value == Extension::KILLBIT) { @@ -600,14 +603,10 @@ static ExtensionInfo* GetInstalledExtensionInfoImpl( } FilePath::StringType path; if (!ext->GetString(kPrefPath, &path)) { - LOG(WARNING) << "Missing path pref for extension " << *extension_id; - NOTREACHED(); return NULL; } int location_value; if (!ext->GetInteger(kPrefLocation, &location_value)) { - LOG(WARNING) << "Missing location pref for extension " << *extension_id; - NOTREACHED(); return NULL; } @@ -765,6 +764,32 @@ std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() { return result; } +bool ExtensionPrefs::AreAppTabToolbarsVisible( + const std::string& extension_id) { + // Default to hiding toolbars. + bool show_toolbars = false; + DictionaryValue* pref = GetExtensionPref(extension_id); + if (!pref) + return show_toolbars; + + pref->GetBoolean( + ASCIIToWide(extension_id) + L"." + kPrefAppTabToolbars, &show_toolbars); + return show_toolbars; +} + +void ExtensionPrefs::SetAppTabToolbarVisibility( + const std::string& extension_id, bool value) { + DictionaryValue* pref = GetOrCreateExtensionPref(extension_id); + std::wstring key = ASCIIToWide(extension_id) + L"." + kPrefAppTabToolbars; + + if (value) + pref->SetBoolean(key, true); + else + pref->Remove(key, NULL); // False is the default value. + + prefs_->ScheduleSavePersistentPrefs(); +} + // static void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) { diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index deba0ee..3f352e7ad 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -136,6 +136,12 @@ class ExtensionPrefs { // Returns the extension id's that have idle install information. std::set<std::string> GetIdleInstallInfoIds(); + // Returns whether app toolbars are visible for the specified extension. + bool AreAppTabToolbarsVisible(const std::string& extension_id); + + // Set whether app toolbars are visible for the specified extension. + void SetAppTabToolbarVisibility(const std::string& extension_id, bool value); + static void RegisterUserPrefs(PrefService* prefs); // The underlying PrefService. diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc index 15e0bc9..5f45ad5 100644 --- a/chrome/browser/extensions/extension_prefs_unittest.cc +++ b/chrome/browser/extensions/extension_prefs_unittest.cc @@ -310,3 +310,38 @@ class ExtensionPrefsIdleInstallInfo : public ExtensionPrefsTest { std::string id4_; }; TEST_F(ExtensionPrefsIdleInstallInfo, IdleInstallInfo) {} + +class ExtensionPrefsAppToolbars : public ExtensionPrefsTest { + public: + virtual void Initialize() { + // We test three different configurations -- the default value, and being + // overrridden set to on or off. + extension_id_default_ = + prefs_.AddExtensionAndReturnId("app_toolbars_default"); + + extension_id_overridden_on_ = + prefs_.AddExtensionAndReturnId("app_toolbars_overridden_on"); + prefs()->SetAppTabToolbarVisibility(extension_id_overridden_on_, true); + + extension_id_overridden_off_ = + prefs_.AddExtensionAndReturnId("app_toolbars_overridden_off"); + prefs()->SetAppTabToolbarVisibility(extension_id_overridden_off_, false); + } + + virtual void Verify() { + // Toolbars default to hidden. + EXPECT_FALSE(prefs()->AreAppTabToolbarsVisible(extension_id_default_)); + + EXPECT_TRUE(prefs()->AreAppTabToolbarsVisible( + extension_id_overridden_on_)); + EXPECT_FALSE(prefs()->AreAppTabToolbarsVisible( + extension_id_overridden_off_)); + } + + private: + // The ids of our three test extensions. + std::string extension_id_default_; + std::string extension_id_overridden_on_; + std::string extension_id_overridden_off_; +}; +TEST_F(ExtensionPrefsAppToolbars, ExtensionPrefsAppToolbars) {} diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc index bda8d62..b2f8c39 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_gtk.cc @@ -38,7 +38,7 @@ class TabGtk::ContextMenuController : public menus::SimpleMenuModel::Delegate { public: explicit ContextMenuController(TabGtk* tab) : tab_(tab), - model_(this, tab->delegate()->IsTabPinned(tab)) { + model_(this, tab->delegate()->IsTabPinned(tab), false, true) { menu_.reset(new MenuGtk(NULL, &model_)); } diff --git a/chrome/browser/tab_menu_model.cc b/chrome/browser/tab_menu_model.cc index 2a62dc3..0dabc38 100644 --- a/chrome/browser/tab_menu_model.cc +++ b/chrome/browser/tab_menu_model.cc @@ -10,9 +10,11 @@ #include "grit/generated_resources.h" TabMenuModel::TabMenuModel(menus::SimpleMenuModel::Delegate* delegate, - bool is_pinned) + bool allow_toolbar_toggle, + bool is_app_tab, + bool is_toolbar_visible) : menus::SimpleMenuModel(delegate) { - Build(is_pinned); + Build(allow_toolbar_toggle, is_app_tab, is_toolbar_visible); } // static @@ -27,7 +29,8 @@ bool TabMenuModel::AreVerticalTabsEnabled() { #endif } -void TabMenuModel::Build(bool is_pinned) { +void TabMenuModel::Build(bool is_pinned, bool allow_toolbar_toggle, + bool is_toolbar_visible) { AddItemWithStringId(TabStripModel::CommandNewTab, IDS_TAB_CXMENU_NEWTAB); AddSeparator(); AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD); @@ -36,6 +39,12 @@ void TabMenuModel::Build(bool is_pinned) { AddItemWithStringId( TabStripModel::CommandTogglePinned, is_pinned ? IDS_TAB_CXMENU_UNPIN_TAB : IDS_TAB_CXMENU_PIN_TAB); + if (allow_toolbar_toggle) { + AddItemWithStringId( + TabStripModel::CommandToggleToolbar, + is_toolbar_visible ? IDS_TAB_CXMENU_HIDE_TOOLBAR : + IDS_TAB_CXMENU_SHOW_TOOLBAR); + } AddSeparator(); AddItemWithStringId(TabStripModel::CommandCloseTab, IDS_TAB_CXMENU_CLOSETAB); diff --git a/chrome/browser/tab_menu_model.h b/chrome/browser/tab_menu_model.h index 189fefe..9712175 100644 --- a/chrome/browser/tab_menu_model.h +++ b/chrome/browser/tab_menu_model.h @@ -15,14 +15,16 @@ class Browser; // of the tab a new TabMenuModel should be created each time the menu is shown. class TabMenuModel : public menus::SimpleMenuModel { public: - TabMenuModel(menus::SimpleMenuModel::Delegate* delegate, bool is_pinned); + TabMenuModel(menus::SimpleMenuModel::Delegate* delegate, bool is_pinned, + bool allow_toolbar_toggle, bool is_toolbar_visible); virtual ~TabMenuModel() {} // Returns true if vertical tabs are enabled. static bool AreVerticalTabsEnabled(); private: - void Build(bool is_pinned); + void Build(bool is_pinned, bool allow_toolbar_toggle, + bool is_toolbar_visible); DISALLOW_COPY_AND_ASSIGN(TabMenuModel); }; diff --git a/chrome/browser/tab_menu_model_unittest.cc b/chrome/browser/tab_menu_model_unittest.cc index eaaa72e..4c07b96 100644 --- a/chrome/browser/tab_menu_model_unittest.cc +++ b/chrome/browser/tab_menu_model_unittest.cc @@ -13,7 +13,7 @@ class TabMenuModelTest : public PlatformTest, public MenuModelTest { }; TEST_F(TabMenuModelTest, Basics) { - TabMenuModel model(&delegate_, true); + TabMenuModel model(&delegate_, true, false, true); // Verify it has items. The number varies by platform, so we don't check // the exact number. diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index 306fb7f..7e0bcb7 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -56,11 +56,14 @@ TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile) order_controller_(NULL) { DCHECK(delegate_); registrar_.Add(this, - NotificationType::TAB_CONTENTS_DESTROYED, - NotificationService::AllSources()); + NotificationType::TAB_CONTENTS_DESTROYED, + NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, Source<Profile>(profile_)); + registrar_.Add(this, + NotificationType::EXTENSION_APP_TOOLBAR_VISIBILITY_CHANGED, + NotificationService::AllSources()); order_controller_ = new TabStripModelOrderController(this); } @@ -441,6 +444,16 @@ bool TabStripModel::IsAppTab(int index) const { return GetTabContentsAt(index)->is_app(); } +bool TabStripModel::IsToolbarVisible(int index) const { + Extension* extension_app = GetTabContentsAt(index)->extension_app(); + if (!extension_app) + return true; + + ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionPrefs* prefs = service->extension_prefs(); + return prefs->AreAppTabToolbarsVisible(extension_app->id()); +} + bool TabStripModel::IsPhantomTab(int index) const { return IsTabPinned(index) && GetTabContentsAt(index)->controller().needs_reload(); @@ -596,6 +609,8 @@ bool TabStripModel::IsContextMenuCommandEnabled( return delegate_->CanRestoreTab(); case CommandTogglePinned: return true; + case CommandToggleToolbar: + return true; case CommandBookmarkAllTabs: return delegate_->CanBookmarkAllTabs(); case CommandUseVerticalTabs: @@ -689,6 +704,32 @@ void TabStripModel::ExecuteContextMenuCommand( } break; } + case CommandToggleToolbar: { + UserMetrics::RecordAction( + UserMetricsAction("TabContextMenu_ToggleToolbar"), + profile_); + + SelectTabContentsAt(context_index, true); + + Extension* extension_app = + GetTabContentsAt(context_index)->extension_app(); + if (!extension_app) + break; + + ExtensionsService* service = profile()->GetExtensionsService(); + ExtensionPrefs* prefs = service->extension_prefs(); + bool new_val = !prefs->AreAppTabToolbarsVisible(extension_app->id()); + prefs->SetAppTabToolbarVisibility(extension_app->id(), new_val); + + // There might be multiple browsers displaying this app, so we send a + // notification to update them all. + NotificationService::current()->Notify( + NotificationType::EXTENSION_APP_TOOLBAR_VISIBILITY_CHANGED, + Source<Extension>(extension_app), + Details<bool>(&new_val)); + + break; + } case CommandBookmarkAllTabs: { UserMetrics::RecordAction( @@ -784,6 +825,17 @@ void TabStripModel::Observe(NotificationType type, break; } + case NotificationType::EXTENSION_APP_TOOLBAR_VISIBILITY_CHANGED: { + Extension* extension = Source<Extension>(source).ptr(); + bool* value = Details<bool>(details).ptr(); + TabContents* selected = GetSelectedTabContents(); + + if (selected && selected->extension_app() == extension) + delegate_->SetToolbarVisibility(*value); + + break; + } + default: NOTREACHED(); } diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h index 5ef9cdb..38954f4 100644 --- a/chrome/browser/tabs/tab_strip_model.h +++ b/chrome/browser/tabs/tab_strip_model.h @@ -229,6 +229,9 @@ class TabStripModelDelegate { // Toggles the use of the vertical tabstrip. virtual void ToggleUseVerticalTabs() = 0; + + // Set the visiblity of the toolbar. + virtual void SetToolbarVisibility(bool value) = 0; }; //////////////////////////////////////////////////////////////////////////////// @@ -517,6 +520,9 @@ class TabStripModel : public NotificationObserver { // See description above class for details on app tabs. bool IsAppTab(int index) const; + // Returns true if the toolbar is visible for the tab at |index|. + bool IsToolbarVisible(int index) const; + // Returns true if the tab is a phantom tab. A phantom tab is one where the // renderer has not been loaded. // See description above class for details on phantom tabs. @@ -584,6 +590,7 @@ class TabStripModel : public NotificationObserver { CommandCloseTabsOpenedBy, CommandRestoreTab, CommandTogglePinned, + CommandToggleToolbar, CommandBookmarkAllTabs, CommandUseVerticalTabs, CommandLast diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc index 1a5d747..51f9543 100644 --- a/chrome/browser/tabs/tab_strip_model_unittest.cc +++ b/chrome/browser/tabs/tab_strip_model_unittest.cc @@ -73,6 +73,7 @@ class TabStripDummyDelegate : public TabStripModelDelegate { virtual void BookmarkAllTabs() {} virtual bool UseVerticalTabs() const { return false; } virtual void ToggleUseVerticalTabs() {} + virtual void SetToolbarVisibility(bool val) {} private: // A dummy TabContents we give to callers that expect us to actually build a diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 67f0eb0..2aec7e8 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -1267,6 +1267,7 @@ void BrowserView::ToggleTabStripMode() { void BrowserView::SetToolbarCollapsedMode(bool val) { toolbar_->SetCollapsed(val); + Layout(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/views/tabs/browser_tab_strip_controller.cc index 6189033..6b00128 100644 --- a/chrome/browser/views/tabs/browser_tab_strip_controller.cc +++ b/chrome/browser/views/tabs/browser_tab_strip_controller.cc @@ -35,7 +35,8 @@ class BrowserTabStripController::TabContextMenuContents TabContextMenuContents(BaseTab* tab, BrowserTabStripController* controller) : ALLOW_THIS_IN_INITIALIZER_LIST( - model_(this, controller->IsTabPinned(tab))), + model_(this, controller->IsTabPinned(tab), controller->IsAppTab(tab), + controller->IsToolbarVisible(tab))), tab_(tab), controller_(controller), last_command_(TabStripModel::CommandFirst) { @@ -165,6 +166,22 @@ bool BrowserTabStripController::IsTabPinned(BaseTab* tab) { return IsTabPinned(tabstrip_->GetModelIndexOfBaseTab(tab)); } +bool BrowserTabStripController::IsAppTab(BaseTab* tab) { + int index = tabstrip_->GetModelIndexOfBaseTab(tab); + if (!model_->ContainsIndex(index)) + return false; + + return model_->IsAppTab(index); +} + +bool BrowserTabStripController::IsToolbarVisible(BaseTab* tab) { + int index = tabstrip_->GetModelIndexOfBaseTab(tab); + if (!model_->ContainsIndex(index)) + return false; + + return model_->IsToolbarVisible(index); +} + int BrowserTabStripController::GetCount() const { return model_->count(); } diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.h b/chrome/browser/views/tabs/browser_tab_strip_controller.h index 1e3661c..2779743 100644 --- a/chrome/browser/views/tabs/browser_tab_strip_controller.h +++ b/chrome/browser/views/tabs/browser_tab_strip_controller.h @@ -33,6 +33,8 @@ class BrowserTabStripController : public TabStripController, void ExecuteCommandForTab(TabStripModel::ContextMenuCommand command_id, BaseTab* tab); bool IsTabPinned(BaseTab* tab); + bool IsAppTab(BaseTab* tab); + bool IsToolbarVisible(BaseTab* tab); // TabStripController implementation: virtual int GetCount() const; diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index 49d6288..67eee26 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -543,6 +543,7 @@ class Extension { FRIEND_TEST(ExtensionTest, LoadPageActionHelper); FRIEND_TEST(TabStripModelTest, Apps); + FRIEND_TEST(TabStripModelTest, ToolbarVisibility); DISALLOW_COPY_AND_ASSIGN(Extension); }; diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index dd16e38..5d15273 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -855,6 +855,10 @@ class NotificationType { // std::pair<int suggest_id, ListValue suggestions_array> EXTENSION_OMNIBOX_SUGGESTIONS_READY, + // The source is the extension object that changed. Details is a bool* + // with the new visibility. + EXTENSION_APP_TOOLBAR_VISIBILITY_CHANGED, + // Privacy Blacklist ------------------------------------------------------- // Sent on the IO thread when a non-visual resource (like a cookie) |