summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-05 22:50:13 +0000
committerpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-05 22:50:13 +0000
commit21d683b2efbe56e98d1b77aaa96d831240b7e1c4 (patch)
treecb5091b789e9eb11ad4a70f61b1da30872d7c517
parente6af8f1c212e3ca8b178853ea21fab1758a6c1a7 (diff)
downloadchromium_src-21d683b2efbe56e98d1b77aaa96d831240b7e1c4.zip
chromium_src-21d683b2efbe56e98d1b77aaa96d831240b7e1c4.tar.gz
chromium_src-21d683b2efbe56e98d1b77aaa96d831240b7e1c4.tar.bz2
Geolocation exceptions window, Windows.
This also makes some correctness/consistency fixes to the model that affect other OSes, e.g. we now allow "remove" on the selected exception set iff all selected exceptions are removable. BUG=39817 TEST=Geolocation exceptions window exists on windows, allows sorting by either column Review URL: http://codereview.chromium.org/1539021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43669 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/resources/locale_settings.grd9
-rw-r--r--chrome/browser/cocoa/geolocation_exceptions_window_controller.mm34
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_table_model.cc200
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_table_model.h22
-rw-r--r--chrome/browser/gtk/options/geolocation_content_exceptions_window.cc35
-rw-r--r--chrome/browser/gtk/options/geolocation_content_exceptions_window.h6
-rwxr-xr-xchrome/browser/views/options/content_filter_page_view.cc15
-rw-r--r--chrome/browser/views/options/geolocation_exceptions_view.cc180
-rw-r--r--chrome/browser/views/options/geolocation_exceptions_view.h91
-rwxr-xr-xchrome/chrome_browser.gypi2
10 files changed, 484 insertions, 110 deletions
diff --git a/chrome/app/resources/locale_settings.grd b/chrome/app/resources/locale_settings.grd
index d715425..5b72014 100644
--- a/chrome/app/resources/locale_settings.grd
+++ b/chrome/app/resources/locale_settings.grd
@@ -628,6 +628,15 @@
<message name="IDS_CONTENT_EXCEPTION_DIALOG_HEIGHT_LINES" use_name_for_id="true">
16
</message>
+
+ <!-- The width and height of the Geolocation Settings Exceptions -->
+ <!-- dialog box in characters and lines (See above). -->
+ <message name="IDS_GEOLOCATION_EXCEPTION_DIALOG_WIDTH_CHARS" use_name_for_id="true">
+ 90
+ </message>
+ <message name="IDS_GEOLOCATION_EXCEPTION_DIALOG_HEIGHT_LINES" use_name_for_id="true">
+ 16
+ </message>
</messages>
</release>
</grit>
diff --git a/chrome/browser/cocoa/geolocation_exceptions_window_controller.mm b/chrome/browser/cocoa/geolocation_exceptions_window_controller.mm
index 4a6a1d3..02715bb 100644
--- a/chrome/browser/cocoa/geolocation_exceptions_window_controller.mm
+++ b/chrome/browser/cocoa/geolocation_exceptions_window_controller.mm
@@ -18,8 +18,7 @@
@interface GeolocationExceptionsWindowController (Private)
- (id)initWithSettingsMap:(GeolocationContentSettingsMap*)settingsMap;
-- (void)selectedRemovableIndices:(std::set<int>*)indices;
-- (int)countSelectedRemovable;
+- (void)selectedRows:(GeolocationContentSettingsTableModel::Rows*)rows;
- (void)adjustEditingButtons;
- (void)modelDidChange;
@end
@@ -135,13 +134,9 @@ GeolocationExceptionsWindowController* g_exceptionWindow = nil;
}
- (IBAction)removeException:(id)sender {
- std::set<int> indices;
- [self selectedRemovableIndices:&indices];
-
- for (std::set<int>::reverse_iterator i = indices.rbegin();
- i != indices.rend(); ++i) {
- model_->RemoveException(*i);
- }
+ GeolocationContentSettingsTableModel::Rows rows;
+ [self selectedRows:&rows];
+ model_->RemoveExceptions(rows);
}
- (IBAction)removeAllExceptions:(id)sender {
@@ -180,27 +175,20 @@ GeolocationExceptionsWindowController* g_exceptionWindow = nil;
// Private --------------------------------------------------------------------
-// Returns the indices of all selected rows that are removable.
-- (void)selectedRemovableIndices:(std::set<int>*)indices {
+// Returns the selected rows.
+- (void)selectedRows:(GeolocationContentSettingsTableModel::Rows*)rows {
NSIndexSet* selection = [tableView_ selectedRowIndexes];
for (NSUInteger index = [selection lastIndex]; index != NSNotFound;
- index = [selection indexLessThanIndex:index]) {
- if (model_->CanRemoveException(index))
- indices->insert(index);
- }
-}
-
-// Returns how many of the selected rows are removable.
-- (int)countSelectedRemovable {
- std::set<int> indices;
- [self selectedRemovableIndices:&indices];
- return indices.size();
+ index = [selection indexLessThanIndex:index])
+ rows->insert(index);
}
// This method appropriately sets the enabled states on the table's editing
// buttons.
- (void)adjustEditingButtons {
- [removeButton_ setEnabled:([self countSelectedRemovable] > 0)];
+ GeolocationContentSettingsTableModel::Rows rows;
+ [self selectedRows:&rows];
+ [removeButton_ setEnabled:model_->CanRemoveExceptions(rows)];
[removeAllButton_ setEnabled:([tableView_ numberOfRows] > 0)];
}
diff --git a/chrome/browser/geolocation/geolocation_content_settings_table_model.cc b/chrome/browser/geolocation/geolocation_content_settings_table_model.cc
index 16245f3..09b8caf 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_table_model.cc
+++ b/chrome/browser/geolocation/geolocation_content_settings_table_model.cc
@@ -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 @@ GeolocationContentSettingsTableModel::GeolocationContentSettingsTableModel(
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 @@ std::wstring GeolocationContentSettingsTableModel::GetText(int row,
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 @@ std::wstring GeolocationContentSettingsTableModel::GetText(int row,
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 @@ void GeolocationContentSettingsTableModel::SetObserver(
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) {
diff --git a/chrome/browser/geolocation/geolocation_content_settings_table_model.h b/chrome/browser/geolocation/geolocation_content_settings_table_model.h
index e4d9d36..4d42407 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_table_model.h
+++ b/chrome/browser/geolocation/geolocation_content_settings_table_model.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_CONTENT_SETTINGS_TABLE_MODEL_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_CONTENT_SETTINGS_TABLE_MODEL_H_
+#include <set>
#include <vector>
#include "app/table_model.h"
@@ -14,18 +15,22 @@
class GeolocationContentSettingsTableModel : public TableModel {
public:
+ typedef std::set<size_t> Rows;
+
explicit GeolocationContentSettingsTableModel(
GeolocationContentSettingsMap* map);
- // Return whether the given row can be removed. A parent with setting of
- // CONTENT_SETTING_DEFAULT can't be removed.
- bool CanRemoveException(int row) const;
+ // Return whether the given set of rows can be removed. A parent with setting
+ // of CONTENT_SETTING_DEFAULT can't be removed unless all its children are
+ // also being removed.
+ bool CanRemoveExceptions(const Rows& rows) const;
- // Removes the exception at the specified index from the map. If it is a
- // parent, the row in model will be updated to have CONTENT_SETTING_DEFAULT.
- // If it is the only child of a CONTENT_SETTING_DEFAULT parent, the parent
- // will be removed from the model too.
- void RemoveException(int row);
+ // Removes the exceptions at the specified indexes. If an exception is a
+ // parent, and it has children, the row in model will be updated to have
+ // CONTENT_SETTING_DEFAULT. If it is the only child of a
+ // CONTENT_SETTING_DEFAULT parent, the parent will be removed from the model
+ // too.
+ void RemoveExceptions(const Rows& rows);
// Removes all the exceptions from both the map and model.
void RemoveAll();
@@ -34,6 +39,7 @@ class GeolocationContentSettingsTableModel : public TableModel {
virtual int RowCount();
virtual std::wstring GetText(int row, int column_id);
virtual void SetObserver(TableModelObserver* observer);
+ virtual int CompareValues(int row1, int row2, int column_id);
private:
struct Entry {
diff --git a/chrome/browser/gtk/options/geolocation_content_exceptions_window.cc b/chrome/browser/gtk/options/geolocation_content_exceptions_window.cc
index 492753b..106d721 100644
--- a/chrome/browser/gtk/options/geolocation_content_exceptions_window.cc
+++ b/chrome/browser/gtk/options/geolocation_content_exceptions_window.cc
@@ -143,37 +143,24 @@ void GeolocationContentExceptionsWindow::UpdateButtonState() {
int row_count = gtk_tree_model_iter_n_children(
GTK_TREE_MODEL(list_store_), NULL);
- gtk_widget_set_sensitive(remove_button_, CountSelectedRemovable() >= 1);
+ GeolocationContentSettingsTableModel::Rows rows;
+ GetSelectedRows(&rows);
+ gtk_widget_set_sensitive(remove_button_, model_->CanRemoveExceptions(rows));
gtk_widget_set_sensitive(remove_all_button_, row_count > 0);
}
-void GeolocationContentExceptionsWindow::GetSelectedRemovableIndicies(
- std::set<int>* indicies) {
- gtk_tree::GetSelectedIndicies(treeview_selection_, indicies);
-
- for (std::set<int>::iterator i = indicies->begin(); i != indicies->end(); ) {
- std::set<int>::iterator prev = i;
- ++i;
- if (!model_->CanRemoveException(*prev))
- indicies->erase(prev);
- }
-}
-
-int GeolocationContentExceptionsWindow::CountSelectedRemovable() {
+void GeolocationContentExceptionsWindow::GetSelectedRows(
+ GeolocationContentSettingsTableModel::Rows* rows) {
std::set<int> indicies;
- GetSelectedRemovableIndicies(&indicies);
- return indicies.size();
+ gtk_tree::GetSelectedIndicies(treeview_selection_, &indicies);
+ for (std::set<int>::iterator i = indicies.begin(); i != indicies.end(); ++i)
+ rows->insert(*i);
}
void GeolocationContentExceptionsWindow::Remove(GtkWidget* widget) {
- std::set<int> indicies;
- GetSelectedRemovableIndicies(&indicies);
-
- for (std::set<int>::reverse_iterator i = indicies.rbegin();
- i != indicies.rend(); ++i) {
- model_->RemoveException(*i);
- }
-
+ GeolocationContentSettingsTableModel::Rows rows;
+ GetSelectedRows(&rows);
+ model_->RemoveExceptions(rows);
UpdateButtonState();
}
diff --git a/chrome/browser/gtk/options/geolocation_content_exceptions_window.h b/chrome/browser/gtk/options/geolocation_content_exceptions_window.h
index d9f30c2..932184c 100644
--- a/chrome/browser/gtk/options/geolocation_content_exceptions_window.h
+++ b/chrome/browser/gtk/options/geolocation_content_exceptions_window.h
@@ -41,11 +41,7 @@ class GeolocationContentExceptionsWindow
// Updates which buttons are enabled.
void UpdateButtonState();
- // Populate |indicies| with the currently selected rows that are removable.
- void GetSelectedRemovableIndicies(std::set<int>* indicies);
-
- // Return the number of selected rows which can be removed.
- int CountSelectedRemovable();
+ void GetSelectedRows(GeolocationContentSettingsTableModel::Rows* rows);
// Callbacks for the buttons.
CHROMEGTK_CALLBACK_0(GeolocationContentExceptionsWindow, void, Remove);
diff --git a/chrome/browser/views/options/content_filter_page_view.cc b/chrome/browser/views/options/content_filter_page_view.cc
index 134f766..0327206 100755
--- a/chrome/browser/views/options/content_filter_page_view.cc
+++ b/chrome/browser/views/options/content_filter_page_view.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/options/exceptions_view.h"
+#include "chrome/browser/views/options/geolocation_exceptions_view.h"
#include "grit/generated_resources.h"
#include "views/controls/button/radio_button.h"
#include "views/grid_layout.h"
@@ -154,12 +155,14 @@ void ContentFilterPageView::InitControlLayout() {
void ContentFilterPageView::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == exceptions_button_) {
- if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION)
- return; // TODO(pkasting): Implement geolocation exceptions dialog.
-
- ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
- profile()->GetHostContentSettingsMap(),
- content_type_);
+ if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ GeolocationExceptionsView::ShowExceptionsWindow(
+ GetWindow()->GetNativeWindow(),
+ profile()->GetGeolocationContentSettingsMap());
+ } else {
+ ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
+ profile()->GetHostContentSettingsMap(), content_type_);
+ }
return;
}
diff --git a/chrome/browser/views/options/geolocation_exceptions_view.cc b/chrome/browser/views/options/geolocation_exceptions_view.cc
new file mode 100644
index 0000000..336e9bb
--- /dev/null
+++ b/chrome/browser/views/options/geolocation_exceptions_view.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/views/options/geolocation_exceptions_view.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "gfx/rect.h"
+#include "views/controls/button/native_button.h"
+#include "views/controls/table/table_view.h"
+#include "views/grid_layout.h"
+#include "views/standard_layout.h"
+#include "views/window/window.h"
+
+static const int kExceptionsViewInsetSize = 5;
+static GeolocationExceptionsView* instance = NULL;
+
+// static
+void GeolocationExceptionsView::ShowExceptionsWindow(
+ gfx::NativeWindow parent,
+ GeolocationContentSettingsMap* map) {
+ if (!instance) {
+ instance = new GeolocationExceptionsView(map);
+ views::Window::CreateChromeWindow(parent, gfx::Rect(), instance);
+ }
+
+ // This will show invisible windows and bring visible windows to the front.
+ instance->window()->Show();
+}
+
+GeolocationExceptionsView::~GeolocationExceptionsView() {
+ instance = NULL;
+ table_->SetModel(NULL);
+}
+
+void GeolocationExceptionsView::OnSelectionChanged() {
+ UpdateButtonState();
+}
+
+void GeolocationExceptionsView::OnTableViewDelete(
+ views::TableView* table_view) {
+ Remove();
+}
+
+void GeolocationExceptionsView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ switch (sender->tag()) {
+ case IDS_EXCEPTIONS_REMOVEALL_BUTTON:
+ RemoveAll();
+ break;
+ case IDS_EXCEPTIONS_REMOVE_BUTTON:
+ Remove();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void GeolocationExceptionsView::Layout() {
+ views::NativeButton* buttons[] = { remove_button_, remove_all_button_ };
+
+ // The buttons are placed in the parent, but we need to lay them out.
+ int max_y = GetParent()->GetLocalBounds(false).bottom() - kButtonVEdgeMargin;
+ int x = kPanelHorizMargin;
+
+ for (size_t i = 0; i < arraysize(buttons); ++i) {
+ gfx::Size pref = buttons[i]->GetPreferredSize();
+ buttons[i]->SetBounds(x, max_y - pref.height(), pref.width(),
+ pref.height());
+ x += pref.width() + kRelatedControlHorizontalSpacing;
+ }
+
+ // Lay out the rest of this view.
+ View::Layout();
+}
+
+gfx::Size GeolocationExceptionsView::GetPreferredSize() {
+ return gfx::Size(views::Window::GetLocalizedContentsSize(
+ IDS_GEOLOCATION_EXCEPTION_DIALOG_WIDTH_CHARS,
+ IDS_GEOLOCATION_EXCEPTION_DIALOG_HEIGHT_LINES));
+}
+
+void GeolocationExceptionsView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && child == this)
+ Init();
+}
+
+std::wstring GeolocationExceptionsView::GetWindowTitle() const {
+ return l10n_util::GetString(IDS_GEOLOCATION_EXCEPTION_TITLE);
+}
+
+GeolocationExceptionsView::GeolocationExceptionsView(
+ GeolocationContentSettingsMap* map)
+ : model_(map),
+ table_(NULL),
+ remove_button_(NULL),
+ remove_all_button_(NULL) {
+}
+
+void GeolocationExceptionsView::Init() {
+ if (table_)
+ return; // We've already Init'd.
+
+ using views::GridLayout;
+
+ std::vector<TableColumn> columns;
+ columns.push_back(
+ TableColumn(IDS_EXCEPTIONS_HOSTNAME_HEADER, TableColumn::LEFT, -1, .75));
+ columns.back().sortable = true;
+ columns.push_back(
+ TableColumn(IDS_EXCEPTIONS_ACTION_HEADER, TableColumn::LEFT, -1, .25));
+ columns.back().sortable = true;
+ table_ = new views::TableView(&model_, columns, views::TEXT_ONLY, false, true,
+ false);
+ views::TableView::SortDescriptors sort;
+ sort.push_back(
+ views::TableView::SortDescriptor(IDS_EXCEPTIONS_HOSTNAME_HEADER, true));
+ table_->SetSortDescriptors(sort);
+ table_->SetObserver(this);
+
+ remove_button_ = new views::NativeButton(
+ this, l10n_util::GetString(IDS_EXCEPTIONS_REMOVE_BUTTON));
+ remove_button_->set_tag(IDS_EXCEPTIONS_REMOVE_BUTTON);
+ remove_all_button_ = new views::NativeButton(
+ this, l10n_util::GetString(IDS_EXCEPTIONS_REMOVEALL_BUTTON));
+ remove_all_button_->set_tag(IDS_EXCEPTIONS_REMOVEALL_BUTTON);
+
+ View* parent = GetParent();
+ parent->AddChildView(remove_button_);
+ parent->AddChildView(remove_all_button_);
+
+ GridLayout* layout = new GridLayout(this);
+ layout->SetInsets(kExceptionsViewInsetSize, kExceptionsViewInsetSize,
+ kExceptionsViewInsetSize, kExceptionsViewInsetSize);
+ SetLayoutManager(layout);
+
+ const int single_column_layout_id = 0;
+ views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
+ column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+
+ layout->StartRow(1, single_column_layout_id);
+ layout->AddView(table_);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+
+ UpdateButtonState();
+}
+
+GeolocationContentSettingsTableModel::Rows
+ GeolocationExceptionsView::GetSelectedRows() const {
+ GeolocationContentSettingsTableModel::Rows rows;
+ for (views::TableView::iterator i(table_->SelectionBegin());
+ i != table_->SelectionEnd(); ++i)
+ rows.insert(*i);
+ return rows;
+}
+
+void GeolocationExceptionsView::UpdateButtonState() {
+ remove_button_->SetEnabled(model_.CanRemoveExceptions(GetSelectedRows()));
+ remove_all_button_->SetEnabled(model_.RowCount() > 0);
+}
+
+void GeolocationExceptionsView::Remove() {
+ model_.RemoveExceptions(GetSelectedRows());
+ UpdateButtonState();
+}
+
+void GeolocationExceptionsView::RemoveAll() {
+ model_.RemoveAll();
+ UpdateButtonState();
+}
diff --git a/chrome/browser/views/options/geolocation_exceptions_view.h b/chrome/browser/views/options/geolocation_exceptions_view.h
new file mode 100644
index 0000000..1a82956
--- /dev/null
+++ b/chrome/browser/views/options/geolocation_exceptions_view.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_OPTIONS_GEOLOCATION_EXCEPTIONS_VIEW_H_
+#define CHROME_BROWSER_VIEWS_OPTIONS_GEOLOCATION_EXCEPTIONS_VIEW_H_
+
+#include <string>
+
+#include "chrome/browser/geolocation/geolocation_content_settings_table_model.h"
+#include "chrome/common/content_settings.h"
+#include "views/controls/button/button.h"
+#include "views/controls/table/table_view_observer.h"
+#include "views/window/dialog_delegate.h"
+
+class GeolocationContentSettingsMap;
+
+namespace views {
+class NativeButton;
+class TableView;
+}
+
+// GeolocationExceptionsView is responsible for showing the user the set of
+// site-specific geolocation permissions. The exceptions are shown in a table
+// view by way of a GeolocationContentSettingsTableModel. The user can remove
+// exceptions.
+// Use the ShowExceptionsWindow method to create and show a
+// GeolocationExceptionsView, which is deleted when the window closes.
+class GeolocationExceptionsView : public views::View,
+ public views::ButtonListener,
+ public views::DialogDelegate,
+ public views::TableViewObserver {
+ public:
+ // Shows the Exceptions window.
+ static void ShowExceptionsWindow(gfx::NativeWindow parent,
+ GeolocationContentSettingsMap* map);
+
+ virtual ~GeolocationExceptionsView();
+
+ // TableViewObserver overrides:
+ virtual void OnSelectionChanged();
+ virtual void OnTableViewDelete(views::TableView* table_view);
+
+ // views::ButtonListener implementation.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // views::View overrides:
+ virtual void Layout();
+ virtual gfx::Size GetPreferredSize();
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
+
+ // views::WindowDelegate implementation.
+ virtual int GetDialogButtons() const {
+ return MessageBoxFlags::DIALOGBUTTON_CANCEL;
+ }
+ virtual bool CanResize() const { return true; }
+ virtual std::wstring GetWindowTitle() const;
+ virtual views::View* GetContentsView() { return this; }
+
+ private:
+ explicit GeolocationExceptionsView(GeolocationContentSettingsMap* map);
+
+ void Init();
+
+ // Resets the enabled state of the buttons from the model.
+ void UpdateButtonState();
+
+ // Returns the set of selected rows.
+ GeolocationContentSettingsTableModel::Rows GetSelectedRows() const;
+
+ // Removes the selected item.
+ void Remove();
+
+ // Removes all.
+ void RemoveAll();
+
+ // The model displayed in the table.
+ GeolocationContentSettingsTableModel model_;
+
+ views::TableView* table_;
+
+ views::NativeButton* remove_button_;
+ views::NativeButton* remove_all_button_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationExceptionsView);
+};
+
+#endif // CHROME_BROWSER_VIEWS_OPTIONS_GEOLOCATION_EXCEPTIONS_VIEW_H_
+
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d161519..2ce186e 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2305,6 +2305,8 @@
'browser/views/options/fonts_page_view.h',
'browser/views/options/general_page_view.cc',
'browser/views/options/general_page_view.h',
+ 'browser/views/options/geolocation_exceptions_view.cc',
+ 'browser/views/options/geolocation_exceptions_view.h',
'browser/views/options/languages_page_view.cc',
'browser/views/options/languages_page_view.h',
'browser/views/options/options_group_view.cc',