| Index: chrome/browser/geolocation/geolocation_content_settings_table_model.cc
|
| ===================================================================
|
| --- chrome/browser/geolocation/geolocation_content_settings_table_model.cc (revision 43621)
|
| +++ chrome/browser/geolocation/geolocation_content_settings_table_model.cc (working copy)
|
| @@ -5,10 +5,47 @@
|
| #include "chrome/browser/geolocation/geolocation_content_settings_table_model.h"
|
|
|
| #include "app/l10n_util.h"
|
| +#include "app/l10n_util_collator.h"
|
| #include "app/table_model_observer.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "chrome/common/url_constants.h"
|
| #include "grit/generated_resources.h"
|
|
|
| +namespace {
|
| +// Return -1, 0, or 1 depending on whether |origin1| should be sorted before,
|
| +// equal to, or after |origin2|.
|
| +int CompareOrigins(const GURL& origin1, const GURL& origin2) {
|
| + if (origin1 == origin2)
|
| + return 0;
|
| +
|
| + // Sort alphabetically by host name.
|
| + std::string origin1_host(origin1.host());
|
| + std::string origin2_host(origin2.host());
|
| + if (origin1_host != origin2_host)
|
| + return origin1_host < origin2_host ? -1 : 1;
|
| +
|
| + // We'll show non-HTTP schemes, so sort them alphabetically, but put HTTP
|
| + // first.
|
| + std::string origin1_scheme(origin1.scheme());
|
| + std::string origin2_scheme(origin2.scheme());
|
| + if (origin1_scheme != origin2_scheme) {
|
| + if (origin1_scheme == chrome::kHttpScheme)
|
| + return -1;
|
| + if (origin2_scheme == chrome::kHttpScheme)
|
| + return 1;
|
| + return origin1_scheme < origin2_scheme ? -1 : 1;
|
| + }
|
| +
|
| + // Sort by port number. This has to differ if the origins are really origins
|
| + // (and not longer URLs). An unspecified port will be -1 and thus
|
| + // automatically come first (which is what we want).
|
| + int origin1_port = origin1.IntPort();
|
| + int origin2_port = origin2.IntPort();
|
| + DCHECK(origin1_port != origin2_port);
|
| + return origin1_port < origin2_port ? -1 : 1;
|
| +}
|
| +} // namespace
|
| +
|
| GeolocationContentSettingsTableModel::GeolocationContentSettingsTableModel(
|
| GeolocationContentSettingsMap* map)
|
| : map_(map),
|
| @@ -20,39 +57,55 @@
|
| AddEntriesForOrigin(i->first, i->second);
|
| }
|
|
|
| -bool GeolocationContentSettingsTableModel::CanRemoveException(int row) const {
|
| - const Entry& entry = entries_[row];
|
| - return !(entry.origin == entry.embedding_origin &&
|
| - static_cast<size_t>(row + 1) < entries_.size() &&
|
| - entries_[row + 1].origin == entry.origin &&
|
| - entry.setting == CONTENT_SETTING_DEFAULT);
|
| +bool GeolocationContentSettingsTableModel::CanRemoveExceptions(
|
| + const Rows& rows) const {
|
| + for (Rows::const_iterator i(rows.begin()); i != rows.end(); ++i) {
|
| + const Entry& entry = entries_[*i];
|
| + if ((entry.origin == entry.embedding_origin) &&
|
| + (entry.setting == CONTENT_SETTING_DEFAULT)) {
|
| + for (size_t j = (*i) + 1;
|
| + (j < entries_.size()) && (entries_[j].origin == entry.origin); ++j) {
|
| + if (!rows.count(j))
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| }
|
|
|
| -void GeolocationContentSettingsTableModel::RemoveException(int row) {
|
| - Entry& entry = entries_[row];
|
| - bool next_has_same_origin = static_cast<size_t>(row + 1) < entries_.size() &&
|
| - entries_[row + 1].origin == entry.origin;
|
| - bool has_children = entry.origin == entry.embedding_origin &&
|
| - next_has_same_origin;
|
| - map_->SetContentSetting(entry.origin, entry.embedding_origin,
|
| - CONTENT_SETTING_DEFAULT);
|
| - if (has_children) {
|
| - entry.setting = CONTENT_SETTING_DEFAULT;
|
| - if (observer_)
|
| - observer_->OnItemsChanged(row, 1);
|
| - } else if (!next_has_same_origin &&
|
| - row > 0 &&
|
| - entries_[row - 1].origin == entry.origin &&
|
| - entries_[row - 1].setting == CONTENT_SETTING_DEFAULT) {
|
| - // If we remove the last non-default child of a default parent, we should
|
| - // remove the parent too.
|
| - entries_.erase(entries_.begin() + row - 1, entries_.begin() + row + 1);
|
| - if (observer_)
|
| - observer_->OnItemsRemoved(row - 1, 2);
|
| - } else {
|
| - entries_.erase(entries_.begin() + row);
|
| - if (observer_)
|
| - observer_->OnItemsRemoved(row, 1);
|
| +void GeolocationContentSettingsTableModel::RemoveExceptions(const Rows& rows) {
|
| + for (Rows::const_reverse_iterator i(rows.rbegin()); i != rows.rend(); ++i) {
|
| + size_t row = *i;
|
| + Entry* entry = &entries_[row];
|
| + GURL entry_origin(entry->origin); // Copy, not reference, since we'll erase
|
| + // |entry| before we're done with this.
|
| + bool next_has_same_origin = ((row + 1) < entries_.size()) &&
|
| + (entries_[row + 1].origin == entry_origin);
|
| + bool has_children = (entry_origin == entry->embedding_origin) &&
|
| + next_has_same_origin;
|
| + map_->SetContentSetting(entry_origin, entry->embedding_origin,
|
| + CONTENT_SETTING_DEFAULT);
|
| + if (has_children) {
|
| + entry->setting = CONTENT_SETTING_DEFAULT;
|
| + if (observer_)
|
| + observer_->OnItemsChanged(row, 1);
|
| + continue;
|
| + }
|
| + do {
|
| + entries_.erase(entries_.begin() + row); // Note: |entry| is now garbage.
|
| + if (observer_)
|
| + observer_->OnItemsRemoved(row, 1);
|
| + // If we remove the last non-default child of a default parent, we
|
| + // should remove the parent too. We do these removals one-at-a-time
|
| + // because the table view will end up being called back as each row is
|
| + // removed, in turn calling back to CanRemoveExceptions(), and if we've
|
| + // already removed more entries than the view has, we'll have problems.
|
| + if ((row == 0) || rows.count(row - 1))
|
| + break;
|
| + entry = &entries_[--row];
|
| + } while (!next_has_same_origin && (entry->origin == entry_origin) &&
|
| + (entry->origin == entry->embedding_origin) &&
|
| + (entry->setting == CONTENT_SETTING_DEFAULT));
|
| }
|
| }
|
|
|
| @@ -72,17 +125,27 @@
|
| int column_id) {
|
| const Entry& entry = entries_[row];
|
| if (column_id == IDS_EXCEPTIONS_HOSTNAME_HEADER) {
|
| - if (entry.origin == entry.embedding_origin)
|
| - return UTF8ToWide(
|
| - GeolocationContentSettingsMap::OriginToString(entry.origin));
|
| - if (entry.embedding_origin.is_empty())
|
| - return ASCIIToWide(" ") +
|
| + if (entry.origin == entry.embedding_origin) {
|
| + return UTF8ToWide(GeolocationContentSettingsMap::OriginToString(
|
| + entry.origin));
|
| + }
|
| + std::wstring indent(L" ");
|
| + if (entry.embedding_origin.is_empty()) {
|
| + // NOTE: As long as the user cannot add/edit entries from the exceptions
|
| + // dialog, it's impossible to actually have a non-default setting for some
|
| + // origin "embedded on any other site", so this row will never appear. If
|
| + // we add the ability to add/edit exceptions, we'll need to decide when to
|
| + // display this and how "removing" it will function.
|
| + return indent +
|
| l10n_util::GetString(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ANY_OTHER);
|
| - return ASCIIToWide(" ") +
|
| - l10n_util::GetStringF(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST,
|
| - UTF8ToWide(GeolocationContentSettingsMap::OriginToString(
|
| - entry.embedding_origin)));
|
| - } else if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
|
| + }
|
| + return indent + l10n_util::GetStringF(
|
| + IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST,
|
| + UTF8ToWide(GeolocationContentSettingsMap::OriginToString(
|
| + entry.embedding_origin)));
|
| + }
|
| +
|
| + if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
|
| switch (entry.setting) {
|
| case CONTENT_SETTING_ALLOW:
|
| return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
|
| @@ -93,11 +156,11 @@
|
| case CONTENT_SETTING_DEFAULT:
|
| return l10n_util::GetString(IDS_EXCEPTIONS_NOT_SET_BUTTON);
|
| default:
|
| - NOTREACHED();
|
| + break;
|
| }
|
| - } else {
|
| - NOTREACHED();
|
| }
|
| +
|
| + NOTREACHED();
|
| return std::wstring();
|
| }
|
|
|
| @@ -106,6 +169,55 @@
|
| observer_ = observer;
|
| }
|
|
|
| +int GeolocationContentSettingsTableModel::CompareValues(int row1,
|
| + int row2,
|
| + int column_id) {
|
| + DCHECK(row1 >= 0 && row1 < RowCount() &&
|
| + row2 >= 0 && row2 < RowCount());
|
| +
|
| + const Entry& entry1 = entries_[row1];
|
| + const Entry& entry2 = entries_[row2];
|
| +
|
| + // Sort top-level requesting origins, keeping all embedded (child) rules
|
| + // together.
|
| + int origin_comparison = CompareOrigins(entry1.origin, entry2.origin);
|
| + if (origin_comparison == 0) {
|
| + // The non-embedded rule comes before all embedded rules.
|
| + bool entry1_origins_same = entry1.origin == entry1.embedding_origin;
|
| + bool entry2_origins_same = entry2.origin == entry2.embedding_origin;
|
| + if (entry1_origins_same != entry2_origins_same)
|
| + return entry1_origins_same ? -1 : 1;
|
| +
|
| + // The "default" embedded rule comes after all other embedded rules.
|
| + bool embedding_origin1_empty = entry1.embedding_origin.is_empty();
|
| + bool embedding_origin2_empty = entry2.embedding_origin.is_empty();
|
| + if (embedding_origin1_empty != embedding_origin2_empty)
|
| + return embedding_origin2_empty ? -1 : 1;
|
| +
|
| + origin_comparison =
|
| + CompareOrigins(entry1.embedding_origin, entry2.embedding_origin);
|
| + } else if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
|
| + // The rows are in different origins. We need to find out how the top-level
|
| + // origins will compare.
|
| + while (entries_[row1].origin != entries_[row1].embedding_origin)
|
| + --row1;
|
| + while (entries_[row2].origin != entries_[row2].embedding_origin)
|
| + --row2;
|
| + }
|
| +
|
| + // The entries are at the same "scope". If we're sorting by action, then do
|
| + // that now.
|
| + if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
|
| + int compare_text = l10n_util::CompareStringWithCollator(
|
| + GetCollator(), GetText(row1, column_id), GetText(row2, column_id));
|
| + if (compare_text != 0)
|
| + return compare_text;
|
| + }
|
| +
|
| + // Sort by the relevant origin.
|
| + return origin_comparison;
|
| +}
|
| +
|
| void GeolocationContentSettingsTableModel::AddEntriesForOrigin(
|
| const GURL& origin,
|
| const GeolocationContentSettingsMap::OneOriginSettings& settings) {
|
|
|