// 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 #include #include "app/l10n_util.h" #include "chrome/browser/views/options/content_exceptions_table_view.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "gfx/rect.h" #include "views/controls/button/native_button.h" #include "views/controls/label.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 ExceptionsView* instances[CONTENT_SETTINGS_NUM_TYPES] = { NULL }; // static void ExceptionsView::ShowExceptionsWindow( gfx::NativeWindow parent, HostContentSettingsMap* map, HostContentSettingsMap* off_the_record_map, ContentSettingsType content_type) { if (!instances[content_type]) { instances[content_type] = new ExceptionsView(map, off_the_record_map, content_type); views::Window::CreateChromeWindow(parent, gfx::Rect(), instances[content_type]); } // This will show invisible windows and bring visible windows to the front. instances[content_type]->window()->Show(); } ExceptionsView::~ExceptionsView() { instances[model_.content_type()] = NULL; 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 HostContentSettingsMap::Pattern& pattern, ContentSetting setting, bool is_off_the_record, int index, bool is_new) { DCHECK(!is_off_the_record || allow_off_the_record_); if (!is_new) model_.RemoveException(index); model_.AddException(pattern, setting, is_off_the_record); int new_index = model_.IndexOfExceptionByPattern(pattern, is_off_the_record); DCHECK(new_index != -1); table_->Select(new_index); } ExceptionsView::ExceptionsView(HostContentSettingsMap* map, HostContentSettingsMap* off_the_record_map, ContentSettingsType type) : model_(map, off_the_record_map, type), allow_off_the_record_(off_the_record_map != NULL), 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 columns; columns.push_back( TableColumn(IDS_EXCEPTIONS_PATTERN_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 ContentExceptionsTableView(&model_, columns); views::TableView::SortDescriptors sort; sort.push_back( views::TableView::SortDescriptor(IDS_EXCEPTIONS_PATTERN_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); if (allow_off_the_record_) { views::Label* label = new views::Label(l10n_util::GetString( IDS_EXCEPTIONS_OTR_IN_ITALICS)); label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); layout->StartRow(0, single_column_layout_id); layout->AddView(label, 1, 1, GridLayout::LEADING, GridLayout::CENTER); 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_, allow_off_the_record_, -1, HostContentSettingsMap::Pattern(), CONTENT_SETTING_BLOCK, false); view->Show(window()->GetNativeWindow()); UpdateButtonState(); } void ExceptionsView::Edit() { DCHECK(table_->FirstSelectedRow() != -1); int index = table_->FirstSelectedRow(); const HostContentSettingsMap::PatternSettingPair& entry = model_.entry_at(index); ExceptionEditorView* view = new ExceptionEditorView(this, &model_, allow_off_the_record_, index, entry.first, entry.second, model_.entry_is_off_the_record(index)); view->Show(window()->GetNativeWindow()); } void ExceptionsView::Remove() { std::vector 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::reverse_iterator i = indices.rbegin(); i != indices.rend(); ++i) { model_.RemoveException(*i); } UpdateButtonState(); } void ExceptionsView::RemoveAll() { model_.RemoveAll(); UpdateButtonState(); }