1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/collected_cookies_views.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
9 #include "chrome/browser/browsing_data/browsing_data_channel_id_helper.h"
10 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
11 #include "chrome/browser/browsing_data/browsing_data_database_helper.h"
12 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
13 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
14 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
15 #include "chrome/browser/browsing_data/cookies_tree_model.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/content_settings/cookie_settings.h"
18 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
19 #include "chrome/browser/infobars/infobar_service.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
22 #include "chrome/browser/ui/views/cookie_info_view.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "chrome/grit/locale_settings.h"
26 #include "components/constrained_window/constrained_window_views.h"
27 #include "content/public/browser/notification_details.h"
28 #include "content/public/browser/notification_source.h"
29 #include "content/public/browser/web_contents.h"
30 #include "grit/theme_resources.h"
31 #include "net/cookies/canonical_cookie.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/resource/resource_bundle.h"
34 #include "ui/gfx/color_utils.h"
35 #include "ui/views/border.h"
36 #include "ui/views/controls/button/label_button.h"
37 #include "ui/views/controls/image_view.h"
38 #include "ui/views/controls/label.h"
39 #include "ui/views/controls/scroll_view.h"
40 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
41 #include "ui/views/controls/tree/tree_view.h"
42 #include "ui/views/layout/box_layout.h"
43 #include "ui/views/layout/grid_layout.h"
44 #include "ui/views/layout/layout_constants.h"
45 #include "ui/views/widget/widget.h"
49 // Declared in browser_dialogs.h so others don't have to depend on our header.
50 void ShowCollectedCookiesDialog(content::WebContents* web_contents) {
51 // Deletes itself on close.
52 new CollectedCookiesViews(web_contents);
59 // Spacing between the infobar frame and its contents.
60 const int kInfobarVerticalPadding = 3;
61 const int kInfobarHorizontalPadding = 8;
63 // Width of the infobar frame.
64 const int kInfobarBorderSize = 1;
66 // Dimensions of the tree views.
67 const int kTreeViewWidth = 400;
68 const int kTreeViewHeight = 125;
70 // The color of the border around the cookies tree view.
71 const SkColor kCookiesBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8);
73 // Spacing constants used with the new dialog style.
74 const int kTabbedPaneTopPadding = 14;
75 const int kLabelBottomPadding = 17;
76 const int kCookieInfoBottomPadding = 4;
77 const int kVPanelPadding = 15;
81 // A custom view that conditionally displays an infobar.
82 class InfobarView : public views::View {
85 content_ = new views::View;
86 SkColor border_color = SK_ColorGRAY;
88 views::Border::CreateSolidBorder(kInfobarBorderSize, border_color));
90 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
91 info_image_ = new views::ImageView();
92 info_image_->SetImage(rb.GetImageSkiaNamed(IDR_INFO));
93 label_ = new views::Label();
95 ~InfobarView() override {}
97 // Update the visibility of the infobar. If |is_visible| is true, a rule for
98 // |setting| on |domain_name| was created.
99 void UpdateVisibility(bool is_visible,
100 ContentSetting setting,
101 const base::string16& domain_name) {
107 base::string16 label;
109 case CONTENT_SETTING_BLOCK:
110 label = l10n_util::GetStringFUTF16(
111 IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name);
114 case CONTENT_SETTING_ALLOW:
115 label = l10n_util::GetStringFUTF16(
116 IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name);
119 case CONTENT_SETTING_SESSION_ONLY:
120 label = l10n_util::GetStringFUTF16(
121 IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name);
127 label_->SetText(label);
133 // Initialize contents and layout.
135 AddChildView(content_);
136 content_->SetLayoutManager(
137 new views::BoxLayout(views::BoxLayout::kHorizontal,
138 kInfobarHorizontalPadding,
139 kInfobarVerticalPadding,
140 views::kRelatedControlSmallHorizontalSpacing));
141 content_->AddChildView(info_image_);
142 content_->AddChildView(label_);
143 UpdateVisibility(false, CONTENT_SETTING_BLOCK, base::string16());
146 // views::View overrides.
147 gfx::Size GetPreferredSize() const override {
151 // Add space around the banner.
152 gfx::Size size(content_->GetPreferredSize());
153 size.Enlarge(0, 2 * views::kRelatedControlVerticalSpacing);
157 void Layout() override {
159 0, views::kRelatedControlVerticalSpacing,
160 width(), height() - views::kRelatedControlVerticalSpacing);
163 void ViewHierarchyChanged(
164 const ViewHierarchyChangedDetails& details) override {
165 if (details.is_add && details.child == this)
169 // Holds the info icon image and text label and renders the border.
170 views::View* content_;
172 views::ImageView* info_image_;
173 // The label responsible for rendering the text.
174 views::Label* label_;
176 DISALLOW_COPY_AND_ASSIGN(InfobarView);
179 ///////////////////////////////////////////////////////////////////////////////
180 // CollectedCookiesViews, public:
182 CollectedCookiesViews::CollectedCookiesViews(content::WebContents* web_contents)
183 : web_contents_(web_contents),
184 allowed_label_(NULL),
185 blocked_label_(NULL),
186 allowed_cookies_tree_(NULL),
187 blocked_cookies_tree_(NULL),
188 block_allowed_button_(NULL),
189 delete_allowed_button_(NULL),
190 allow_blocked_button_(NULL),
191 for_session_blocked_button_(NULL),
192 cookie_info_view_(NULL),
194 status_changed_(false) {
195 TabSpecificContentSettings* content_settings =
196 TabSpecificContentSettings::FromWebContents(web_contents);
197 registrar_.Add(this, chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
198 content::Source<TabSpecificContentSettings>(content_settings));
199 ShowWebModalDialogViews(this, web_contents);
202 ///////////////////////////////////////////////////////////////////////////////
203 // CollectedCookiesViews, views::DialogDelegate implementation:
205 base::string16 CollectedCookiesViews::GetWindowTitle() const {
206 return l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE);
209 int CollectedCookiesViews::GetDialogButtons() const {
210 return ui::DIALOG_BUTTON_CANCEL;
213 base::string16 CollectedCookiesViews::GetDialogButtonLabel(
214 ui::DialogButton button) const {
215 return l10n_util::GetStringUTF16(IDS_CLOSE);
218 bool CollectedCookiesViews::Cancel() {
219 if (status_changed_) {
220 CollectedCookiesInfoBarDelegate::Create(
221 InfoBarService::FromWebContents(web_contents_));
226 ui::ModalType CollectedCookiesViews::GetModalType() const {
227 return ui::MODAL_TYPE_CHILD;
230 ///////////////////////////////////////////////////////////////////////////////
231 // CollectedCookiesViews, views::ButtonListener implementation:
233 void CollectedCookiesViews::ButtonPressed(views::Button* sender,
234 const ui::Event& event) {
235 if (sender == block_allowed_button_) {
236 AddContentException(allowed_cookies_tree_, CONTENT_SETTING_BLOCK);
237 } else if (sender == delete_allowed_button_) {
238 allowed_cookies_tree_model_->DeleteCookieNode(
239 static_cast<CookieTreeNode*>(allowed_cookies_tree_->GetSelectedNode()));
240 } else if (sender == allow_blocked_button_) {
241 AddContentException(blocked_cookies_tree_, CONTENT_SETTING_ALLOW);
242 } else if (sender == for_session_blocked_button_) {
243 AddContentException(blocked_cookies_tree_, CONTENT_SETTING_SESSION_ONLY);
247 ///////////////////////////////////////////////////////////////////////////////
248 // CollectedCookiesViews, views::TabbedPaneListener implementation:
250 void CollectedCookiesViews::TabSelectedAt(int index) {
255 ///////////////////////////////////////////////////////////////////////////////
256 // CollectedCookiesViews, views::TreeViewController implementation:
258 void CollectedCookiesViews::OnTreeViewSelectionChanged(
259 views::TreeView* tree_view) {
264 ///////////////////////////////////////////////////////////////////////////////
265 // CollectedCookiesViews, views::View overrides:
267 gfx::Size CollectedCookiesViews::GetMinimumSize() const {
268 // Allow UpdateWebContentsModalDialogPosition to clamp the dialog width.
269 return gfx::Size(0, View::GetMinimumSize().height());
272 void CollectedCookiesViews::ViewHierarchyChanged(
273 const ViewHierarchyChangedDetails& details) {
274 views::DialogDelegateView::ViewHierarchyChanged(details);
275 if (details.is_add && details.child == this)
279 ////////////////////////////////////////////////////////////////////////////////
280 // CollectedCookiesViews, private:
282 CollectedCookiesViews::~CollectedCookiesViews() {
283 allowed_cookies_tree_->SetModel(NULL);
284 blocked_cookies_tree_->SetModel(NULL);
287 void CollectedCookiesViews::Init() {
288 using views::GridLayout;
290 GridLayout* layout = GridLayout::CreatePanel(this);
291 SetLayoutManager(layout);
293 const int single_column_layout_id = 0;
294 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
295 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
296 GridLayout::USE_PREF, 0, 0);
298 layout->StartRow(0, single_column_layout_id);
299 views::TabbedPane* tabbed_pane = new views::TabbedPane();
300 layout->SetInsets(gfx::Insets(kTabbedPaneTopPadding, 0, 0, 0));
302 layout->AddView(tabbed_pane);
303 // NOTE: Panes must be added after |tabbed_pane| has been added to its parent.
304 base::string16 label_allowed = l10n_util::GetStringUTF16(
305 IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL);
306 base::string16 label_blocked = l10n_util::GetStringUTF16(
307 IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_TAB_LABEL);
308 tabbed_pane->AddTab(label_allowed, CreateAllowedPane());
309 tabbed_pane->AddTab(label_blocked, CreateBlockedPane());
310 tabbed_pane->SelectTabAt(0);
311 tabbed_pane->set_listener(this);
312 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
314 layout->StartRow(0, single_column_layout_id);
315 cookie_info_view_ = new CookieInfoView();
316 layout->AddView(cookie_info_view_);
317 layout->AddPaddingRow(0, kCookieInfoBottomPadding);
319 layout->StartRow(0, single_column_layout_id);
320 infobar_ = new InfobarView();
321 layout->AddView(infobar_);
327 views::View* CollectedCookiesViews::CreateAllowedPane() {
328 TabSpecificContentSettings* content_settings =
329 TabSpecificContentSettings::FromWebContents(web_contents_);
331 // Create the controls that go into the pane.
332 allowed_label_ = new views::Label(l10n_util::GetStringUTF16(
333 IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL));
335 allowed_cookies_tree_model_ =
336 content_settings->CreateAllowedCookiesTreeModel();
337 allowed_cookies_tree_ = new views::TreeView();
338 allowed_cookies_tree_->SetModel(allowed_cookies_tree_model_.get());
339 allowed_cookies_tree_->SetRootShown(false);
340 allowed_cookies_tree_->SetEditable(false);
341 allowed_cookies_tree_->set_auto_expand_children(true);
342 allowed_cookies_tree_->SetController(this);
344 block_allowed_button_ = new views::LabelButton(this,
345 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON));
346 block_allowed_button_->SetStyle(views::Button::STYLE_BUTTON);
348 delete_allowed_button_ = new views::LabelButton(this,
349 l10n_util::GetStringUTF16(IDS_COOKIES_REMOVE_LABEL));
350 delete_allowed_button_->SetStyle(views::Button::STYLE_BUTTON);
352 // Create the view that holds all the controls together. This will be the
353 // pane added to the tabbed pane.
354 using views::GridLayout;
356 views::View* pane = new views::View();
357 GridLayout* layout = GridLayout::CreatePanel(pane);
358 layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew,
359 kVPanelPadding, views::kButtonHEdgeMarginNew);
360 pane->SetLayoutManager(layout);
362 const int single_column_layout_id = 0;
363 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
364 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
365 GridLayout::USE_PREF, 0, 0);
367 const int three_columns_layout_id = 1;
368 column_set = layout->AddColumnSet(three_columns_layout_id);
369 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
370 GridLayout::USE_PREF, 0, 0);
371 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
372 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
373 GridLayout::USE_PREF, 0, 0);
375 layout->StartRow(0, single_column_layout_id);
376 layout->AddView(allowed_label_);
377 layout->AddPaddingRow(0, kLabelBottomPadding);
379 layout->StartRow(1, single_column_layout_id);
380 layout->AddView(CreateScrollView(allowed_cookies_tree_), 1, 1,
381 GridLayout::FILL, GridLayout::FILL, kTreeViewWidth,
383 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
385 layout->StartRow(0, three_columns_layout_id);
386 layout->AddView(block_allowed_button_);
387 layout->AddView(delete_allowed_button_);
392 views::View* CollectedCookiesViews::CreateBlockedPane() {
393 TabSpecificContentSettings* content_settings =
394 TabSpecificContentSettings::FromWebContents(web_contents_);
397 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
398 PrefService* prefs = profile->GetPrefs();
400 // Create the controls that go into the pane.
401 blocked_label_ = new views::Label(
402 l10n_util::GetStringUTF16(
403 prefs->GetBoolean(prefs::kBlockThirdPartyCookies) ?
404 IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
405 IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL));
406 blocked_label_->SetMultiLine(true);
407 blocked_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
408 blocked_cookies_tree_model_ =
409 content_settings->CreateBlockedCookiesTreeModel();
410 blocked_cookies_tree_ = new views::TreeView();
411 blocked_cookies_tree_->SetModel(blocked_cookies_tree_model_.get());
412 blocked_cookies_tree_->SetRootShown(false);
413 blocked_cookies_tree_->SetEditable(false);
414 blocked_cookies_tree_->set_auto_expand_children(true);
415 blocked_cookies_tree_->SetController(this);
417 allow_blocked_button_ = new views::LabelButton(this,
418 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON));
419 allow_blocked_button_->SetStyle(views::Button::STYLE_BUTTON);
420 for_session_blocked_button_ = new views::LabelButton(this,
421 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
422 for_session_blocked_button_->SetStyle(views::Button::STYLE_BUTTON);
424 // Create the view that holds all the controls together. This will be the
425 // pane added to the tabbed pane.
426 using views::GridLayout;
428 views::View* pane = new views::View();
429 GridLayout* layout = GridLayout::CreatePanel(pane);
430 layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew,
431 kVPanelPadding, views::kButtonHEdgeMarginNew);
432 pane->SetLayoutManager(layout);
434 const int single_column_layout_id = 0;
435 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
436 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
437 GridLayout::USE_PREF, 0, 0);
439 const int three_columns_layout_id = 1;
440 column_set = layout->AddColumnSet(three_columns_layout_id);
441 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
442 GridLayout::USE_PREF, 0, 0);
443 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
444 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
445 GridLayout::USE_PREF, 0, 0);
447 layout->StartRow(0, single_column_layout_id);
448 layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL);
449 layout->AddPaddingRow(0, kLabelBottomPadding);
451 layout->StartRow(1, single_column_layout_id);
453 CreateScrollView(blocked_cookies_tree_), 1, 1,
454 GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight);
455 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
457 layout->StartRow(0, three_columns_layout_id);
458 layout->AddView(allow_blocked_button_);
459 layout->AddView(for_session_blocked_button_);
464 views::View* CollectedCookiesViews::CreateScrollView(views::TreeView* pane) {
465 views::ScrollView* scroll_view = new views::ScrollView();
466 scroll_view->SetContents(pane);
467 scroll_view->SetBorder(
468 views::Border::CreateSolidBorder(1, kCookiesBorderColor));
472 void CollectedCookiesViews::EnableControls() {
473 bool enable_allowed_buttons = false;
474 ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
476 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
477 if (cookie_node->GetDetailedInfo().node_type ==
478 CookieTreeNode::DetailedInfo::TYPE_HOST) {
479 enable_allowed_buttons = static_cast<CookieTreeHostNode*>(
480 cookie_node)->CanCreateContentException();
483 block_allowed_button_->SetEnabled(enable_allowed_buttons);
484 delete_allowed_button_->SetEnabled(node != NULL);
486 bool enable_blocked_buttons = false;
487 node = blocked_cookies_tree_->GetSelectedNode();
489 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
490 if (cookie_node->GetDetailedInfo().node_type ==
491 CookieTreeNode::DetailedInfo::TYPE_HOST) {
492 enable_blocked_buttons = static_cast<CookieTreeHostNode*>(
493 cookie_node)->CanCreateContentException();
496 allow_blocked_button_->SetEnabled(enable_blocked_buttons);
497 for_session_blocked_button_->SetEnabled(enable_blocked_buttons);
500 void CollectedCookiesViews::ShowCookieInfo() {
501 ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
503 node = blocked_cookies_tree_->GetSelectedNode();
506 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
507 const CookieTreeNode::DetailedInfo detailed_info =
508 cookie_node->GetDetailedInfo();
510 if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) {
511 cookie_info_view_->SetCookie(detailed_info.cookie->Domain(),
512 *detailed_info.cookie);
514 cookie_info_view_->ClearCookieDisplay();
517 cookie_info_view_->ClearCookieDisplay();
521 void CollectedCookiesViews::AddContentException(views::TreeView* tree_view,
522 ContentSetting setting) {
523 CookieTreeHostNode* host_node =
524 static_cast<CookieTreeHostNode*>(tree_view->GetSelectedNode());
526 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
527 host_node->CreateContentException(
528 CookieSettings::Factory::GetForProfile(profile).get(), setting);
529 infobar_->UpdateVisibility(true, setting, host_node->GetTitle());
530 status_changed_ = true;
533 ///////////////////////////////////////////////////////////////////////////////
534 // CollectedCookiesViews, content::NotificationObserver implementation:
536 void CollectedCookiesViews::Observe(
538 const content::NotificationSource& source,
539 const content::NotificationDetails& details) {
540 DCHECK_EQ(chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, type);
541 GetWidget()->Close();