diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 17 | ||||
-rw-r--r-- | chrome/app/resources/locale_settings.grd | 9 | ||||
-rw-r--r-- | chrome/browser/views/options/content_exceptions_table_model.cc | 89 | ||||
-rw-r--r-- | chrome/browser/views/options/content_exceptions_table_model.h | 54 | ||||
-rw-r--r-- | chrome/browser/views/options/content_filter_page_view.cc | 5 | ||||
-rw-r--r-- | chrome/browser/views/options/cookie_filter_page_view.cc | 5 | ||||
-rw-r--r-- | chrome/browser/views/options/exception_editor_view.cc | 183 | ||||
-rw-r--r-- | chrome/browser/views/options/exception_editor_view.h | 114 | ||||
-rw-r--r-- | chrome/browser/views/options/exceptions_view.cc | 245 | ||||
-rw-r--r-- | chrome/browser/views/options/exceptions_view.h | 108 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 6 |
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&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', |