summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd17
-rw-r--r--chrome/app/resources/locale_settings.grd9
-rw-r--r--chrome/browser/views/options/content_exceptions_table_model.cc89
-rw-r--r--chrome/browser/views/options/content_exceptions_table_model.h54
-rw-r--r--chrome/browser/views/options/content_filter_page_view.cc5
-rw-r--r--chrome/browser/views/options/cookie_filter_page_view.cc5
-rw-r--r--chrome/browser/views/options/exception_editor_view.cc183
-rw-r--r--chrome/browser/views/options/exception_editor_view.h114
-rw-r--r--chrome/browser/views/options/exceptions_view.cc245
-rw-r--r--chrome/browser/views/options/exceptions_view.h108
-rwxr-xr-xchrome/chrome_browser.gypi6
11 files changed, 833 insertions, 2 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 274aecd..62490f5 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3735,6 +3735,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_EXCEPTIONS_ADD_BUTTON" desc="A button in the cookie/image/javascript/plugins exceptions dialog for adding new exception rules.">
Add...
</message>
+ <message name="IDS_EXCEPTIONS_EDIT_BUTTON" desc="A button in the cookie/image/javascript/plugins exceptions dialog for editing an exception.">
+ Edit...
+ </message>
<message name="IDS_EXCEPTIONS_REMOVE_BUTTON" desc="A button in exception dialogs for removing individual exception rules.">
Remove
</message>
@@ -3754,6 +3757,20 @@ Keep your key file in a safe place. You will need it to create new versions of y
example.com
</message>
+ <!-- Cookie/Images/JavaScript/Plugins exception editor dialogs -->
+ <message name="IDS_EXCEPTION_EDITOR_TITLE" desc="Title for exception editor">
+ Edit Exception
+ </message>
+ <message name="IDS_EXCEPTION_EDITOR_NEW_TITLE" desc="Title for exception editor">
+ New Exception
+ </message>
+ <message name="IDS_EXCEPTION_EDITOR_HOST_TITLE" desc="Title of the host field in the exception editor">
+ Host:
+ </message>
+ <message name="IDS_EXCEPTION_EDITOR_ACTION_TITLE" desc="Title of the action combobox in the exception editor">
+ Action:
+ </message>
+
<!-- Cookie alert dialog -->
<message name="IDS_COOKIE_ALERT_TITLE" desc="Format string for cookie alert dialog title">
Cookie from <ph name="HOST">$1<ex>www.google.com</ex></ph>
diff --git a/chrome/app/resources/locale_settings.grd b/chrome/app/resources/locale_settings.grd
index 2c595ff..a2f934d 100644
--- a/chrome/app/resources/locale_settings.grd
+++ b/chrome/app/resources/locale_settings.grd
@@ -593,6 +593,15 @@
<message name="IDS_ABOUT_GOOGLE_TRANSLATE_URL" translateable="false">
http://www.google.com/support/chrome/bin/answer.py?answer=173424&amp;hl=[GRITLANGCODE]
</message>
+
+ <!-- The width and height of the Content Settings Exceptions dialog box in -->
+ <!-- characters and lines (See above). -->
+ <message name="IDS_CONTENT_EXCEPTION_DIALOG_WIDTH_CHARS" use_name_for_id="true">
+ 86
+ </message>
+ <message name="IDS_CONTENT_EXCEPTION_DIALOG_HEIGHT_LINES" use_name_for_id="true">
+ 16
+ </message>
</messages>
</release>
</grit>
diff --git a/chrome/browser/views/options/content_exceptions_table_model.cc b/chrome/browser/views/options/content_exceptions_table_model.cc
new file mode 100644
index 0000000..a733747
--- /dev/null
+++ b/chrome/browser/views/options/content_exceptions_table_model.cc
@@ -0,0 +1,89 @@
+// 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/content_exceptions_table_model.h"
+
+#include "app/l10n_util.h"
+#include "app/table_model_observer.h"
+#include "chrome/browser/host_content_settings_map.h"
+#include "grit/generated_resources.h"
+
+ContentExceptionsTableModel::ContentExceptionsTableModel(
+ HostContentSettingsMap* map,
+ ContentSettingsType type)
+ : map_(map),
+ content_type_(type),
+ observer_(NULL) {
+ // Load the contents.
+ map->GetSettingsForOneType(type, &entries_);
+}
+
+void ContentExceptionsTableModel::AddException(const std::string& host,
+ ContentSetting setting) {
+ entries_.push_back(HostContentSettingsMap::HostSettingPair(host, setting));
+ map_->SetContentSetting(host, content_type_, setting);
+ if (observer_)
+ observer_->OnItemsAdded(RowCount() - 1, 1);
+}
+
+void ContentExceptionsTableModel::RemoveException(int row) {
+ const HostContentSettingsMap::HostSettingPair& pair = entries_[row];
+ map_->SetContentSetting(pair.first, content_type_, CONTENT_SETTING_DEFAULT);
+ entries_.erase(entries_.begin() + row);
+ if (observer_)
+ observer_->OnItemsRemoved(row, 1);
+}
+
+void ContentExceptionsTableModel::RemoveAll() {
+ int old_row_count = RowCount();
+ entries_.clear();
+ map_->ClearSettingsForOneType(content_type_);
+ observer_->OnItemsRemoved(0, old_row_count);
+}
+
+int ContentExceptionsTableModel::IndexOfExceptionByHost(
+ const std::string& host) {
+ // This is called on every key type in the editor. Move to a map if we end up
+ // with lots of exceptions.
+ for (size_t i = 0; i < entries_.size(); ++i) {
+ if (entries_[i].first == host)
+ return static_cast<int>(i);
+ }
+ return -1;
+}
+
+int ContentExceptionsTableModel::RowCount() {
+ return static_cast<int>(entries_.size());
+}
+
+std::wstring ContentExceptionsTableModel::GetText(int row, int column_id) {
+ HostContentSettingsMap::HostSettingPair entry = entries_[row];
+
+ switch (column_id) {
+ case IDS_EXCEPTIONS_HOSTNAME_HEADER:
+ return UTF8ToWide(entry.first);
+
+ case IDS_EXCEPTIONS_ACTION_HEADER:
+ switch (entry.second) {
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_BLOCK_BUTTON);
+ case CONTENT_SETTING_ASK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ASK_BUTTON);
+ default:
+ NOTREACHED();
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ return std::wstring();
+}
+
+void ContentExceptionsTableModel::SetObserver(TableModelObserver* observer) {
+ observer_ = observer;
+}
diff --git a/chrome/browser/views/options/content_exceptions_table_model.h b/chrome/browser/views/options/content_exceptions_table_model.h
new file mode 100644
index 0000000..8016eb0
--- /dev/null
+++ b/chrome/browser/views/options/content_exceptions_table_model.h
@@ -0,0 +1,54 @@
+// 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_CONTENT_EXCEPTIONS_TABLE_MODEL_H_
+#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_MODEL_H_
+
+#include <string>
+
+#include "app/table_model.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/content_settings_types.h"
+#include "chrome/browser/host_content_settings_map.h"
+
+class ContentExceptionsTableModel : public TableModel {
+ public:
+ ContentExceptionsTableModel(HostContentSettingsMap* map,
+ ContentSettingsType content_type);
+
+ HostContentSettingsMap* map() const { return map_; }
+ ContentSettingsType content_type() const { return content_type_; }
+
+ const HostContentSettingsMap::HostSettingPair& entry_at(int index) {
+ return entries_[index];
+ }
+
+ // Adds a new exception on the map and table model.
+ void AddException(const std::string& host, ContentSetting setting);
+
+ // Removes the exception at the specified index from both the map and model.
+ void RemoveException(int row);
+
+ // Removes all the exceptions from both the map and model.
+ void RemoveAll();
+
+ // Returns the index of the specified exception given a host, or -1 if there
+ // is no exception for the specified host.
+ int IndexOfExceptionByHost(const std::string& host);
+
+ // TableModel overrides:
+ virtual int RowCount();
+ virtual std::wstring GetText(int row, int column_id);
+ virtual void SetObserver(TableModelObserver* observer);
+
+ private:
+ HostContentSettingsMap* map_;
+ ContentSettingsType content_type_;
+ HostContentSettingsMap::SettingsForOneType entries_;
+ TableModelObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentExceptionsTableModel);
+};
+
+#endif // CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_MODEL_H_
diff --git a/chrome/browser/views/options/content_filter_page_view.cc b/chrome/browser/views/options/content_filter_page_view.cc
index 4be6291..badd057 100644
--- a/chrome/browser/views/options/content_filter_page_view.cc
+++ b/chrome/browser/views/options/content_filter_page_view.cc
@@ -10,6 +10,7 @@
#include "app/resource_bundle.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/views/options/exceptions_view.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -128,7 +129,9 @@ void ContentFilterPageView::InitControlLayout() {
void ContentFilterPageView::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == exceptions_button_) {
- // TODO(pkasting): Show exceptions dialog
+ ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
+ profile()->GetHostContentSettingsMap(),
+ content_type_);
return;
}
diff --git a/chrome/browser/views/options/cookie_filter_page_view.cc b/chrome/browser/views/options/cookie_filter_page_view.cc
index 7abe096..a7ec450 100644
--- a/chrome/browser/views/options/cookie_filter_page_view.cc
+++ b/chrome/browser/views/options/cookie_filter_page_view.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/options/cookies_view.h"
+#include "chrome/browser/views/options/exceptions_view.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -166,7 +167,9 @@ void CookieFilterPageView::ButtonPressed(
settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
CONTENT_SETTING_BLOCK);
} else if (sender == exceptions_button_) {
- // TODO(pkasting): Show exceptions dialog.
+ ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
+ settings_map,
+ CONTENT_SETTINGS_TYPE_COOKIES);
} else if (sender == block_3rdparty_check_) {
settings_map->SetBlockThirdPartyCookies(block_3rdparty_check_->checked());
} else if (sender == clear_on_close_check_) {
diff --git a/chrome/browser/views/options/exception_editor_view.cc b/chrome/browser/views/options/exception_editor_view.cc
new file mode 100644
index 0000000..63265781
--- /dev/null
+++ b/chrome/browser/views/options/exception_editor_view.cc
@@ -0,0 +1,183 @@
+// 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/exception_editor_view.h"
+
+#include "app/l10n_util.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"
+#include "net/base/net_util.h"
+#include "views/grid_layout.h"
+#include "views/controls/label.h"
+#include "views/standard_layout.h"
+#include "views/window/window.h"
+
+// 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.
+static bool ValidHost(const std::string& host) {
+ if (host.empty())
+ return false;
+
+ url_canon::CanonHostInfo host_info;
+ return !net::CanonicalizeHost(host, &host_info).empty();
+}
+
+int ExceptionEditorView::ActionComboboxModel::GetItemCount() {
+ return show_ask_ ? arraysize(kAskSettings) : arraysize(kNoAskSettings);
+}
+
+std::wstring ExceptionEditorView::ActionComboboxModel::GetItemAt(int index) {
+ switch (setting_for_index(index)) {
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_BLOCK_BUTTON);
+ case CONTENT_SETTING_ASK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ASK_BUTTON);
+ default:
+ NOTREACHED();
+ }
+ return std::wstring();
+}
+
+ContentSetting ExceptionEditorView::ActionComboboxModel::setting_for_index(
+ int index) {
+ return show_ask_ ? kAskSettings[index] : kNoAskSettings[index];
+}
+
+int ExceptionEditorView::ActionComboboxModel::index_for_setting(
+ ContentSetting setting) {
+ for (int i = 0; i < GetItemCount(); ++i)
+ if (setting_for_index(i) == setting)
+ return i;
+ NOTREACHED();
+ return 0;
+}
+
+ExceptionEditorView::ExceptionEditorView(Delegate* delegate,
+ ContentExceptionsTableModel* model,
+ int index,
+ const std::string& host,
+ ContentSetting setting)
+ : delegate_(delegate),
+ model_(model),
+ cb_model_(model->content_type() == CONTENT_SETTINGS_TYPE_COOKIES),
+ index_(index),
+ host_(host),
+ setting_(setting) {
+ Init();
+}
+
+void ExceptionEditorView::Show(gfx::NativeWindow parent) {
+ views::Window* window =
+ views::Window::CreateChromeWindow(parent, gfx::Rect(), this);
+ window->Show();
+ GetDialogClientView()->UpdateDialogButtons();
+ host_tf_->SelectAll();
+ host_tf_->RequestFocus();
+}
+
+bool ExceptionEditorView::IsModal() const {
+ return true;
+}
+
+std::wstring ExceptionEditorView::GetWindowTitle() const {
+ return is_new() ? l10n_util::GetString(IDS_EXCEPTION_EDITOR_NEW_TITLE) :
+ l10n_util::GetString(IDS_EXCEPTION_EDITOR_TITLE);
+}
+
+bool ExceptionEditorView::IsDialogButtonEnabled(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
+ std::string new_host = UTF16ToUTF8(host_tf_->text());
+ if (is_new()) {
+ return ValidHost(new_host) &&
+ (model_->IndexOfExceptionByHost(new_host) == -1);
+ }
+ return !new_host.empty() &&
+ (host_ == new_host ||
+ (ValidHost(new_host) &&
+ model_->IndexOfExceptionByHost(new_host) == -1));
+ }
+ return true;
+}
+
+bool ExceptionEditorView::Cancel() {
+ return true;
+}
+
+bool ExceptionEditorView::Accept() {
+ std::string new_host = UTF16ToUTF8(host_tf_->text());
+ ContentSetting setting =
+ cb_model_.setting_for_index(action_cb_->selected_item());
+ delegate_->AcceptExceptionEdit(new_host, setting, index_, is_new());
+ return true;
+}
+
+views::View* ExceptionEditorView::GetContentsView() {
+ return this;
+}
+
+void ExceptionEditorView::ContentsChanged(views::Textfield* sender,
+ const std::wstring& new_contents) {
+ GetDialogClientView()->UpdateDialogButtons();
+}
+
+bool ExceptionEditorView::HandleKeystroke(
+ views::Textfield* sender,
+ const views::Textfield::Keystroke& key) {
+ return false;
+}
+
+void ExceptionEditorView::Init() {
+ using views::GridLayout;
+
+ host_tf_ = new views::Textfield();
+ host_tf_->SetText(UTF8ToUTF16(host_));
+ host_tf_->SetController(this);
+
+ action_cb_ = new views::Combobox(&cb_model_);
+ if (!is_new())
+ action_cb_->SetSelectedItem(cb_model_.index_for_setting(setting_));
+
+ GridLayout* layout = CreatePanelGridLayout(this);
+ SetLayoutManager(layout);
+
+ // For the Textfields.
+ views::ColumnSet* column_set = layout->AddColumnSet(1);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+
+ // Add the contents.
+ layout->StartRow(0, 1);
+ layout->AddView(CreateLabel(IDS_EXCEPTION_EDITOR_HOST_TITLE));
+ layout->AddView(host_tf_);
+
+ layout->StartRowWithPadding(0, 1, 0, kRelatedControlVerticalSpacing);
+ layout->AddView(CreateLabel(IDS_EXCEPTION_EDITOR_ACTION_TITLE));
+ layout->AddView(action_cb_);
+}
+
+views::Label* ExceptionEditorView::CreateLabel(int message_id) {
+ views::Label* label = new views::Label(l10n_util::GetString(message_id));
+ label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ return label;
+}
diff --git a/chrome/browser/views/options/exception_editor_view.h b/chrome/browser/views/options/exception_editor_view.h
new file mode 100644
index 0000000..6a86f79
--- /dev/null
+++ b/chrome/browser/views/options/exception_editor_view.h
@@ -0,0 +1,114 @@
+// 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_EXCEPTION_EDITOR_VIEW_H_
+#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTION_EDITOR_VIEW_H_
+
+#include <string>
+
+#include "app/combobox_model.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/content_settings_types.h"
+#include "views/window/dialog_delegate.h"
+#include "views/controls/combobox/combobox.h"
+#include "views/controls/textfield/textfield.h"
+
+namespace views {
+class Label;
+}
+
+class ContentExceptionsTableModel;
+
+// ExceptionEditorView is responsible for showing a dialog that allows the user
+// to create or edit a single content exception. If the user clicks ok the
+// delegate is notified and completes the edit.
+//
+// To use an ExceptionEditorView create one and invoke Show on it.
+// ExceptionEditorView is deleted when the dialog closes.
+class ExceptionEditorView : public views::View,
+ public views::Textfield::Controller,
+ public views::DialogDelegate {
+ 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() {}
+ };
+
+ // Creates a new ExceptionEditorView with the supplied args. |index| is the
+ // index into the ContentExceptionsTableModel of the exception. This is not
+ // used by ExceptionEditorView but instead passed to the delegate.
+ ExceptionEditorView(Delegate* delegate,
+ ContentExceptionsTableModel* model,
+ int index,
+ const std::string& host,
+ ContentSetting setting);
+ virtual ~ExceptionEditorView() {}
+
+ void Show(gfx::NativeWindow parent);
+
+ // views::DialogDelegate overrides.
+ virtual bool IsModal() const;
+ virtual std::wstring GetWindowTitle() const;
+ virtual bool IsDialogButtonEnabled(
+ MessageBoxFlags::DialogButton button) const;
+ virtual bool Cancel();
+ virtual bool Accept();
+ virtual views::View* GetContentsView();
+
+ // views::Textfield::Controller overrides. Updates whether the user can
+ // accept the dialog as well as updating image views showing whether value is
+ // valid.
+ virtual void ContentsChanged(views::Textfield* sender,
+ const std::wstring& new_contents);
+ virtual bool HandleKeystroke(views::Textfield* sender,
+ const views::Textfield::Keystroke& key);
+
+ private:
+ // Model for the combobox.
+ class ActionComboboxModel : public ComboboxModel {
+ public:
+ explicit ActionComboboxModel(bool show_ask) : show_ask_(show_ask) {}
+
+ virtual int GetItemCount();
+ virtual std::wstring GetItemAt(int index);
+
+ ContentSetting setting_for_index(int index);
+ int index_for_setting(ContentSetting);
+
+ private:
+ const bool show_ask_;
+
+ DISALLOW_COPY_AND_ASSIGN(ActionComboboxModel);
+ };
+
+ void Init();
+
+ views::Label* CreateLabel(int message_id);
+
+ // Returns true if we're adding a new item.
+ bool is_new() const { return index_ == -1; }
+
+ Delegate* delegate_;
+ ContentExceptionsTableModel* model_;
+ ActionComboboxModel cb_model_;
+
+ // Index of the item being edited. If -1, indices this is a new entry.
+ const int index_;
+ const std::string host_;
+ const ContentSetting setting_;
+
+ views::Textfield* host_tf_;
+ views::Combobox* action_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExceptionEditorView);
+};
+
+#endif // CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTION_EDITOR_VIEW_H_
diff --git a/chrome/browser/views/options/exceptions_view.cc b/chrome/browser/views/options/exceptions_view.cc
new file mode 100644
index 0000000..a49df3e
--- /dev/null
+++ b/chrome/browser/views/options/exceptions_view.cc
@@ -0,0 +1,245 @@
+// 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/exceptions_view.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "base/gfx/rect.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.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
+void ExceptionsView::ShowExceptionsWindow(gfx::NativeWindow parent,
+ HostContentSettingsMap* map,
+ ContentSettingsType type) {
+ views::Window::CreateChromeWindow(
+ parent, gfx::Rect(), new ExceptionsView(map, type))->Show();
+}
+
+ExceptionsView::~ExceptionsView() {
+ table_->SetModel(NULL);
+}
+
+void ExceptionsView::OnSelectionChanged() {
+ UpdateButtonState();
+}
+
+void ExceptionsView::OnDoubleClick() {
+ if (table_->SelectedRowCount() == 1)
+ Edit();
+}
+
+void ExceptionsView::OnTableViewDelete(views::TableView* table_view) {
+ Remove();
+}
+
+void ExceptionsView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ switch (sender->tag()) {
+ case IDS_EXCEPTIONS_ADD_BUTTON:
+ Add();
+ break;
+ case IDS_EXCEPTIONS_EDIT_BUTTON:
+ Edit();
+ break;
+ case IDS_EXCEPTIONS_REMOVEALL_BUTTON:
+ RemoveAll();
+ break;
+ case IDS_EXCEPTIONS_REMOVE_BUTTON:
+ Remove();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void ExceptionsView::Layout() {
+ views::NativeButton* buttons[] = { add_button_, edit_button_,
+ 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 ExceptionsView::GetPreferredSize() {
+ return gfx::Size(views::Window::GetLocalizedContentsSize(
+ IDS_CONTENT_EXCEPTION_DIALOG_WIDTH_CHARS,
+ IDS_CONTENT_EXCEPTION_DIALOG_HEIGHT_LINES));
+}
+
+void ExceptionsView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && child == this)
+ Init();
+}
+
+std::wstring ExceptionsView::GetWindowTitle() const {
+ switch (model_.content_type()) {
+ case CONTENT_SETTINGS_TYPE_COOKIES:
+ return l10n_util::GetString(IDS_COOKIE_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_IMAGES:
+ return l10n_util::GetString(IDS_IMAGES_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
+ return l10n_util::GetString(IDS_JS_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_PLUGINS:
+ return l10n_util::GetString(IDS_PLUGINS_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_POPUPS:
+ return l10n_util::GetString(IDS_POPUP_EXCEPTION_TITLE);
+ default:
+ NOTREACHED();
+ }
+ return std::wstring();
+}
+
+void ExceptionsView::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);
+ table_->Select(new_index);
+}
+
+ExceptionsView::ExceptionsView(HostContentSettingsMap* map,
+ ContentSettingsType type)
+ : model_(map, type),
+ table_(NULL),
+ add_button_(NULL),
+ edit_button_(NULL),
+ remove_button_(NULL),
+ remove_all_button_(NULL) {
+}
+
+void ExceptionsView::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);
+
+ add_button_ = new views::NativeButton(
+ this, l10n_util::GetString(IDS_EXCEPTIONS_ADD_BUTTON));
+ add_button_->set_tag(IDS_EXCEPTIONS_ADD_BUTTON);
+ edit_button_ = new views::NativeButton(
+ this, l10n_util::GetString(IDS_EXCEPTIONS_EDIT_BUTTON));
+ edit_button_->set_tag(IDS_EXCEPTIONS_EDIT_BUTTON);
+ 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(add_button_);
+ parent->AddChildView(edit_button_);
+ 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();
+}
+
+void ExceptionsView::UpdateButtonState() {
+ int selected_row_count = table_->SelectedRowCount();
+ // TODO: 34177, support editing of more than one entry at a time.
+ edit_button_->SetEnabled(selected_row_count == 1);
+ remove_button_->SetEnabled(selected_row_count >= 1);
+ remove_all_button_->SetEnabled(model_.RowCount() > 0);
+}
+
+void ExceptionsView::Add() {
+ ExceptionEditorView* view =
+ new ExceptionEditorView(this, &model_, -1, std::string(),
+ CONTENT_SETTING_BLOCK);
+ view->Show(window()->GetNativeWindow());
+
+ UpdateButtonState();
+}
+
+void ExceptionsView::Edit() {
+ DCHECK(table_->FirstSelectedRow() != -1);
+ int index = table_->FirstSelectedRow();
+ const HostContentSettingsMap::HostSettingPair& entry =
+ model_.entry_at(index);
+ ExceptionEditorView* view =
+ new ExceptionEditorView(this, &model_, index, entry.first, entry.second);
+ view->Show(window()->GetNativeWindow());
+}
+
+void ExceptionsView::Remove() {
+ std::vector<int> indices;
+ for (views::TableView::iterator i = table_->SelectionBegin();
+ i != table_->SelectionEnd(); ++i) {
+ indices.push_back(*i);
+ }
+ std::sort(indices.begin(), indices.end());
+ for (std::vector<int>::reverse_iterator i = indices.rbegin();
+ i != indices.rend(); ++i) {
+ model_.RemoveException(*i);
+ }
+
+ UpdateButtonState();
+}
+
+void ExceptionsView::RemoveAll() {
+ model_.RemoveAll();
+
+ UpdateButtonState();
+}
diff --git a/chrome/browser/views/options/exceptions_view.h b/chrome/browser/views/options/exceptions_view.h
new file mode 100644
index 0000000..cedda01
--- /dev/null
+++ b/chrome/browser/views/options/exceptions_view.h
@@ -0,0 +1,108 @@
+// 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_EXCEPTIONS_VIEW_H_
+#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_VIEW_H_
+
+#include <string>
+
+#include "chrome/browser/views/options/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"
+#include "views/controls/button/button.h"
+#include "views/controls/table/table_view_observer.h"
+#include "views/window/dialog_delegate.h"
+
+class HostContentSettingsMap;
+
+namespace views {
+class NativeButton;
+class TableView;
+}
+
+// ExceptionsView is responsible for showing the user the set of content
+// exceptions for a specific type. The exceptions are shown in a table view
+// by way of a ContentExceptionsTableModel. The user can add/edit/remove
+// exceptions. Editing and creating new exceptions is done way of the
+// ExceptionEditorView.
+// Use the ShowExceptionsWindow method to create and show an ExceptionsView
+// for a specific type. ExceptionsView is deleted when the window closes.
+class ExceptionsView : public ExceptionEditorView::Delegate,
+ public views::View,
+ public views::ButtonListener,
+ public views::DialogDelegate,
+ public views::TableViewObserver {
+ public:
+ // Shows the Exceptions window.
+ static void ShowExceptionsWindow(gfx::NativeWindow parent,
+ HostContentSettingsMap* map,
+ ContentSettingsType type);
+
+ virtual ~ExceptionsView();
+
+ // TableViewObserver overrides:
+ virtual void OnSelectionChanged();
+ virtual void OnDoubleClick();
+ 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; }
+
+ // ExceptionEditorView::Delegate implementation.
+ virtual void AcceptExceptionEdit(const std::string& host,
+ ContentSetting setting,
+ int index,
+ bool is_new);
+
+ private:
+ ExceptionsView(HostContentSettingsMap* map, ContentSettingsType type);
+
+ void Init();
+
+ // Resets the enabled state of the buttons from the model.
+ void UpdateButtonState();
+
+ // Adds a new item.
+ void Add();
+
+ // Edits the selected item.
+ void Edit();
+
+ // Removes the selected item.
+ void Remove();
+
+ // Removes all.
+ void RemoveAll();
+
+ // The model displayed in the table.
+ ContentExceptionsTableModel model_;
+
+ views::TableView* table_;
+
+ views::NativeButton* add_button_;
+ views::NativeButton* edit_button_;
+ views::NativeButton* remove_button_;
+ views::NativeButton* remove_all_button_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExceptionsView);
+};
+
+#endif // CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_VIEW_H_
+
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 17de9ec..1e4d615 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1865,6 +1865,8 @@
'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',
@@ -1875,6 +1877,10 @@
'browser/views/options/cookie_filter_page_view.h',
'browser/views/options/cookies_view.cc',
'browser/views/options/cookies_view.h',
+ 'browser/views/options/exception_editor_view.cc',
+ 'browser/views/options/exception_editor_view.h',
+ 'browser/views/options/exceptions_view.cc',
+ 'browser/views/options/exceptions_view.h',
'browser/views/options/exceptions_page_view.cc',
'browser/views/options/exceptions_page_view.h',
'browser/views/options/fonts_languages_window_view.cc',