#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
base::Bind(&ExtensionToolbarModel::OnReady,
weak_ptr_factory_.GetWeakPtr()));
visible_icon_count_ = prefs_->GetInteger(pref_names::kToolbarSize);
- pref_change_registrar_.Init(prefs_);
- pref_change_callback_ =
- base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange,
- base::Unretained(this));
- pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
+
+ // We only care about watching the prefs if not in incognito mode.
+ if (!profile_->IsOffTheRecord()) {
+ pref_change_registrar_.Init(prefs_);
+ pref_change_callback_ =
+ base::Bind(&ExtensionToolbarModel::OnExtensionToolbarPrefChange,
+ base::Unretained(this));
+ pref_change_registrar_.Add(pref_names::kToolbar, pref_change_callback_);
+ }
}
ExtensionToolbarModel::~ExtensionToolbarModel() {
observers_.RemoveObserver(observer);
}
-void ExtensionToolbarModel::MoveExtensionIcon(const Extension* extension,
- int index) {
- ExtensionList::iterator pos = std::find(toolbar_items_.begin(),
- toolbar_items_.end(), extension);
+void ExtensionToolbarModel::MoveExtensionIcon(const std::string& id,
+ size_t index) {
+ ExtensionList::iterator pos = toolbar_items_.begin();
+ while (pos != toolbar_items_.end() && (*pos)->id() != id)
+ ++pos;
if (pos == toolbar_items_.end()) {
NOTREACHED();
return;
}
+ scoped_refptr<const Extension> extension = *pos;
toolbar_items_.erase(pos);
- ExtensionIdList::iterator pos_id;
- pos_id = std::find(last_known_positions_.begin(),
- last_known_positions_.end(), extension->id());
+ ExtensionIdList::iterator pos_id = std::find(last_known_positions_.begin(),
+ last_known_positions_.end(),
+ id);
if (pos_id != last_known_positions_.end())
last_known_positions_.erase(pos_id);
- int i = 0;
- bool inserted = false;
- for (ExtensionList::iterator iter = toolbar_items_.begin();
- iter != toolbar_items_.end();
- ++iter, ++i) {
- if (i == index) {
- pos_id = std::find(last_known_positions_.begin(),
- last_known_positions_.end(), (*iter)->id());
- last_known_positions_.insert(pos_id, extension->id());
-
- toolbar_items_.insert(iter, make_scoped_refptr(extension));
- inserted = true;
- break;
- }
- }
-
- if (!inserted) {
- DCHECK_EQ(index, static_cast<int>(toolbar_items_.size()));
+ if (index < toolbar_items_.size()) {
+ // If the index is not at the end, find the item currently at |index|, and
+ // insert |extension| before it in both |toolbar_items_| and
+ // |last_known_positions_|.
+ ExtensionList::iterator iter = toolbar_items_.begin() + index;
+ last_known_positions_.insert(std::find(last_known_positions_.begin(),
+ last_known_positions_.end(),
+ (*iter)->id()),
+ id);
+ toolbar_items_.insert(iter, extension);
+ } else {
+ // Otherwise, put |extension| at the end.
+ DCHECK_EQ(toolbar_items_.size(), index);
index = toolbar_items_.size();
-
- toolbar_items_.push_back(make_scoped_refptr(extension));
- last_known_positions_.push_back(extension->id());
+ toolbar_items_.push_back(extension);
+ last_known_positions_.push_back(id);
}
FOR_EACH_OBSERVER(
- Observer, observers_, ToolbarExtensionMoved(extension, index));
- MaybeUpdateVisibilityPref(extension, index);
+ Observer, observers_, ToolbarExtensionMoved(extension.get(), index));
+ MaybeUpdateVisibilityPref(extension.get(), index);
UpdatePrefs();
}
-void ExtensionToolbarModel::SetVisibleIconCount(int count) {
- visible_icon_count_ =
- count == static_cast<int>(toolbar_items_.size()) ? -1 : count;
+void ExtensionToolbarModel::SetVisibleIconCount(size_t count) {
+ visible_icon_count_ = (count == 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_) {
+ // Only set the prefs if we're not in highlight mode and the profile is not
+ // incognito. Highlight mode is designed to be a transitory state, and should
+ // not persist across browser restarts (though it may be re-entered), and we
+ // don't store anything in incognito.
+ if (!is_highlighting_ && !profile_->IsOffTheRecord()) {
// 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
weak_ptr_factory_.GetWeakPtr()));
prefs_->SetInteger(pref_names::kToolbarSize, visible_icon_count_);
}
+
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
void ExtensionToolbarModel::OnExtensionActionUpdated(
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));
+ ExtensionList::const_iterator iter =
+ std::find(toolbar_items_.begin(), toolbar_items_.end(), extension);
+ if (iter != toolbar_items_.end()) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_, ToolbarExtensionUpdated(extension));
+ // If the action was in the overflow menu, we have to alert observers that
+ // the toolbar needs to be reordered (to show the action).
+ if (static_cast<size_t>(iter - toolbar_items_.begin()) >=
+ visible_icon_count()) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_, OnToolbarReorderNecessary(web_contents));
+ }
}
}
extension_prefs_, extension->id());
// Hiding works differently with the new and old toolbars.
if (include_all_extensions_) {
+ // It's possible that we haven't added this extension yet, if its
+ // visibility was adjusted in the course of its initialization.
+ if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) ==
+ toolbar_items_.end())
+ return;
+
int new_size = 0;
int new_index = 0;
if (visible) {
- // If this action used to be hidden, we can't possible be showing all.
+ // If this action used to be hidden, we can't possibly 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;
}
SetVisibleIconCount(new_size);
- MoveExtensionIcon(extension, new_index);
- FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
+ MoveExtensionIcon(extension->id(), new_index);
} else { // Don't include all extensions.
if (visible)
AddExtension(extension);
void ExtensionToolbarModel::OnReady() {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
- InitializeExtensionList(registry->enabled_extensions());
+ InitializeExtensionList();
// Wait until the extension system is ready before observing any further
// changes so that the toolbar buttons can be shown in their stable ordering
// taken from prefs.
// Found an id, need to see if it is visible.
for (ExtensionList::const_iterator iter_ext = toolbar_items_.begin();
iter_ext < toolbar_items_.end(); ++iter_ext) {
- if ((*iter_ext)->id().compare(*iter_id) == 0) {
+ if ((*iter_ext)->id() == (*iter_id)) {
// This extension is visible, update the index value.
++new_index;
break;
}
bool ExtensionToolbarModel::ShouldAddExtension(const Extension* extension) {
+ // In incognito mode, don't add any extensions that aren't incognito-enabled.
+ if (profile_->IsOffTheRecord() &&
+ !util::IsIncognitoEnabled(extension->id(), profile_))
+ return false;
+
ExtensionActionManager* action_manager =
ExtensionActionManager::Get(profile_);
if (include_all_extensions_) {
// 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->GetExtensionAction(*extension) != NULL;
}
return action_manager->GetBrowserAction(*extension) &&
if (!ShouldAddExtension(extension))
return;
- size_t new_index = toolbar_items_.size();
-
// See if we have a last known good position for this extension.
- ExtensionIdList::iterator last_pos = std::find(last_known_positions_.begin(),
- last_known_positions_.end(),
- extension->id());
- if (last_pos != last_known_positions_.end()) {
- new_index = FindNewPositionFromLastKnownGood(extension);
- if (new_index != toolbar_items_.size()) {
- toolbar_items_.insert(toolbar_items_.begin() + new_index,
- make_scoped_refptr(extension));
- } else {
- toolbar_items_.push_back(make_scoped_refptr(extension));
- }
- } else {
- // This is a never before seen extension, that was added to the end. Make
- // sure to reflect that. (|new_index| was set above.)
- toolbar_items_.push_back(make_scoped_refptr(extension));
+ bool is_new_extension =
+ std::find(last_known_positions_.begin(),
+ last_known_positions_.end(),
+ extension->id()) == last_known_positions_.end();
+ size_t new_index = is_new_extension ? toolbar_items_.size() :
+ FindNewPositionFromLastKnownGood(extension);
+ toolbar_items_.insert(toolbar_items_.begin() + new_index,
+ make_scoped_refptr(extension));
+ if (is_new_extension) {
last_known_positions_.push_back(extension->id());
UpdatePrefs();
}
if (!is_highlighting_) {
FOR_EACH_OBSERVER(
Observer, observers_, ToolbarExtensionAdded(extension, new_index));
+
+ // If this is an incognito profile, we also have to check to make sure the
+ // overflow matches the main bar's status.
+ if (profile_->IsOffTheRecord()) {
+ ExtensionToolbarModel* main_model =
+ ExtensionToolbarModel::Get(profile_->GetOriginalProfile());
+ // Find what the index will be in the main bar. Because Observer calls are
+ // nondeterministic, we can't just assume the main bar will have the
+ // extension and look it up.
+ int main_index = is_new_extension ?
+ main_model->toolbar_items_.size() :
+ main_model->FindNewPositionFromLastKnownGood(extension);
+ bool visible = main_index < main_model->visible_icon_count_ ||
+ main_model->visible_icon_count_ == -1;
+ // We may need to adjust the visible count if the incognito bar isn't
+ // showing all icons and this one is visible, or if it is showing all
+ // icons and this is hidden.
+ if (visible && visible_icon_count_ != -1)
+ SetVisibleIconCount(visible_icon_count_ + 1);
+ else if (!visible && visible_icon_count_ == -1)
+ SetVisibleIconCount(toolbar_items_.size() - 1);
+ }
}
}
if (pos == toolbar_items_.end())
return;
+ // If our visible count is set to the current size, we need to decrement it.
+ if (visible_icon_count_ == static_cast<int>(toolbar_items_.size()))
+ SetVisibleIconCount(toolbar_items_.size() - 1);
+
toolbar_items_.erase(pos);
// If we're in highlight mode, we also have to remove the extension from
UpdatePrefs();
}
+void ExtensionToolbarModel::ClearItems() {
+ size_t items_count = toolbar_items_.size();
+ for (size_t i = 0; i < items_count; ++i) {
+ const Extension* extension = toolbar_items_.back().get();
+ toolbar_items_.pop_back();
+ FOR_EACH_OBSERVER(Observer, observers_, ToolbarExtensionRemoved(extension));
+ }
+ DCHECK(toolbar_items_.empty());
+}
+
// Combine the currently enabled extensions that have browser actions (which
// we get from the ExtensionRegistry) with the ordering we get from the
// pref service. For robustness we use a somewhat inefficient process:
// have holes.
// 2. Create a vector of extensions that did not have a pref value.
// 3. Remove holes from the sorted vector and append the unsorted vector.
-void ExtensionToolbarModel::InitializeExtensionList(
- const ExtensionSet& extensions) {
+void ExtensionToolbarModel::InitializeExtensionList() {
last_known_positions_ = extension_prefs_->GetToolbarOrder();
- Populate(last_known_positions_, extensions);
+ if (profile_->IsOffTheRecord())
+ IncognitoPopulate();
+ else
+ Populate(last_known_positions_);
extensions_initialized_ = true;
MaybeUpdateVisibilityPrefs();
FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
}
-void ExtensionToolbarModel::Populate(const ExtensionIdList& positions,
- const ExtensionSet& extensions) {
+void ExtensionToolbarModel::Populate(const ExtensionIdList& positions) {
+ DCHECK(!profile_->IsOffTheRecord());
+ const ExtensionSet& extensions =
+ ExtensionRegistry::Get(profile_)->enabled_extensions();
// Items that have explicit positions.
- ExtensionList sorted;
- sorted.resize(positions.size(), NULL);
+ ExtensionList sorted(positions.size(), NULL);
// The items that don't have explicit positions.
ExtensionList unsorted;
- ExtensionActionManager* extension_action_manager =
- ExtensionActionManager::Get(profile_);
-
// Create the lists.
int hidden = 0;
- for (ExtensionSet::const_iterator it = extensions.begin();
- it != extensions.end();
- ++it) {
- const Extension* extension = it->get();
- if (!ShouldAddExtension(extension)) {
- if (extension_action_manager->GetBrowserAction(*extension))
+ for (const scoped_refptr<const Extension>& extension : extensions) {
+ if (!ShouldAddExtension(extension.get())) {
+ if (!ExtensionActionAPI::GetBrowserActionVisibility(extension_prefs_,
+ extension->id()))
++hidden;
continue;
}
if (pos != positions.end())
sorted[pos - positions.begin()] = extension;
else
- unsorted.push_back(make_scoped_refptr(extension));
+ unsorted.push_back(extension);
}
- size_t items_count = toolbar_items_.size();
- for (size_t i = 0; i < items_count; i++) {
- 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_, ToolbarExtensionRemoved(extension));
- }
- DCHECK(toolbar_items_.empty());
+ // Clear the current items, if any.
+ ClearItems();
// Merge the lists.
toolbar_items_.reserve(sorted.size() + unsorted.size());
- for (ExtensionList::const_iterator iter = sorted.begin();
- iter != sorted.end(); ++iter) {
+ for (const scoped_refptr<const Extension>& extension : sorted) {
// It's possible for the extension order to contain items that aren't
// actually loaded on this machine. For example, when extension sync is on,
// we sync the extension order as-is but double-check with the user before
// syncing NPAPI-containing extensions, so if one of those is not actually
// synced, we'll get a NULL in the list. This sort of case can also happen
// if some error prevents an extension from loading.
- if (iter->get() != NULL) {
- toolbar_items_.push_back(*iter);
+ if (extension.get() != NULL) {
+ toolbar_items_.push_back(extension);
FOR_EACH_OBSERVER(
Observer,
observers_,
- ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
+ ToolbarExtensionAdded(extension.get(), toolbar_items_.size() - 1));
}
}
- for (ExtensionList::const_iterator iter = unsorted.begin();
- iter != unsorted.end(); ++iter) {
- if (iter->get() != NULL) {
- toolbar_items_.push_back(*iter);
+ for (const scoped_refptr<const Extension>& extension : unsorted) {
+ if (extension.get() != NULL) {
+ toolbar_items_.push_back(extension);
FOR_EACH_OBSERVER(
Observer,
observers_,
- ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
+ ToolbarExtensionAdded(extension.get(), toolbar_items_.size() - 1));
}
}
}
}
+void ExtensionToolbarModel::IncognitoPopulate() {
+ DCHECK(profile_->IsOffTheRecord());
+ // Clear the current items, if any.
+ ClearItems();
+
+ const ExtensionToolbarModel* original_model =
+ ExtensionToolbarModel::Get(profile_->GetOriginalProfile());
+
+ // Find the absolute value of the original model's count.
+ int original_visible = original_model->visible_icon_count();
+
+ // In incognito mode, we show only those extensions that are
+ // incognito-enabled. Further, any actions that were overflowed in regular
+ // mode are still overflowed. Order is the same as in regular mode.
+ visible_icon_count_ = 0;
+ for (ExtensionList::const_iterator iter =
+ original_model->toolbar_items_.begin();
+ iter != original_model->toolbar_items_.end(); ++iter) {
+ if (ShouldAddExtension(iter->get())) {
+ toolbar_items_.push_back(*iter);
+ if (iter - original_model->toolbar_items_.begin() < original_visible)
+ ++visible_icon_count_;
+ FOR_EACH_OBSERVER(
+ Observer,
+ observers_,
+ ToolbarExtensionAdded(iter->get(), toolbar_items_.size() - 1));
+ }
+ }
+}
+
void ExtensionToolbarModel::UpdatePrefs() {
- if (!extension_prefs_)
+ if (!extension_prefs_ || profile_->IsOffTheRecord())
return;
// Don't observe change caused by self.
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_) {
+ if (include_all_extensions_ && !profile_->IsOffTheRecord()) {
bool visible = index < visible_icon_count_ || visible_icon_count_ == -1;
if (visible != ExtensionActionAPI::GetBrowserActionVisibility(
extension_prefs_, extension->id())) {
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();
- iter != toolbar_items_.end();
- ++iter, ++original_index) {
- if (util::IsIncognitoEnabled((*iter)->id(), profile_)) {
- if (incognito_index == i)
- break;
- ++i;
- }
- }
- return original_index;
-}
-
-int ExtensionToolbarModel::OriginalIndexToIncognito(int original_index) {
- int incognito_index = 0, i = 0;
- for (ExtensionList::iterator iter = toolbar_items_.begin();
- iter != toolbar_items_.end();
- ++iter, ++i) {
- if (original_index == i)
- break;
- if (util::IsIncognitoEnabled((*iter)->id(), profile_))
- ++incognito_index;
- }
- return incognito_index;
-}
-
void ExtensionToolbarModel::OnExtensionToolbarPrefChange() {
// If extensions are not ready, defer to later Populate() call.
if (!extensions_initialized_)
last_known_positions_.swap(pref_positions);
// Re-populate.
- Populate(last_known_positions_,
- ExtensionRegistry::Get(profile_)->enabled_extensions());
+ Populate(last_known_positions_);
if (last_known_positions_.size() > pref_position_size) {
// Need to update pref because we have extra icons. But can't call
}
}
+size_t ExtensionToolbarModel::GetVisibleIconCountForTab(
+ content::WebContents* web_contents) const {
+ if (all_icons_visible())
+ return visible_icon_count(); // Already displaying all actions.
+
+ ExtensionActionAPI* extension_action_api = ExtensionActionAPI::Get(profile_);
+ size_t total_icons = visible_icon_count_;
+ for (size_t i = total_icons; i < toolbar_items_.size(); ++i) {
+ if (extension_action_api->ExtensionWantsToRun(toolbar_items_[i].get(),
+ web_contents))
+ ++total_icons;
+ }
+ return total_icons;
+}
+
+ExtensionList ExtensionToolbarModel::GetItemOrderForTab(
+ content::WebContents* web_contents) const {
+ // If we're highlighting, the items are always the same.
+ if (is_highlighting_)
+ return highlighted_items_;
+
+ // Start by initializing the array to be the same as toolbar items (this isn't
+ // any more expensive than initializing it to be of the same size with all
+ // nulls, and saves us time at the end).
+ ExtensionList result = toolbar_items_;
+ if (toolbar_items_.empty())
+ return result;
+
+ ExtensionList overflowed_actions_wanting_to_run;
+ ExtensionActionAPI* extension_action_api = ExtensionActionAPI::Get(profile_);
+ size_t boundary = visible_icon_count();
+ // Rotate any actions that want to run to the boundary between visible and
+ // overflowed actions.
+ for (ExtensionList::iterator iter = result.begin() + boundary;
+ iter != result.end(); ++iter) {
+ if (extension_action_api->ExtensionWantsToRun(iter->get(), web_contents)) {
+ std::rotate(result.begin() + boundary, iter, iter + 1);
+ ++boundary;
+ }
+ }
+ return result;
+}
+
bool ExtensionToolbarModel::ShowExtensionActionPopup(
const Extension* extension,
Browser* browser,
// Otherwise, make sure we have enough room to show all the extensions
// requested.
- if (visible_icon_count_ < static_cast<int>(extension_ids.size())) {
+ if (visible_icon_count_ < static_cast<int>(extension_ids.size()))
SetVisibleIconCount(extension_ids.size());
- // Inform observers.
- FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
- }
-
if (visible_icon_count_ == -1)
return; // May have been set to max by SetVisibleIconCount.
extension != toolbar_items_.end(); ++extension) {
if ((*extension)->id() == (*it)) {
if (extension - toolbar_items_.begin() >= visible_icon_count_)
- MoveExtensionIcon(extension->get(), 0);
+ MoveExtensionIcon((*extension)->id(), 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_, ToolbarVisibleCountChanged());
}
FOR_EACH_OBSERVER(Observer, observers_, ToolbarHighlightModeChanged(true));
if (is_highlighting_) {
highlighted_items_.clear();
is_highlighting_ = false;
- if (old_visible_icon_count_ != visible_icon_count_) {
+ if (old_visible_icon_count_ != visible_icon_count_)
SetVisibleIconCount(old_visible_icon_count_);
- FOR_EACH_OBSERVER(Observer, observers_, ToolbarVisibleCountChanged());
- }
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