diff options
author | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-19 19:01:47 +0000 |
---|---|---|
committer | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-19 19:01:47 +0000 |
commit | 47115104dc1a6a06b85dc23cc4d5993847ea0fa7 (patch) | |
tree | edcb2976dbf42db35e85d711a08db8777187d67b | |
parent | 083d0031696fedc3ac35351c059a3097b6bfa87e (diff) | |
download | chromium_src-47115104dc1a6a06b85dc23cc4d5993847ea0fa7.zip chromium_src-47115104dc1a6a06b85dc23cc4d5993847ea0fa7.tar.gz chromium_src-47115104dc1a6a06b85dc23cc4d5993847ea0fa7.tar.bz2 |
GTK: Implement the exceptions dialog for the content filtering settings.
BUG=35178
TEST=none
Review URL: http://codereview.chromium.org/646060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39468 0039d316-1c4b-4281-b951-d872f2087c98
15 files changed, 663 insertions, 25 deletions
diff --git a/chrome/browser/views/options/content_exceptions_table_model.cc b/chrome/browser/content_exceptions_table_model.cc index a733747..530fc10 100644 --- a/chrome/browser/views/options/content_exceptions_table_model.cc +++ b/chrome/browser/content_exceptions_table_model.cc @@ -2,7 +2,7 @@ // 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/content_exceptions_table_model.h" +#include "chrome/browser/content_exceptions_table_model.h" #include "app/l10n_util.h" #include "app/table_model_observer.h" diff --git a/chrome/browser/views/options/content_exceptions_table_model.h b/chrome/browser/content_exceptions_table_model.h index 8016eb0..9ade4d8 100644 --- a/chrome/browser/views/options/content_exceptions_table_model.h +++ b/chrome/browser/content_exceptions_table_model.h @@ -2,8 +2,8 @@ // 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_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ -#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ +#ifndef CHROME_BROWSER_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ +#define CHROME_BROWSER_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ #include <string> @@ -51,4 +51,4 @@ class ContentExceptionsTableModel : public TableModel { DISALLOW_COPY_AND_ASSIGN(ContentExceptionsTableModel); }; -#endif // CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ +#endif // CHROME_BROWSER_CONTENT_EXCEPTIONS_TABLE_MODEL_H_ diff --git a/chrome/browser/gtk/options/content_exception_editor.cc b/chrome/browser/gtk/options/content_exception_editor.cc new file mode 100644 index 0000000..809a31b --- /dev/null +++ b/chrome/browser/gtk/options/content_exception_editor.cc @@ -0,0 +1,168 @@ +// 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/gtk/options/content_exception_editor.h" + +#include "app/l10n_util.h" +#include "base/message_loop.h" +#include "chrome/browser/content_exceptions_table_model.h" +#include "chrome/browser/host_content_settings_map.h" +#include "chrome/common/gtk_util.h" +#include "googleurl/src/url_canon.h" +#include "googleurl/src/url_parse.h" +#include "grit/generated_resources.h" +#include "net/base/net_util.h" + +namespace { + +// The settings shown in the combobox if show_ask_ is false; +static const ContentSetting kNoAskSettings[] = { CONTENT_SETTING_ALLOW, + CONTENT_SETTING_BLOCK }; + +// The settings shown in the combobox if show_ask_ is true; +static const ContentSetting kAskSettings[] = { CONTENT_SETTING_ALLOW, + CONTENT_SETTING_ASK, + CONTENT_SETTING_BLOCK }; + +// Returns true if the host name is valid. +bool ValidHost(const std::string& host) { + if (host.empty()) + return false; + + url_canon::CanonHostInfo host_info; + return !net::CanonicalizeHost(host, &host_info).empty(); +} + +} // namespace + +ContentExceptionEditor::ContentExceptionEditor( + GtkWindow* parent, + ContentExceptionEditor::Delegate* delegate, + ContentExceptionsTableModel* model, + int index, + const std::string& host, + ContentSetting setting) + : delegate_(delegate), + model_(model), + show_ask_(model->content_type() == CONTENT_SETTINGS_TYPE_COOKIES), + index_(index), + host_(host), + setting_(setting) { + dialog_ = gtk_dialog_new_with_buttons( + l10n_util::GetStringUTF8(is_new() ? + IDS_EXCEPTION_EDITOR_NEW_TITLE : + IDS_EXCEPTION_EDITOR_TITLE).c_str(), + parent, + // Non-modal. + static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK); + + entry_ = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(entry_), host_.c_str()); + g_signal_connect(entry_, "changed", G_CALLBACK(OnEntryChanged), this); + gtk_entry_set_activates_default(GTK_ENTRY(entry_), TRUE); + + action_combo_ = gtk_combo_box_new_text(); + for (int i = 0; i < GetItemCount(); ++i) { + gtk_combo_box_append_text(GTK_COMBO_BOX(action_combo_), + GetTitleFor(i).c_str()); + } + gtk_combo_box_set_active(GTK_COMBO_BOX(action_combo_), + IndexForSetting(setting_)); + + GtkWidget* table = gtk_util::CreateLabeledControlsGroup( + NULL, + l10n_util::GetStringUTF8(IDS_EXCEPTION_EDITOR_HOST_TITLE).c_str(), + entry_, + l10n_util::GetStringUTF8(IDS_EXCEPTION_EDITOR_ACTION_TITLE).c_str(), + action_combo_, + NULL); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), table); + + // Prime the state of the buttons. + OnEntryChanged(GTK_EDITABLE(entry_), this); + + gtk_widget_show_all(dialog_); + + g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); + g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this); +} + +int ContentExceptionEditor::GetItemCount() { + return show_ask_ ? arraysize(kAskSettings) : arraysize(kNoAskSettings); +} + +std::string ContentExceptionEditor::GetTitleFor(int index) { + switch (SettingForIndex(index)) { + case CONTENT_SETTING_ALLOW: + return l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ALLOW_BUTTON); + case CONTENT_SETTING_BLOCK: + return l10n_util::GetStringUTF8(IDS_EXCEPTIONS_BLOCK_BUTTON); + case CONTENT_SETTING_ASK: + return l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ASK_BUTTON); + default: + NOTREACHED(); + } + return std::string(); +} + +ContentSetting ContentExceptionEditor::SettingForIndex(int index) { + return show_ask_ ? kAskSettings[index] : kNoAskSettings[index]; +} + +int ContentExceptionEditor::IndexForSetting(ContentSetting setting) { + for (int i = 0; i < GetItemCount(); ++i) + if (SettingForIndex(i) == setting) + return i; + NOTREACHED(); + return 0; +} + +// static +void ContentExceptionEditor::OnEntryChanged(GtkEditable* entry, + ContentExceptionEditor* window) { + bool can_accept = false; + std::string new_host = gtk_entry_get_text(GTK_ENTRY(window->entry_)); + if (window->is_new()) { + can_accept = ValidHost(new_host) && + (window->model_->IndexOfExceptionByHost(new_host) == -1); + } else { + can_accept = !new_host.empty() && + (window->host_ == new_host || + (ValidHost(new_host) && + window->model_->IndexOfExceptionByHost(new_host) == -1)); + } + + gtk_dialog_set_response_sensitive(GTK_DIALOG(window->dialog_), + GTK_RESPONSE_OK, can_accept); +} + +// static +void ContentExceptionEditor::OnResponse( + GtkWidget* sender, + int response_id, + ContentExceptionEditor* window) { + if (response_id == GTK_RESPONSE_OK) { + // Notify our delegate to update everything. + std::string new_host = gtk_entry_get_text(GTK_ENTRY(window->entry_)); + ContentSetting setting = window->SettingForIndex(gtk_combo_box_get_active( + GTK_COMBO_BOX(window->action_combo_))); + window->delegate_->AcceptExceptionEdit(new_host, setting, window->index_, + window->is_new()); + } + + gtk_widget_destroy(window->dialog_); +} + +// static +void ContentExceptionEditor::OnWindowDestroy( + GtkWidget* widget, + ContentExceptionEditor* editor) { + MessageLoop::current()->DeleteSoon(FROM_HERE, editor); +} diff --git a/chrome/browser/gtk/options/content_exception_editor.h b/chrome/browser/gtk/options/content_exception_editor.h new file mode 100644 index 0000000..c71e693 --- /dev/null +++ b/chrome/browser/gtk/options/content_exception_editor.h @@ -0,0 +1,80 @@ +// 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_GTK_OPTIONS_CONTENT_EXCEPTION_EDITOR_H_ +#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTION_EDITOR_H_ + +#include <gtk/gtk.h> + +#include <string> + +#include "chrome/browser/content_exceptions_table_model.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/content_settings_types.h" + +// An editor which lets the user create or edit an individual exception to the +// current content setting policy. (i.e. let www.google.com always show +// images). Modal to parent. +class ContentExceptionEditor { + public: + class Delegate { + public: + // Invoked when the user accepts the edit. + virtual void AcceptExceptionEdit(const std::string& host, + ContentSetting setting, + int index, + bool is_new) = 0; + + protected: + virtual ~Delegate() {} + }; + + ContentExceptionEditor(GtkWindow* parent, + Delegate* delegate, + ContentExceptionsTableModel* model, + int index, + const std::string& host, + ContentSetting setting); + + private: + // Returns true if we're adding a new item. + bool is_new() const { return index_ == -1; } + + // Returns the number of items in the |action_combo_|. + int GetItemCount(); + + // Returns the string representation for an item in |action_combo_|. + std::string GetTitleFor(int index); + + // Changes an index from |action_combo_| into a ContentSetting and vice versa. + ContentSetting SettingForIndex(int index); + int IndexForSetting(ContentSetting setting); + + // GTK callbacks + static void OnEntryChanged(GtkEditable* entry, + ContentExceptionEditor* window); + static void OnResponse(GtkWidget* sender, + int response_id, + ContentExceptionEditor* window); + static void OnWindowDestroy(GtkWidget* widget, + ContentExceptionEditor* editor); + + Delegate* delegate_; + ContentExceptionsTableModel* model_; + bool show_ask_; + + // Index of the item being edited. If -1, indicates this is a new entry. + const int index_; + const std::string host_; + const ContentSetting setting_; + + // UI widgets. + GtkWidget* dialog_; + GtkWidget* entry_; + GtkWidget* action_combo_; + + DISALLOW_COPY_AND_ASSIGN(ContentExceptionEditor); +}; + +#endif // CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTION_EDITOR_H_ diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.cc b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc new file mode 100644 index 0000000..eea927f --- /dev/null +++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc @@ -0,0 +1,270 @@ +// 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/gtk/options/content_exceptions_window_gtk.h" + +#include "app/gfx/gtk_util.h" +#include "app/l10n_util.h" +#include "base/message_loop.h" +#include "chrome/browser/gtk/options/content_exception_editor.h" +#include "chrome/common/gtk_util.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" + +namespace { + +// Singletons for each possible exception window. +ContentExceptionsWindowGtk* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL }; + +// Response ids for our custom buttons. +enum { + RESPONSE_ADD = 1, + RESPONSE_EDIT, + RESPONSE_REMOVE, + RESPONSE_REMOVE_ALL +}; + +GtkWidget* BuildDialogButton(GtkWidget* dialog, int ids_id, + const gchar* stock_id, gint response_id) { + GtkWidget* widget = gtk_util::AddButtonToDialog( + dialog, + gtk_util::ConvertAcceleratorsFromWindowsStyle( + l10n_util::GetStringUTF8(ids_id)).c_str(), + stock_id, + response_id); + gtk_button_set_use_underline(GTK_BUTTON(widget), TRUE); + gtk_button_box_set_child_secondary( + GTK_BUTTON_BOX(GTK_DIALOG(dialog)->action_area), + widget, + TRUE); + + return widget; +} + +} // namespace + +// static +void ContentExceptionsWindowGtk::ShowExceptionsWindow( + GtkWindow* parent, + HostContentSettingsMap* map, + ContentSettingsType type) { + DCHECK(map); + DCHECK(type < CONTENT_SETTINGS_NUM_TYPES); + + if (!instances[type]) { + // Create the options window. + instances[type] = new ContentExceptionsWindowGtk(parent, map, type); + } +} + +ContentExceptionsWindowGtk::~ContentExceptionsWindowGtk() { +} + +ContentExceptionsWindowGtk::ContentExceptionsWindowGtk( + GtkWindow* parent, + HostContentSettingsMap* map, + ContentSettingsType type) { + // Build the model adapters that translate views and TableModels into + // something GTK can use. + list_store_ = gtk_list_store_new(COL_COUNT, G_TYPE_STRING, G_TYPE_STRING); + treeview_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_)); + g_object_unref(list_store_); + + // Set up the properties of the treeview + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_), TRUE); + + GtkTreeViewColumn* hostname_column = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8(IDS_EXCEPTIONS_HOSTNAME_HEADER).c_str(), + gtk_cell_renderer_text_new(), + "text", COL_HOSTNAME, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), hostname_column); + + GtkTreeViewColumn* action_column = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8(IDS_EXCEPTIONS_ACTION_HEADER).c_str(), + gtk_cell_renderer_text_new(), + "text", COL_ACTION, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), action_column); + + treeview_selection_ = gtk_tree_view_get_selection( + GTK_TREE_VIEW(treeview_)); + gtk_tree_selection_set_mode(treeview_selection_, GTK_SELECTION_MULTIPLE); + g_signal_connect(treeview_selection_, "changed", + G_CALLBACK(OnSelectionChanged), this); + + // Bind |list_store_| to our C++ model. + model_.reset(new ContentExceptionsTableModel(map, type)); + model_adapter_.reset(new gtk_tree::TableAdapter(this, list_store_, + model_.get())); + // Force a reload of everything to copy data into |list_store_|. + model_adapter_->OnModelChanged(); + + dialog_ = gtk_dialog_new_with_buttons( + GetWindowTitle().c_str(), + parent, + static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE, + NULL); + // Allow browser windows to go in front of the options dialog in metacity. + gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), + gtk_util::kContentAreaSpacing); + + // Create a scrolled window to wrap the treeview widget in order to have a + // frame. + GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), + GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), scrolled); + + // Add the main tree view to the scrolled window. + gtk_container_add(GTK_CONTAINER(scrolled), treeview_); + + BuildDialogButton(dialog_, IDS_EXCEPTIONS_ADD_BUTTON, + GTK_STOCK_ADD, RESPONSE_ADD); + edit_button_ = BuildDialogButton(dialog_, IDS_EXCEPTIONS_EDIT_BUTTON, + GTK_STOCK_EDIT, RESPONSE_EDIT); + remove_button_ = BuildDialogButton(dialog_, IDS_EXCEPTIONS_REMOVE_BUTTON, + GTK_STOCK_REMOVE, RESPONSE_REMOVE); + remove_all_button_ = BuildDialogButton( + dialog_, IDS_EXCEPTIONS_REMOVEALL_BUTTON, + GTK_STOCK_CLEAR, RESPONSE_REMOVE_ALL); + + UpdateButtonState(); + + gtk_widget_show_all(dialog_); + + g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); + g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this); +} + +void ContentExceptionsWindowGtk::SetColumnValues(int row, GtkTreeIter* iter) { + std::wstring hostname = model_->GetText(row, IDS_EXCEPTIONS_HOSTNAME_HEADER); + gtk_list_store_set(list_store_, iter, COL_HOSTNAME, + WideToUTF8(hostname).c_str(), -1); + + std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER); + gtk_list_store_set(list_store_, iter, COL_ACTION, + WideToUTF8(action).c_str(), -1); +} + +void ContentExceptionsWindowGtk::AcceptExceptionEdit(const std::string& host, + ContentSetting setting, + int index, + bool is_new) { + if (!is_new) + model_->RemoveException(index); + model_->AddException(host, setting); + + int new_index = model_->IndexOfExceptionByHost(host); + DCHECK(new_index != -1); + + GtkTreePath* path = gtk_tree_path_new_from_indices(new_index, -1); + gtk_tree_selection_select_path(treeview_selection_, path); + gtk_tree_path_free(path); + + UpdateButtonState(); +} + +void ContentExceptionsWindowGtk::UpdateButtonState() { + int num_selected = gtk_tree_selection_count_selected_rows( + treeview_selection_); + int row_count = gtk_tree_model_iter_n_children( + GTK_TREE_MODEL(list_store_), NULL); + + // TODO(erg): http://crbug.com/34177 , support editing of more than one entry + // at a time. + gtk_widget_set_sensitive(edit_button_, num_selected == 1); + gtk_widget_set_sensitive(remove_button_, num_selected >= 1); + gtk_widget_set_sensitive(remove_all_button_, row_count > 0); +} + +void ContentExceptionsWindowGtk::Add() { + new ContentExceptionEditor(GTK_WINDOW(dialog_), + this, model_.get(), -1, std::string(), + CONTENT_SETTING_BLOCK); +} + +void ContentExceptionsWindowGtk::Edit() { + std::set<int> indices; + gtk_tree::GetSelectedIndicies(treeview_selection_, &indices); + DCHECK_GT(indices.size(), 0u); + int index = *indices.begin(); + const HostContentSettingsMap::HostSettingPair& entry = + model_->entry_at(index); + new ContentExceptionEditor(GTK_WINDOW(dialog_), this, model_.get(), index, + entry.first, entry.second); +} + +void ContentExceptionsWindowGtk::Remove() { + std::set<int> indices; + gtk_tree::GetSelectedIndicies(treeview_selection_, &indices); + + for (std::set<int>::reverse_iterator i = indices.rbegin(); + i != indices.rend(); ++i) { + model_->RemoveException(*i); + } + + UpdateButtonState(); +} + +void ContentExceptionsWindowGtk::RemoveAll() { + model_->RemoveAll(); + UpdateButtonState(); +} + +std::string ContentExceptionsWindowGtk::GetWindowTitle() const { + switch (model_->content_type()) { + case CONTENT_SETTINGS_TYPE_COOKIES: + return l10n_util::GetStringUTF8(IDS_COOKIE_EXCEPTION_TITLE); + case CONTENT_SETTINGS_TYPE_IMAGES: + return l10n_util::GetStringUTF8(IDS_IMAGES_EXCEPTION_TITLE); + case CONTENT_SETTINGS_TYPE_JAVASCRIPT: + return l10n_util::GetStringUTF8(IDS_JS_EXCEPTION_TITLE); + case CONTENT_SETTINGS_TYPE_PLUGINS: + return l10n_util::GetStringUTF8(IDS_PLUGINS_EXCEPTION_TITLE); + case CONTENT_SETTINGS_TYPE_POPUPS: + return l10n_util::GetStringUTF8(IDS_POPUP_EXCEPTION_TITLE); + default: + NOTREACHED(); + } + return std::string(); +} + +// static +void ContentExceptionsWindowGtk::OnResponse( + GtkDialog* dialog, + int response_id, + ContentExceptionsWindowGtk* window) { + if (response_id == RESPONSE_ADD) { + window->Add(); + } else if (response_id == RESPONSE_EDIT) { + window->Edit(); + } else if (response_id == RESPONSE_REMOVE) { + window->Remove(); + } else if (response_id == RESPONSE_REMOVE_ALL) { + window->RemoveAll(); + } else { + gtk_widget_destroy(window->dialog_); + } +} + +// static +void ContentExceptionsWindowGtk::OnWindowDestroy( + GtkWidget* widget, + ContentExceptionsWindowGtk* window) { + instances[window->model_->content_type()] = NULL; + MessageLoop::current()->DeleteSoon(FROM_HERE, window); +} + +// static +void ContentExceptionsWindowGtk::OnSelectionChanged( + GtkTreeSelection *selection, + ContentExceptionsWindowGtk* languages_page) { + languages_page->UpdateButtonState(); +} diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.h b/chrome/browser/gtk/options/content_exceptions_window_gtk.h new file mode 100644 index 0000000..d2dae62 --- /dev/null +++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.h @@ -0,0 +1,101 @@ +// 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_GTK_OPTIONS_CONTENT_EXCEPTIONS_WINDOW_GTK_H_ +#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTIONS_WINDOW_GTK_H_ + +#include <gtk/gtk.h> + +#include <string> + +#include "base/scoped_ptr.h" +#include "chrome/browser/content_exceptions_table_model.h" +#include "chrome/browser/gtk/options/content_exception_editor.h" +#include "chrome/common/content_settings.h" +#include "chrome/common/content_settings_types.h" +#include "chrome/common/gtk_tree.h" + +class HostContentSettingsMap; + +// Dialog that lists each of the exceptions to the current content policy, and +// has options for adding/editing/removing entries. Modal to parrent. +class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate, + public ContentExceptionEditor::Delegate { + public: + static void ShowExceptionsWindow(GtkWindow* window, + HostContentSettingsMap* map, + ContentSettingsType content_type); + + ~ContentExceptionsWindowGtk(); + + // gtk_tree::TableAdapter::Delegate implementation: + virtual void SetColumnValues(int row, GtkTreeIter* iter); + + // ContentExceptionEditor::Delegate implementation: + virtual void AcceptExceptionEdit(const std::string& host, + ContentSetting setting, + int index, + bool is_new); + + private: + // Column ids for |list_store_|. + enum { + COL_HOSTNAME, + COL_ACTION, + COL_COUNT + }; + + ContentExceptionsWindowGtk(GtkWindow* parent, + HostContentSettingsMap* map, + ContentSettingsType type); + + // Updates which buttons are enabled. + void UpdateButtonState(); + + // Callbacks for the buttons. + void Add(); + void Edit(); + void Remove(); + void RemoveAll(); + + // Returns the title of the window (changes based on what ContentSettingsType + // was set to in the constructor). + std::string GetWindowTitle() const; + + // GTK Callbacks + static void OnResponse(GtkDialog* dialog, + int response_id, + ContentExceptionsWindowGtk* window); + static void OnWindowDestroy(GtkWidget* widget, + ContentExceptionsWindowGtk* window); + static void OnSelectionChanged(GtkTreeSelection *selection, + ContentExceptionsWindowGtk* languages_page); + + // The list presented in |treeview_|; a gobject instead of a C++ object. + GtkListStore* list_store_; + + // The C++, views-ish, cross-platform model class that actually contains the + // gold standard data. + scoped_ptr<ContentExceptionsTableModel> model_; + + // The adapter that ferries data back and forth between |model_| and + // |list_store_| whenever either of them change. + scoped_ptr<gtk_tree::TableAdapter> model_adapter_; + + // The exception window. + GtkWidget* dialog_; + + // The treeview that presents the site/action pairs. + GtkWidget* treeview_; + + // The current user selection from |treeview_|. + GtkTreeSelection* treeview_selection_; + + // Buttons. + GtkWidget* edit_button_; + GtkWidget* remove_button_; + GtkWidget* remove_all_button_; +}; + +#endif // CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTIONS_WINDOW_GTK_H_ diff --git a/chrome/browser/gtk/options/content_filter_page_gtk.cc b/chrome/browser/gtk/options/content_filter_page_gtk.cc index 5bab461..b575325 100644 --- a/chrome/browser/gtk/options/content_filter_page_gtk.cc +++ b/chrome/browser/gtk/options/content_filter_page_gtk.cc @@ -7,6 +7,7 @@ #include "app/l10n_util.h" #include "chrome/browser/host_content_settings_map.h" #include "chrome/browser/profile.h" +#include "chrome/browser/gtk/options/content_exceptions_window_gtk.h" #include "chrome/browser/gtk/options/options_layout_gtk.h" #include "chrome/common/gtk_util.h" #include "chrome/common/pref_names.h" @@ -88,8 +89,6 @@ GtkWidget* ContentFilterPageGtk::InitGroup() { GtkWidget* exceptions_button = gtk_button_new_with_label( l10n_util::GetStringUTF8(IDS_COOKIES_EXCEPTIONS_BUTTON).c_str()); - // TODO(erg): Disable the exceptions button until that is implemented. - gtk_widget_set_sensitive(exceptions_button, FALSE); g_signal_connect(G_OBJECT(exceptions_button), "clicked", G_CALLBACK(OnExceptionsClicked), this); @@ -117,5 +116,9 @@ void ContentFilterPageGtk::OnAllowToggled( void ContentFilterPageGtk::OnExceptionsClicked( GtkWidget* button, ContentFilterPageGtk* content_page) { - // TODO(erg): Implement a GTK equivalent of ExceptionsView. + HostContentSettingsMap* settings_map = + content_page->profile()->GetHostContentSettingsMap(); + ContentExceptionsWindowGtk::ShowExceptionsWindow( + GTK_WINDOW(gtk_widget_get_toplevel(button)), + settings_map, content_page->content_type_); } diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc index a1b4108..97ce956 100644 --- a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc +++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc @@ -9,6 +9,7 @@ #include "chrome/browser/browsing_data_local_storage_helper.h" #include "chrome/browser/gtk/browser_window_gtk.h" #include "chrome/browser/gtk/gtk_chrome_link_button.h" +#include "chrome/browser/gtk/options/content_exceptions_window_gtk.h" #include "chrome/browser/gtk/options/cookies_view.h" #include "chrome/browser/gtk/options/options_layout_gtk.h" #include "chrome/browser/host_content_settings_map.h" @@ -107,8 +108,6 @@ GtkWidget* CookieFilterPageGtk::InitCookieStoringGroup() { // Exception button. GtkWidget* exceptions_button = gtk_button_new_with_label( l10n_util::GetStringUTF8(IDS_COOKIES_EXCEPTIONS_BUTTON).c_str()); - // TODO(erg): Disable the exceptions button until that is implemented. - gtk_widget_set_sensitive(exceptions_button, FALSE); g_signal_connect(G_OBJECT(exceptions_button), "clicked", G_CALLBACK(OnExceptionsClicked), this); gtk_box_pack_start(GTK_BOX(vbox), WrapInHBox(exceptions_button), @@ -171,9 +170,13 @@ void CookieFilterPageGtk::OnCookiesAllowToggled( } void CookieFilterPageGtk::OnExceptionsClicked( - GtkToggleButton* toggle_button, + GtkWidget* button, CookieFilterPageGtk* cookie_page) { - // TODO(erg): Implement the exceptions button. + HostContentSettingsMap* settings_map = + cookie_page->profile()->GetHostContentSettingsMap(); + ContentExceptionsWindowGtk::ShowExceptionsWindow( + GTK_WINDOW(gtk_widget_get_toplevel(button)), + settings_map, CONTENT_SETTINGS_TYPE_COOKIES); } void CookieFilterPageGtk::OnBlock3rdpartyToggled( diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.h b/chrome/browser/gtk/options/cookie_filter_page_gtk.h index 7d805ca..6c554c2 100644 --- a/chrome/browser/gtk/options/cookie_filter_page_gtk.h +++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.h @@ -34,7 +34,7 @@ class CookieFilterPageGtk : public OptionsPageBase { // GTK callbacks static void OnCookiesAllowToggled(GtkWidget* toggle_button, CookieFilterPageGtk* cookie_page); - static void OnExceptionsClicked(GtkToggleButton* toggle_button, + static void OnExceptionsClicked(GtkWidget* toggle_button, CookieFilterPageGtk* cookie_page); static void OnBlock3rdpartyToggled(GtkToggleButton* toggle_button, CookieFilterPageGtk* cookie_page); diff --git a/chrome/browser/gtk/options/languages_page_gtk.cc b/chrome/browser/gtk/options/languages_page_gtk.cc index 8ac6a3e..2f17c9c 100644 --- a/chrome/browser/gtk/options/languages_page_gtk.cc +++ b/chrome/browser/gtk/options/languages_page_gtk.cc @@ -374,16 +374,9 @@ void LanguagesPageGtk::OnAddButtonClicked(GtkButton* button, // static void LanguagesPageGtk::OnRemoveButtonClicked(GtkButton* button, LanguagesPageGtk* languages_page) { - GList* list = gtk_tree_selection_get_selected_rows( - languages_page->language_order_selection_, NULL); std::set<int> selected_rows; - GList* node; - for (node = list; node != NULL; node = node->next) { - selected_rows.insert( - gtk_tree::GetRowNumForPath(static_cast<GtkTreePath*>(node->data))); - } - g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); - g_list_free(list); + gtk_tree::GetSelectedIndicies(languages_page->language_order_selection_, + &selected_rows); int selected_row = 0; for (std::set<int>::reverse_iterator selected = selected_rows.rbegin(); diff --git a/chrome/browser/views/options/exception_editor_view.cc b/chrome/browser/views/options/exception_editor_view.cc index 63265781..32a772b 100644 --- a/chrome/browser/views/options/exception_editor_view.cc +++ b/chrome/browser/views/options/exception_editor_view.cc @@ -5,8 +5,8 @@ #include "chrome/browser/views/options/exception_editor_view.h" #include "app/l10n_util.h" +#include "chrome/browser/content_exceptions_table_model.h" #include "chrome/browser/host_content_settings_map.h" -#include "chrome/browser/views/options/content_exceptions_table_model.h" #include "googleurl/src/url_canon.h" #include "googleurl/src/url_parse.h" #include "grit/generated_resources.h" diff --git a/chrome/browser/views/options/exceptions_view.h b/chrome/browser/views/options/exceptions_view.h index ca3b110..bc33564 100644 --- a/chrome/browser/views/options/exceptions_view.h +++ b/chrome/browser/views/options/exceptions_view.h @@ -7,7 +7,7 @@ #include <string> -#include "chrome/browser/views/options/content_exceptions_table_model.h" +#include "chrome/browser/content_exceptions_table_model.h" #include "chrome/browser/views/options/exception_editor_view.h" #include "chrome/common/content_settings.h" #include "chrome/common/content_settings_types.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index aafafd3..1cecec6 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -688,6 +688,8 @@ 'browser/cocoa/window_size_autosaver.mm', 'browser/command_updater.cc', 'browser/command_updater.h', + 'browser/content_exceptions_table_model.cc', + 'browser/content_exceptions_table_model.h', 'browser/cookie_modal_dialog.cc', 'browser/cookie_modal_dialog.h', 'browser/cookie_modal_dialog_views.cc', @@ -1100,6 +1102,10 @@ 'browser/gtk/options/advanced_contents_gtk.h', 'browser/gtk/options/advanced_page_gtk.cc', 'browser/gtk/options/advanced_page_gtk.h', + 'browser/gtk/options/content_exception_editor.cc', + 'browser/gtk/options/content_exception_editor.h', + 'browser/gtk/options/content_exceptions_window_gtk.cc', + 'browser/gtk/options/content_exceptions_window_gtk.h', 'browser/gtk/options/content_filter_page_gtk.cc', 'browser/gtk/options/content_filter_page_gtk.h', 'browser/gtk/options/content_page_gtk.cc', @@ -2018,8 +2024,6 @@ 'browser/views/options/advanced_contents_view.h', 'browser/views/options/advanced_page_view.cc', 'browser/views/options/advanced_page_view.h', - 'browser/views/options/content_exceptions_table_model.cc', - 'browser/views/options/content_exceptions_table_model.h', 'browser/views/options/content_page_view.cc', 'browser/views/options/content_page_view.h', 'browser/views/options/content_filter_page_view.cc', diff --git a/chrome/common/gtk_tree.cc b/chrome/common/gtk_tree.cc index 625c248..a1ff19f 100644 --- a/chrome/common/gtk_tree.cc +++ b/chrome/common/gtk_tree.cc @@ -65,6 +65,18 @@ bool RemoveRecursively(GtkTreeStore* tree_store, GtkTreeIter* iter) { return gtk_tree_store_remove(tree_store, iter); } +void GetSelectedIndicies(GtkTreeSelection* selection, std::set<int>* out) { + GList* list = gtk_tree_selection_get_selected_rows( + selection, NULL); + GList* node; + for (node = list; node != NULL; node = node->next) { + out->insert( + gtk_tree::GetRowNumForPath(static_cast<GtkTreePath*>(node->data))); + } + g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); + g_list_free(list); +} + //////////////////////////////////////////////////////////////////////////////// // TableAdapter diff --git a/chrome/common/gtk_tree.h b/chrome/common/gtk_tree.h index 2b2f893..4c2f38e 100644 --- a/chrome/common/gtk_tree.h +++ b/chrome/common/gtk_tree.h @@ -6,6 +6,7 @@ #define CHROME_COMMON_GTK_TREE_H_ #include <gtk/gtk.h> +#include <set> #include <vector> #include "app/table_model_observer.h" @@ -36,6 +37,9 @@ void SelectAndFocusRowNum(int row, GtkTreeView* tree_view); // valid. bool RemoveRecursively(GtkTreeStore* tree_store, GtkTreeIter* iter); +// Writes all the indexes of selected rows into |out|. +void GetSelectedIndicies(GtkTreeSelection* selection, std::set<int>* out); + // A helper class for populating a GtkListStore from a TableModel. class TableAdapter : public TableModelObserver { public: |