diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-05 22:50:13 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-05 22:50:13 +0000 |
commit | 21d683b2efbe56e98d1b77aaa96d831240b7e1c4 (patch) | |
tree | cb5091b789e9eb11ad4a70f61b1da30872d7c517 | |
parent | e6af8f1c212e3ca8b178853ea21fab1758a6c1a7 (diff) | |
download | chromium_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
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', |