#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include <algorithm>
#include <string>
+#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.h"
#include "base/prefs/pref_service.h"
namespace extensions {
-bool ExtensionToolbarModel::Observer::BrowserActionShowPopup(
- const Extension* extension) {
- return false;
-}
-
ExtensionToolbarModel::ExtensionToolbarModel(Profile* profile,
ExtensionPrefs* extension_prefs)
: profile_(profile),
extension_prefs_(extension_prefs),
prefs_(profile_->GetPrefs()),
extensions_initialized_(false),
+ include_all_extensions_(
+ FeatureSwitch::extension_action_redesign()->IsEnabled()),
is_highlighting_(false),
+ extension_action_observer_(this),
extension_registry_observer_(this),
weak_ptr_factory_(this) {
ExtensionSystem::Get(profile_)->ready().Post(
observers_.RemoveObserver(observer);
}
-void ExtensionToolbarModel::MoveBrowserAction(const Extension* extension,
+void ExtensionToolbarModel::MoveExtensionIcon(const Extension* extension,
int index) {
ExtensionList::iterator pos = std::find(toolbar_items_.begin(),
toolbar_items_.end(), extension);
last_known_positions_.push_back(extension->id());
}
- FOR_EACH_OBSERVER(Observer, observers_, BrowserActionMoved(extension, index));
-
+ FOR_EACH_OBSERVER(
+ Observer, observers_, ToolbarExtensionMoved(extension, index));
+ MaybeUpdateVisibilityPref(extension, index);
UpdatePrefs();
}
-ExtensionAction::ShowAction ExtensionToolbarModel::ExecuteBrowserAction(
- const Extension* extension,
- Browser* browser,
- GURL* popup_url_out,
- bool should_grant) {
- content::WebContents* web_contents = NULL;
- int tab_id = 0;
- if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
- return ExtensionAction::ACTION_NONE;
-
- ExtensionAction* browser_action =
- ExtensionActionManager::Get(profile_)->GetBrowserAction(*extension);
-
- // For browser actions, visibility == enabledness.
- if (!browser_action->GetIsVisible(tab_id))
- return ExtensionAction::ACTION_NONE;
-
- if (should_grant) {
- TabHelper::FromWebContents(web_contents)
- ->active_tab_permission_granter()
- ->GrantIfRequested(extension);
- }
-
- if (browser_action->HasPopup(tab_id)) {
- if (popup_url_out)
- *popup_url_out = browser_action->GetPopupUrl(tab_id);
- return ExtensionAction::ACTION_SHOW_POPUP;
- }
-
- ExtensionActionAPI::BrowserActionExecuted(
- browser->profile(), *browser_action, web_contents);
- return ExtensionAction::ACTION_NONE;
-}
-
void ExtensionToolbarModel::SetVisibleIconCount(int count) {
visible_icon_count_ =
count == static_cast<int>(toolbar_items_.size()) ? -1 : count;
+
// Only set the prefs if we're not in highlight mode. Highlight mode is
// designed to be a transitory state, and should not persist across browser
// restarts (though it may be re-entered).
- if (!is_highlighting_)
+ if (!is_highlighting_) {
+ // Additionally, if we are using the new toolbar, any icons which are in the
+ // overflow menu are considered "hidden". But it so happens that the times
+ // we are likely to call SetVisibleIconCount() are also those when we are
+ // in flux. So wait for things to cool down before setting the prefs.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs,
+ weak_ptr_factory_.GetWeakPtr()));
prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_);
+ }
+}
+
+void ExtensionToolbarModel::OnExtensionActionUpdated(
+ ExtensionAction* extension_action,
+ content::WebContents* web_contents,
+ content::BrowserContext* browser_context) {
+ const Extension* extension =
+ ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
+ extension_action->extension_id());
+ // Notify observers if the extension exists and is in the model.
+ if (extension &&
+ std::find(toolbar_items_.begin(),
+ toolbar_items_.end(),
+ extension) != toolbar_items_.end()) {
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionUpdated(extension));
+ }
}
void ExtensionToolbarModel::OnExtensionLoaded(
if (toolbar_items_[i].get() == extension)
return;
}
- if (ExtensionActionAPI::GetBrowserActionVisibility(extension_prefs_,
- extension->id())) {
- AddExtension(extension);
- }
+
+ AddExtension(extension);
}
void ExtensionToolbarModel::OnExtensionUnloaded(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
- DCHECK_EQ(
- extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
- type);
+ DCHECK_EQ(NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, type);
const Extension* extension =
ExtensionRegistry::Get(profile_)->GetExtensionById(
*content::Details<const std::string>(details).ptr(),
ExtensionRegistry::EVERYTHING);
- if (ExtensionActionAPI::GetBrowserActionVisibility(extension_prefs_,
- extension->id()))
- AddExtension(extension);
- else
- RemoveExtension(extension);
+
+ bool visible = ExtensionActionAPI::GetBrowserActionVisibility(
+ extension_prefs_, extension->id());
+ // Hiding works differently with the new and old toolbars.
+ if (include_all_extensions_) {
+ int new_size = 0;
+ int new_index = 0;
+ if (visible) {
+ // If this action used to be hidden, we can't possible be showing all.
+ DCHECK_NE(-1, visible_icon_count_);
+ // Grow the bar by one and move the extension to the end of the visibles.
+ new_size = visible_icon_count_ + 1;
+ new_index = new_size - 1;
+ } else {
+ // If we're hiding one, we must be showing at least one.
+ DCHECK_NE(visible_icon_count_, 0);
+ // Shrink the bar by one and move the extension to the beginning of the
+ // overflow menu.
+ new_size = visible_icon_count_ == -1 ?
+ toolbar_items_.size() - 1 : visible_icon_count_ - 1;
+ new_index = new_size;
+ }
+ SetVisibleIconCount(new_size);
+ MoveExtensionIcon(extension, new_index);
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
+ } else { // Don't include all extensions.
+ if (visible)
+ AddExtension(extension);
+ else
+ RemoveExtension(extension);
+ }
}
void ExtensionToolbarModel::OnReady() {
// changes so that the toolbar buttons can be shown in their stable ordering
// taken from prefs.
extension_registry_observer_.Add(registry);
+ extension_action_observer_.Add(ExtensionActionAPI::Get(profile_));
registrar_.Add(
this,
extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
// See if we have last known good position for this extension.
size_t new_index = 0;
// Loop through the ID list of known positions, to count the number of visible
- // browser action icons preceding |extension|.
+ // extension icons preceding |extension|.
for (ExtensionIdList::const_iterator iter_id = last_known_positions_.begin();
iter_id < last_known_positions_.end(); ++iter_id) {
if ((*iter_id) == extension->id())
return toolbar_items_.size();
}
+bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) {
+ ExtensionActionManager* action_manager =
+ ExtensionActionManager::Get(profile_);
+ if (include_all_extensions_) {
+ // In this case, we don't care about the browser action visibility, because
+ // we want to show each extension regardless.
+ // TODO(devlin): Extension actions which are not visible should be moved to
+ // the overflow menu by default.
+ return action_manager->GetBrowserAction(*extension) ||
+ action_manager->GetPageAction(*extension);
+ }
+
+ return action_manager->GetBrowserAction(*extension) &&
+ ExtensionActionAPI::GetBrowserActionVisibility(
+ extension_prefs_, extension->id());
+}
+
void ExtensionToolbarModel::AddExtension(const Extension* extension) {
- // We only care about extensions with browser actions.
- if (!ExtensionActionManager::Get(profile_)->GetBrowserAction(*extension))
+ if (!ShouldAddExtension(extension))
return;
size_t new_index = toolbar_items_.size();
UpdatePrefs();
}
+ MaybeUpdateVisibilityPref(extension, new_index);
+
// If we're currently highlighting, then even though we add a browser action
// to the full list (|toolbar_items_|, there won't be another *visible*
// browser action, which was what the observers care about.
if (!is_highlighting_) {
- FOR_EACH_OBSERVER(Observer, observers_,
- BrowserActionAdded(extension, new_index));
+ FOR_EACH_OBSERVER(
+ Observer, observers_, ToolbarExtensionAdded(extension, new_index));
}
}
extension);
if (pos != highlighted_items_.end()) {
highlighted_items_.erase(pos);
- FOR_EACH_OBSERVER(Observer, observers_, BrowserActionRemoved(extension));
+ FOR_EACH_OBSERVER(
+ Observer, observers_, ToolbarExtensionRemoved(extension));
// If the highlighted list is now empty, we stop highlighting.
if (highlighted_items_.empty())
StopHighlighting();
}
} else {
- FOR_EACH_OBSERVER(Observer, observers_, BrowserActionRemoved(extension));
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionRemoved(extension));
}
UpdatePrefs();
Populate(last_known_positions_, extensions);
extensions_initialized_ = true;
- FOR_EACH_OBSERVER(Observer, observers_, VisibleCountChanged());
+ MaybeUpdateVisibilityPrefs();
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
void ExtensionToolbarModel::Populate(const ExtensionIdList& positions,
it != extensions.end();
++it) {
const Extension* extension = it->get();
- if (!extension_action_manager->GetBrowserAction(*extension))
- continue;
- if (!ExtensionActionAPI::GetBrowserActionVisibility(
- extension_prefs_, extension->id())) {
- ++hidden;
+ if (!ShouldAddExtension(extension)) {
+ if (extension_action_manager->GetBrowserAction(*extension))
+ ++hidden;
continue;
}
size_t items_count = toolbar_items_.size();
for (size_t i = 0; i < items_count; i++) {
- const Extension* extension = toolbar_items_.back();
+ const Extension* extension = toolbar_items_.back().get();
// By popping the extension here (before calling BrowserActionRemoved),
// we will not shrink visible count by one after BrowserActionRemoved
// calls SetVisibleCount.
toolbar_items_.pop_back();
FOR_EACH_OBSERVER(
- Observer, observers_, BrowserActionRemoved(extension));
+ Observer, observers_, ToolbarExtensionRemoved(extension));
}
DCHECK(toolbar_items_.empty());
if (iter->get() != NULL) {
toolbar_items_.push_back(*iter);
FOR_EACH_OBSERVER(
- Observer, observers_, BrowserActionAdded(
- *iter, toolbar_items_.size() - 1));
+ Observer,
+ observers_,
+ ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
}
}
for (ExtensionList::const_iterator iter = unsorted.begin();
if (iter->get() != NULL) {
toolbar_items_.push_back(*iter);
FOR_EACH_OBSERVER(
- Observer, observers_, BrowserActionAdded(
- *iter, toolbar_items_.size() - 1));
+ Observer,
+ observers_,
+ ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
}
}
pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
}
+void ExtensionToolbarModel::MaybeUpdateVisibilityPref(
+ const Extension* extension, int index) {
+ // We only update the visibility pref for hidden/not hidden based on the
+ // overflow menu with the new toolbar design.
+ if (include_all_extensions_) {
+ bool visible = index < visible_icon_count_ || visible_icon_count_ == -1;
+ if (visible != ExtensionActionAPI::GetBrowserActionVisibility(
+ extension_prefs_, extension->id())) {
+ // Don't observe changes caused by ourselves.
+ bool was_registered = false;
+ if (registrar_.IsRegistered(
+ this,
+ NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
+ content::Source<ExtensionPrefs>(extension_prefs_))) {
+ was_registered = true;
+ registrar_.Remove(
+ this,
+ NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
+ content::Source<ExtensionPrefs>(extension_prefs_));
+ }
+ ExtensionActionAPI::SetBrowserActionVisibility(
+ extension_prefs_, extension->id(), visible);
+ if (was_registered) {
+ registrar_.Add(this,
+ NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
+ content::Source<ExtensionPrefs>(extension_prefs_));
+ }
+ }
+ }
+}
+
+void ExtensionToolbarModel::MaybeUpdateVisibilityPrefs() {
+ for (size_t i = 0u; i < toolbar_items_.size(); ++i)
+ MaybeUpdateVisibilityPref(toolbar_items_[i].get(), i);
+}
+
int ExtensionToolbarModel::IncognitoIndexToOriginal(int incognito_index) {
int original_index = 0, i = 0;
for (ExtensionList::iterator iter = toolbar_items_.begin();
}
}
-bool ExtensionToolbarModel::ShowBrowserActionPopup(const Extension* extension) {
+bool ExtensionToolbarModel::ShowExtensionActionPopup(
+ const Extension* extension,
+ Browser* browser,
+ bool grant_active_tab) {
ObserverListBase<Observer>::Iterator it(observers_);
Observer* obs = NULL;
+ // Look for the Observer associated with the browser.
+ // This would be cleaner if we had an abstract class for the Toolbar UI
+ // (like we do for LocationBar), but sadly, we don't.
while ((obs = it.GetNext()) != NULL) {
- // Stop after first popup since it should only show in the active window.
- if (obs->BrowserActionShowPopup(extension))
- return true;
+ if (obs->GetBrowser() == browser)
+ return obs->ShowExtensionActionPopup(extension, grant_active_tab);
}
return false;
}
SetVisibleIconCount(extension_ids.size());
// Inform observers.
- FOR_EACH_OBSERVER(Observer, observers_, VisibleCountChanged());
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
if (visible_icon_count_ == -1)
extension != toolbar_items_.end(); ++extension) {
if ((*extension)->id() == (*it)) {
if (extension - toolbar_items_.begin() >= visible_icon_count_)
- MoveBrowserAction(*extension, 0);
+ MoveExtensionIcon(extension->get(), 0);
break;
}
}
if (visible_icon_count_ != -1 &&
visible_icon_count_ < static_cast<int>(extension_ids.size())) {
SetVisibleIconCount(extension_ids.size());
- FOR_EACH_OBSERVER(Observer, observers_, VisibleCountChanged());
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
- FOR_EACH_OBSERVER(Observer, observers_, HighlightModeChanged(true));
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarHighlightModeChanged(true));
return true;
}
is_highlighting_ = false;
if (old_visible_icon_count_ != visible_icon_count_) {
SetVisibleIconCount(old_visible_icon_count_);
- FOR_EACH_OBSERVER(Observer, observers_, VisibleCountChanged());
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
- FOR_EACH_OBSERVER(Observer, observers_, HighlightModeChanged(false));
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarHighlightModeChanged(false));
}
}
+void ExtensionToolbarModel::SetVisibleIconCountForTest(size_t visible_icons) {
+ SetVisibleIconCount(visible_icons);
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
+}
+
} // namespace extensions