// Copyright (c) 2011 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/ui/views/collected_cookies_win.h" #include "chrome/browser/cookies_tree_model.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/collected_cookies_infobar_delegate.h" #include "chrome/browser/ui/views/cookie_info_view.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/common/notification_details.h" #include "content/common/notification_source.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_utils.h" #include "views/controls/button/native_button.h" #include "views/controls/image_view.h" #include "views/controls/label.h" #include "views/controls/separator.h" #include "views/controls/tabbed_pane/tabbed_pane.h" #include "views/layout/box_layout.h" #include "views/layout/grid_layout.h" #include "views/layout/layout_constants.h" #include "views/widget/root_view.h" #include "views/widget/widget_win.h" #include "views/window/window.h" namespace browser { // Declared in browser_dialogs.h so others don't have to depend on our header. void ShowCollectedCookiesDialog(gfx::NativeWindow parent_window, TabContents* tab_contents) { // Deletes itself on close. new CollectedCookiesWin(parent_window, tab_contents); } } // namespace browser namespace { // Spacing between the infobar frame and its contents. const int kInfobarVerticalPadding = 3; const int kInfobarHorizontalPadding = 8; // Width of the infobar frame. const int kInfobarBorderSize = 1; // Dimensions of the tree views. const int kTreeViewWidth = 400; const int kTreeViewHeight = 125; } // namespace // A custom view that conditionally displays an infobar. class InfobarView : public views::View { public: InfobarView() { content_ = new views::View; SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW); views::Border* border = views::Border::CreateSolidBorder( kInfobarBorderSize, border_color); content_->set_border(border); ResourceBundle& rb = ResourceBundle::GetSharedInstance(); info_image_ = new views::ImageView(); info_image_->SetImage(rb.GetBitmapNamed(IDR_INFO)); label_ = new views::Label(); } virtual ~InfobarView() {} // Update the visibility of the infobar. If |is_visible| is true, a rule for // |setting| on |domain_name| was created. void UpdateVisibility(bool is_visible, ContentSetting setting, const std::wstring& domain_name) { if (!is_visible) { SetVisible(false); return; } std::wstring label; switch (setting) { case CONTENT_SETTING_BLOCK: label = UTF16ToWide(l10n_util::GetStringFUTF16( IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, WideToUTF16(domain_name))); break; case CONTENT_SETTING_ALLOW: label = UTF16ToWide(l10n_util::GetStringFUTF16( IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, WideToUTF16(domain_name))); break; case CONTENT_SETTING_SESSION_ONLY: label = UTF16ToWide(l10n_util::GetStringFUTF16( IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, WideToUTF16(domain_name))); break; default: NOTREACHED(); } label_->SetText(label); content_->Layout(); SetVisible(true); } private: // Initialize contents and layout. void Init() { AddChildView(content_); content_->SetLayoutManager( new views::BoxLayout(views::BoxLayout::kHorizontal, kInfobarHorizontalPadding, kInfobarVerticalPadding, views::kRelatedControlSmallHorizontalSpacing)); content_->AddChildView(info_image_); content_->AddChildView(label_); UpdateVisibility(false, CONTENT_SETTING_BLOCK, std::wstring()); } // views::View overrides. virtual gfx::Size GetPreferredSize() { if (!IsVisible()) return gfx::Size(); // Add space around the banner. gfx::Size size(content_->GetPreferredSize()); size.Enlarge(0, 2 * views::kRelatedControlVerticalSpacing); return size; } virtual void Layout() { content_->SetBounds( 0, views::kRelatedControlVerticalSpacing, width(), height() - views::kRelatedControlVerticalSpacing); } virtual void ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child) { if (is_add && child == this) Init(); } // Holds the info icon image and text label and renders the border. views::View* content_; // Info icon image. views::ImageView* info_image_; // The label responsible for rendering the text. views::Label* label_; DISALLOW_COPY_AND_ASSIGN(InfobarView); }; /////////////////////////////////////////////////////////////////////////////// // CollectedCookiesWin, constructor and destructor: CollectedCookiesWin::CollectedCookiesWin(gfx::NativeWindow parent_window, TabContents* tab_contents) : tab_contents_(tab_contents), allowed_label_(NULL), blocked_label_(NULL), allowed_cookies_tree_(NULL), blocked_cookies_tree_(NULL), block_allowed_button_(NULL), allow_blocked_button_(NULL), for_session_blocked_button_(NULL), infobar_(NULL), status_changed_(false) { TabSpecificContentSettings* content_settings = tab_contents->GetTabSpecificContentSettings(); registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN, Source<TabSpecificContentSettings>(content_settings)); Init(); window_ = tab_contents_->CreateConstrainedDialog(this); } CollectedCookiesWin::~CollectedCookiesWin() { allowed_cookies_tree_->SetModel(NULL); blocked_cookies_tree_->SetModel(NULL); } void CollectedCookiesWin::Init() { using views::GridLayout; GridLayout* layout = GridLayout::CreatePanel(this); SetLayoutManager(layout); const int single_column_layout_id = 0; views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); const int single_column_with_padding_layout_id = 1; views::ColumnSet* column_set_with_padding = layout->AddColumnSet( single_column_with_padding_layout_id); column_set_with_padding->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); column_set_with_padding->AddPaddingColumn(0, 2); layout->StartRow(0, single_column_layout_id); views::TabbedPane* tabbed_pane = new views::TabbedPane(); layout->AddView(tabbed_pane); // NOTE: the panes need to be added after the tabbed_pane has been added to // its parent. std::wstring label_allowed = UTF16ToWide(l10n_util::GetStringUTF16( IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL)); std::wstring label_blocked = UTF16ToWide(l10n_util::GetStringUTF16( IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_TAB_LABEL)); tabbed_pane->AddTab(label_allowed, CreateAllowedPane()); tabbed_pane->AddTab(label_blocked, CreateBlockedPane()); tabbed_pane->SelectTabAt(0); tabbed_pane->set_listener(this); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, single_column_with_padding_layout_id); cookie_info_view_ = new CookieInfoView(false); layout->AddView(cookie_info_view_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, single_column_with_padding_layout_id); infobar_ = new InfobarView(); layout->AddView(infobar_); EnableControls(); ShowCookieInfo(); } views::View* CollectedCookiesWin::CreateAllowedPane() { TabSpecificContentSettings* content_settings = tab_contents_->GetTabSpecificContentSettings(); // Create the controls that go into the pane. allowed_label_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL))); allowed_cookies_tree_model_.reset( content_settings->GetAllowedCookiesTreeModel()); allowed_cookies_tree_ = new views::TreeView(); allowed_cookies_tree_->SetModel(allowed_cookies_tree_model_.get()); allowed_cookies_tree_->SetController(this); allowed_cookies_tree_->SetRootShown(false); allowed_cookies_tree_->SetEditable(false); allowed_cookies_tree_->set_lines_at_root(true); allowed_cookies_tree_->set_auto_expand_children(true); block_allowed_button_ = new views::NativeButton(this, UTF16ToWide( l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON))); // Create the view that holds all the controls together. This will be the // pane added to the tabbed pane. using views::GridLayout; views::View* pane = new views::View(); GridLayout* layout = GridLayout::CreatePanel(pane); pane->SetLayoutManager(layout); const int single_column_layout_id = 0; views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); layout->StartRow(0, single_column_layout_id); layout->AddView(allowed_label_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(1, single_column_layout_id); layout->AddView(allowed_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, single_column_layout_id); layout->AddView(block_allowed_button_, 1, 1, GridLayout::LEADING, GridLayout::CENTER); return pane; } views::View* CollectedCookiesWin::CreateBlockedPane() { TabSpecificContentSettings* content_settings = tab_contents_->GetTabSpecificContentSettings(); HostContentSettingsMap* host_content_settings_map = tab_contents_->profile()->GetHostContentSettingsMap(); // Create the controls that go into the pane. blocked_label_ = new views::Label( UTF16ToWide(l10n_util::GetStringUTF16( host_content_settings_map->BlockThirdPartyCookies() ? IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED : IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL))); blocked_label_->SetMultiLine(true); blocked_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); blocked_cookies_tree_model_.reset( content_settings->GetBlockedCookiesTreeModel()); blocked_cookies_tree_ = new views::TreeView(); blocked_cookies_tree_->SetModel(blocked_cookies_tree_model_.get()); blocked_cookies_tree_->SetController(this); blocked_cookies_tree_->SetRootShown(false); blocked_cookies_tree_->SetEditable(false); blocked_cookies_tree_->set_lines_at_root(true); blocked_cookies_tree_->set_auto_expand_children(true); allow_blocked_button_ = new views::NativeButton(this, UTF16ToWide( l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON))); for_session_blocked_button_ = new views::NativeButton(this, UTF16ToWide( l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON))); // Create the view that holds all the controls together. This will be the // pane added to the tabbed pane. using views::GridLayout; views::View* pane = new views::View(); GridLayout* layout = GridLayout::CreatePanel(pane); pane->SetLayoutManager(layout); const int single_column_layout_id = 0; views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); const int three_columns_layout_id = 1; column_set = layout->AddColumnSet(three_columns_layout_id); column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); layout->StartRow(0, single_column_layout_id); layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(1, single_column_layout_id); layout->AddView( blocked_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); layout->StartRow(0, three_columns_layout_id); layout->AddView(allow_blocked_button_); layout->AddView(for_session_blocked_button_); return pane; } /////////////////////////////////////////////////////////////////////////////// // ConstrainedDialogDelegate implementation. std::wstring CollectedCookiesWin::GetWindowTitle() const { return UTF16ToWide( l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE)); } int CollectedCookiesWin::GetDialogButtons() const { return MessageBoxFlags::DIALOGBUTTON_CANCEL; } std::wstring CollectedCookiesWin::GetDialogButtonLabel( MessageBoxFlags::DialogButton button) const { return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLOSE)); } void CollectedCookiesWin::DeleteDelegate() { delete this; } bool CollectedCookiesWin::Cancel() { if (status_changed_) { tab_contents_->AddInfoBar( new CollectedCookiesInfoBarDelegate(tab_contents_)); } return true; } views::View* CollectedCookiesWin::GetContentsView() { return this; } /////////////////////////////////////////////////////////////////////////////// // views::ButtonListener implementation. void CollectedCookiesWin::ButtonPressed(views::Button* sender, const views::Event& event) { if (sender == block_allowed_button_) AddContentException(allowed_cookies_tree_, CONTENT_SETTING_BLOCK); else if (sender == allow_blocked_button_) AddContentException(blocked_cookies_tree_, CONTENT_SETTING_ALLOW); else if (sender == for_session_blocked_button_) AddContentException(blocked_cookies_tree_, CONTENT_SETTING_SESSION_ONLY); } /////////////////////////////////////////////////////////////////////////////// // views::TabbedPaneListener implementation. void CollectedCookiesWin::TabSelectedAt(int index) { EnableControls(); ShowCookieInfo(); } /////////////////////////////////////////////////////////////////////////////// // views::TreeViewController implementation. void CollectedCookiesWin::OnTreeViewSelectionChanged( views::TreeView* tree_view) { EnableControls(); ShowCookieInfo(); } /////////////////////////////////////////////////////////////////////////////// // CollectedCookiesWin, private methods. void CollectedCookiesWin::EnableControls() { bool enable_allowed_buttons = false; ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode(); if (node) { CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); if (cookie_node->GetDetailedInfo().node_type == CookieTreeNode::DetailedInfo::TYPE_ORIGIN) { enable_allowed_buttons = static_cast<CookieTreeOriginNode*>( cookie_node)->CanCreateContentException(); } } block_allowed_button_->SetEnabled(enable_allowed_buttons); bool enable_blocked_buttons = false; node = blocked_cookies_tree_->GetSelectedNode(); if (node) { CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); if (cookie_node->GetDetailedInfo().node_type == CookieTreeNode::DetailedInfo::TYPE_ORIGIN) { enable_blocked_buttons = static_cast<CookieTreeOriginNode*>( cookie_node)->CanCreateContentException(); } } allow_blocked_button_->SetEnabled(enable_blocked_buttons); for_session_blocked_button_->SetEnabled(enable_blocked_buttons); } void CollectedCookiesWin::ShowCookieInfo() { ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode(); if (!node) node = blocked_cookies_tree_->GetSelectedNode(); if (node) { CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); const CookieTreeNode::DetailedInfo detailed_info = cookie_node->GetDetailedInfo(); if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) { CookieTreeCookieNode* cookie_info_node = static_cast<CookieTreeCookieNode*>(cookie_node); cookie_info_view_->SetCookie(detailed_info.cookie->Domain(), *detailed_info.cookie); } else { cookie_info_view_->ClearCookieDisplay(); } } else { cookie_info_view_->ClearCookieDisplay(); } } void CollectedCookiesWin::AddContentException(views::TreeView* tree_view, ContentSetting setting) { CookieTreeOriginNode* origin_node = static_cast<CookieTreeOriginNode*>(tree_view->GetSelectedNode()); origin_node->CreateContentException( tab_contents_->profile()->GetHostContentSettingsMap(), setting); infobar_->UpdateVisibility(true, setting, origin_node->GetTitle()); gfx::Rect bounds = GetWidget()->GetClientAreaScreenBounds(); // WidgetWin::GetBounds returns the bounds relative to the parent window, // while WidgetWin::SetBounds wants screen coordinates. Do the translation // here until http://crbug.com/52851 is fixed. POINT topleft = {bounds.x(), bounds.y()}; MapWindowPoints(HWND_DESKTOP, tab_contents_->GetNativeView(), &topleft, 1); gfx::Size size = GetRootView()->GetPreferredSize(); bounds.SetRect(topleft.x, topleft.y, size.width(), size.height()); GetWidget()->SetBounds(bounds); status_changed_ = true; } /////////////////////////////////////////////////////////////////////////////// // NotificationObserver implementation. void CollectedCookiesWin::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(type == NotificationType::COLLECTED_COOKIES_SHOWN); DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(), tab_contents_->GetTabSpecificContentSettings()); window_->CloseConstrainedWindow(); }