collected_cookies_views.cc revision f2477e01787aa58f445919b809d89e252beef54f
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.
4
5#include "chrome/browser/ui/views/collected_cookies_views.h"
6
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_cookie_helper.h"
10#include "chrome/browser/browsing_data/browsing_data_database_helper.h"
11#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
12#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
13#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
14#include "chrome/browser/browsing_data/browsing_data_server_bound_cert_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/local_shared_objects_container.h"
19#include "chrome/browser/content_settings/tab_specific_content_settings.h"
20#include "chrome/browser/infobars/infobar_service.h"
21#include "chrome/browser/profiles/profile.h"
22#include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
23#include "chrome/browser/ui/views/constrained_window_views.h"
24#include "chrome/browser/ui/views/cookie_info_view.h"
25#include "chrome/common/pref_names.h"
26#include "components/web_modal/web_contents_modal_dialog_host.h"
27#include "components/web_modal/web_contents_modal_dialog_manager.h"
28#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
29#include "content/public/browser/notification_details.h"
30#include "content/public/browser/notification_source.h"
31#include "content/public/browser/web_contents.h"
32#include "grit/generated_resources.h"
33#include "grit/locale_settings.h"
34#include "grit/theme_resources.h"
35#include "net/cookies/canonical_cookie.h"
36#include "ui/base/l10n/l10n_util.h"
37#include "ui/base/resource/resource_bundle.h"
38#include "ui/gfx/color_utils.h"
39#include "ui/views/border.h"
40#include "ui/views/controls/button/label_button.h"
41#include "ui/views/controls/image_view.h"
42#include "ui/views/controls/label.h"
43#include "ui/views/controls/scroll_view.h"
44#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
45#include "ui/views/controls/tree/tree_view.h"
46#include "ui/views/layout/box_layout.h"
47#include "ui/views/layout/grid_layout.h"
48#include "ui/views/layout/layout_constants.h"
49#include "ui/views/widget/widget.h"
50#include "ui/views/window/dialog_delegate.h"
51
52using web_modal::WebContentsModalDialogManager;
53using web_modal::WebContentsModalDialogManagerDelegate;
54
55namespace chrome {
56
57// Declared in browser_dialogs.h so others don't have to depend on our header.
58void ShowCollectedCookiesDialog(content::WebContents* web_contents) {
59  // Deletes itself on close.
60  new CollectedCookiesViews(web_contents);
61}
62
63}  // namespace chrome
64
65namespace {
66
67// Spacing between the infobar frame and its contents.
68const int kInfobarVerticalPadding = 3;
69const int kInfobarHorizontalPadding = 8;
70
71// Width of the infobar frame.
72const int kInfobarBorderSize = 1;
73
74// Dimensions of the tree views.
75const int kTreeViewWidth = 400;
76const int kTreeViewHeight = 125;
77
78// The color of the border around the cookies tree view.
79const SkColor kCookiesBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8);
80
81// Spacing constants used with the new dialog style.
82const int kTabbedPaneTopPadding = 14;
83const int kLabelBottomPadding = 17;
84const int kCookieInfoBottomPadding = 4;
85const int kVPanelPadding = 15;
86
87}  // namespace
88
89// A custom view that conditionally displays an infobar.
90class InfobarView : public views::View {
91 public:
92  InfobarView() {
93    content_ = new views::View;
94#if defined(USE_AURA) || !defined(OS_WIN)
95    SkColor border_color = SK_ColorGRAY;
96#else
97    SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
98#endif
99    views::Border* border = views::Border::CreateSolidBorder(
100        kInfobarBorderSize, border_color);
101    content_->set_border(border);
102
103    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
104    info_image_ = new views::ImageView();
105    info_image_->SetImage(rb.GetImageSkiaNamed(IDR_INFO));
106    label_ = new views::Label();
107  }
108  virtual ~InfobarView() {}
109
110  // Update the visibility of the infobar. If |is_visible| is true, a rule for
111  // |setting| on |domain_name| was created.
112  void UpdateVisibility(bool is_visible,
113                        ContentSetting setting,
114                        const string16& domain_name) {
115    if (!is_visible) {
116      SetVisible(false);
117      return;
118    }
119
120    string16 label;
121    switch (setting) {
122      case CONTENT_SETTING_BLOCK:
123        label = l10n_util::GetStringFUTF16(
124            IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name);
125        break;
126
127      case CONTENT_SETTING_ALLOW:
128        label = l10n_util::GetStringFUTF16(
129            IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name);
130        break;
131
132      case CONTENT_SETTING_SESSION_ONLY:
133        label = l10n_util::GetStringFUTF16(
134            IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name);
135        break;
136
137      default:
138        NOTREACHED();
139    }
140    label_->SetText(label);
141    content_->Layout();
142    SetVisible(true);
143  }
144
145 private:
146  // Initialize contents and layout.
147  void Init() {
148    AddChildView(content_);
149    content_->SetLayoutManager(
150        new views::BoxLayout(views::BoxLayout::kHorizontal,
151                             kInfobarHorizontalPadding,
152                             kInfobarVerticalPadding,
153                             views::kRelatedControlSmallHorizontalSpacing));
154    content_->AddChildView(info_image_);
155    content_->AddChildView(label_);
156    UpdateVisibility(false, CONTENT_SETTING_BLOCK, string16());
157  }
158
159  // views::View overrides.
160  virtual gfx::Size GetPreferredSize() OVERRIDE {
161    if (!visible())
162      return gfx::Size();
163
164    // Add space around the banner.
165    gfx::Size size(content_->GetPreferredSize());
166    size.Enlarge(0, 2 * views::kRelatedControlVerticalSpacing);
167    return size;
168  }
169
170  virtual void Layout() OVERRIDE {
171    content_->SetBounds(
172        0, views::kRelatedControlVerticalSpacing,
173        width(), height() - views::kRelatedControlVerticalSpacing);
174  }
175
176  virtual void ViewHierarchyChanged(
177      const ViewHierarchyChangedDetails& details) OVERRIDE {
178    if (details.is_add && details.child == this)
179      Init();
180  }
181
182  // Holds the info icon image and text label and renders the border.
183  views::View* content_;
184  // Info icon image.
185  views::ImageView* info_image_;
186  // The label responsible for rendering the text.
187  views::Label* label_;
188
189  DISALLOW_COPY_AND_ASSIGN(InfobarView);
190};
191
192///////////////////////////////////////////////////////////////////////////////
193// CollectedCookiesViews, public:
194
195CollectedCookiesViews::CollectedCookiesViews(content::WebContents* web_contents)
196    : web_contents_(web_contents),
197      allowed_label_(NULL),
198      blocked_label_(NULL),
199      allowed_cookies_tree_(NULL),
200      blocked_cookies_tree_(NULL),
201      block_allowed_button_(NULL),
202      allow_blocked_button_(NULL),
203      for_session_blocked_button_(NULL),
204      cookie_info_view_(NULL),
205      infobar_(NULL),
206      status_changed_(false) {
207  TabSpecificContentSettings* content_settings =
208      TabSpecificContentSettings::FromWebContents(web_contents);
209  registrar_.Add(this, chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
210                 content::Source<TabSpecificContentSettings>(content_settings));
211  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
212      WebContentsModalDialogManager::FromWebContents(web_contents);
213  WebContentsModalDialogManagerDelegate* modal_delegate =
214      web_contents_modal_dialog_manager->delegate();
215  DCHECK(modal_delegate);
216  window_ = views::Widget::CreateWindowAsFramelessChild(
217      this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
218  web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
219}
220
221///////////////////////////////////////////////////////////////////////////////
222// CollectedCookiesViews, views::DialogDelegate implementation:
223
224string16 CollectedCookiesViews::GetWindowTitle() const {
225  return l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE);
226}
227
228int CollectedCookiesViews::GetDialogButtons() const {
229  return ui::DIALOG_BUTTON_CANCEL;
230}
231
232string16 CollectedCookiesViews::GetDialogButtonLabel(
233    ui::DialogButton button) const {
234  return l10n_util::GetStringUTF16(IDS_CLOSE);
235}
236
237void CollectedCookiesViews::DeleteDelegate() {
238  delete this;
239}
240
241bool CollectedCookiesViews::Cancel() {
242  if (status_changed_) {
243    CollectedCookiesInfoBarDelegate::Create(
244        InfoBarService::FromWebContents(web_contents_));
245  }
246
247  return true;
248}
249
250// TODO(wittman): Remove this override once we move to the new style frame view
251// on all dialogs.
252views::NonClientFrameView* CollectedCookiesViews::CreateNonClientFrameView(
253    views::Widget* widget) {
254  return CreateConstrainedStyleNonClientFrameView(
255      widget,
256      web_contents_->GetBrowserContext());
257}
258
259ui::ModalType CollectedCookiesViews::GetModalType() const {
260#if defined(USE_ASH)
261  return ui::MODAL_TYPE_CHILD;
262#else
263  return views::WidgetDelegate::GetModalType();
264#endif
265}
266
267///////////////////////////////////////////////////////////////////////////////
268// CollectedCookiesViews, views::ButtonListener implementation:
269
270void CollectedCookiesViews::ButtonPressed(views::Button* sender,
271                                          const ui::Event& event) {
272  if (sender == block_allowed_button_)
273    AddContentException(allowed_cookies_tree_, CONTENT_SETTING_BLOCK);
274  else if (sender == allow_blocked_button_)
275    AddContentException(blocked_cookies_tree_, CONTENT_SETTING_ALLOW);
276  else if (sender == for_session_blocked_button_)
277    AddContentException(blocked_cookies_tree_, CONTENT_SETTING_SESSION_ONLY);
278}
279
280///////////////////////////////////////////////////////////////////////////////
281// CollectedCookiesViews, views::TabbedPaneListener implementation:
282
283void CollectedCookiesViews::TabSelectedAt(int index) {
284  EnableControls();
285  ShowCookieInfo();
286}
287
288///////////////////////////////////////////////////////////////////////////////
289// CollectedCookiesViews, views::TreeViewController implementation:
290
291void CollectedCookiesViews::OnTreeViewSelectionChanged(
292    views::TreeView* tree_view) {
293  EnableControls();
294  ShowCookieInfo();
295}
296
297///////////////////////////////////////////////////////////////////////////////
298// CollectedCookiesViews, views::View overrides:
299
300gfx::Size CollectedCookiesViews::GetMinimumSize() {
301  // Allow UpdateWebContentsModalDialogPosition to clamp the dialog width.
302  return gfx::Size(0, View::GetMinimumSize().height());
303}
304
305void CollectedCookiesViews::ViewHierarchyChanged(
306    const ViewHierarchyChangedDetails& details) {
307  if (details.is_add && details.child == this)
308    Init();
309}
310
311////////////////////////////////////////////////////////////////////////////////
312// CollectedCookiesViews, private:
313
314CollectedCookiesViews::~CollectedCookiesViews() {
315  allowed_cookies_tree_->SetModel(NULL);
316  blocked_cookies_tree_->SetModel(NULL);
317}
318
319void CollectedCookiesViews::Init() {
320  using views::GridLayout;
321
322  GridLayout* layout = GridLayout::CreatePanel(this);
323  SetLayoutManager(layout);
324
325  const int single_column_layout_id = 0;
326  views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
327  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
328                        GridLayout::USE_PREF, 0, 0);
329
330  layout->StartRow(0, single_column_layout_id);
331  views::TabbedPane* tabbed_pane = new views::TabbedPane();
332  layout->SetInsets(gfx::Insets(kTabbedPaneTopPadding, 0, 0, 0));
333
334  layout->AddView(tabbed_pane);
335  // NOTE: Panes must be added after |tabbed_pane| has been added to its parent.
336  string16 label_allowed = l10n_util::GetStringUTF16(
337      IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL);
338  string16 label_blocked = l10n_util::GetStringUTF16(
339      IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_TAB_LABEL);
340  tabbed_pane->AddTab(label_allowed, CreateAllowedPane());
341  tabbed_pane->AddTab(label_blocked, CreateBlockedPane());
342  tabbed_pane->SelectTabAt(0);
343  tabbed_pane->set_listener(this);
344  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
345
346  layout->StartRow(0, single_column_layout_id);
347  cookie_info_view_ = new CookieInfoView();
348  layout->AddView(cookie_info_view_);
349  layout->AddPaddingRow(0, kCookieInfoBottomPadding);
350
351  layout->StartRow(0, single_column_layout_id);
352  infobar_ = new InfobarView();
353  layout->AddView(infobar_);
354
355  EnableControls();
356  ShowCookieInfo();
357}
358
359views::View* CollectedCookiesViews::CreateAllowedPane() {
360  TabSpecificContentSettings* content_settings =
361      TabSpecificContentSettings::FromWebContents(web_contents_);
362
363  // Create the controls that go into the pane.
364  allowed_label_ = new views::Label(l10n_util::GetStringUTF16(
365      IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL));
366
367  const LocalSharedObjectsContainer& allowed_data =
368      content_settings->allowed_local_shared_objects();
369  allowed_cookies_tree_model_ = allowed_data.CreateCookiesTreeModel();
370  allowed_cookies_tree_ = new views::TreeView();
371  allowed_cookies_tree_->SetModel(allowed_cookies_tree_model_.get());
372  allowed_cookies_tree_->SetRootShown(false);
373  allowed_cookies_tree_->SetEditable(false);
374  allowed_cookies_tree_->set_auto_expand_children(true);
375  allowed_cookies_tree_->SetController(this);
376
377  block_allowed_button_ = new views::LabelButton(this,
378      l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON));
379  block_allowed_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
380
381  // Create the view that holds all the controls together.  This will be the
382  // pane added to the tabbed pane.
383  using views::GridLayout;
384
385  views::View* pane = new views::View();
386  GridLayout* layout = GridLayout::CreatePanel(pane);
387  layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew,
388                    kVPanelPadding, views::kButtonHEdgeMarginNew);
389  pane->SetLayoutManager(layout);
390
391  const int single_column_layout_id = 0;
392  views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
393  column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
394                        GridLayout::USE_PREF, 0, 0);
395
396  layout->StartRow(0, single_column_layout_id);
397  layout->AddView(allowed_label_);
398  layout->AddPaddingRow(0, kLabelBottomPadding);
399
400  layout->StartRow(1, single_column_layout_id);
401  layout->AddView(CreateScrollView(allowed_cookies_tree_), 1, 1,
402                  GridLayout::FILL, GridLayout::FILL, kTreeViewWidth,
403                  kTreeViewHeight);
404  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
405
406  layout->StartRow(0, single_column_layout_id);
407  layout->AddView(block_allowed_button_, 1, 1, GridLayout::LEADING,
408                  GridLayout::CENTER);
409
410  return pane;
411}
412
413views::View* CollectedCookiesViews::CreateBlockedPane() {
414  TabSpecificContentSettings* content_settings =
415      TabSpecificContentSettings::FromWebContents(web_contents_);
416
417  Profile* profile =
418      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
419  PrefService* prefs = profile->GetPrefs();
420
421  // Create the controls that go into the pane.
422  blocked_label_ = new views::Label(
423      l10n_util::GetStringUTF16(
424          prefs->GetBoolean(prefs::kBlockThirdPartyCookies) ?
425              IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
426              IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL));
427  blocked_label_->SetMultiLine(true);
428  blocked_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
429  const LocalSharedObjectsContainer& blocked_data =
430      content_settings->blocked_local_shared_objects();
431  blocked_cookies_tree_model_ = blocked_data.CreateCookiesTreeModel();
432  blocked_cookies_tree_ = new views::TreeView();
433  blocked_cookies_tree_->SetModel(blocked_cookies_tree_model_.get());
434  blocked_cookies_tree_->SetRootShown(false);
435  blocked_cookies_tree_->SetEditable(false);
436  blocked_cookies_tree_->set_auto_expand_children(true);
437  blocked_cookies_tree_->SetController(this);
438
439  allow_blocked_button_ = new views::LabelButton(this,
440      l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON));
441  allow_blocked_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
442  for_session_blocked_button_ = new views::LabelButton(this,
443      l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
444  for_session_blocked_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
445
446  // Create the view that holds all the controls together.  This will be the
447  // pane added to the tabbed pane.
448  using views::GridLayout;
449
450  views::View* pane = new views::View();
451  GridLayout* layout = GridLayout::CreatePanel(pane);
452  layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew,
453                    kVPanelPadding, views::kButtonHEdgeMarginNew);
454  pane->SetLayoutManager(layout);
455
456  const int single_column_layout_id = 0;
457  views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
458  column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
459                        GridLayout::USE_PREF, 0, 0);
460
461  const int three_columns_layout_id = 1;
462  column_set = layout->AddColumnSet(three_columns_layout_id);
463  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
464                        GridLayout::USE_PREF, 0, 0);
465  column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
466  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
467                        GridLayout::USE_PREF, 0, 0);
468
469  layout->StartRow(0, single_column_layout_id);
470  layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL);
471  layout->AddPaddingRow(0, kLabelBottomPadding);
472
473  layout->StartRow(1, single_column_layout_id);
474  layout->AddView(
475      CreateScrollView(blocked_cookies_tree_), 1, 1,
476      GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight);
477  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
478
479  layout->StartRow(0, three_columns_layout_id);
480  layout->AddView(allow_blocked_button_);
481  layout->AddView(for_session_blocked_button_);
482
483  return pane;
484}
485
486views::View* CollectedCookiesViews::CreateScrollView(views::TreeView* pane) {
487  views::ScrollView* scroll_view = new views::ScrollView();
488  scroll_view->SetContents(pane);
489  scroll_view->set_border(
490      views::Border::CreateSolidBorder(1, kCookiesBorderColor));
491  return scroll_view;
492}
493
494void CollectedCookiesViews::EnableControls() {
495  bool enable_allowed_buttons = false;
496  ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
497  if (node) {
498    CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
499    if (cookie_node->GetDetailedInfo().node_type ==
500        CookieTreeNode::DetailedInfo::TYPE_HOST) {
501      enable_allowed_buttons = static_cast<CookieTreeHostNode*>(
502          cookie_node)->CanCreateContentException();
503    }
504  }
505  block_allowed_button_->SetEnabled(enable_allowed_buttons);
506
507  bool enable_blocked_buttons = false;
508  node = blocked_cookies_tree_->GetSelectedNode();
509  if (node) {
510    CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
511    if (cookie_node->GetDetailedInfo().node_type ==
512        CookieTreeNode::DetailedInfo::TYPE_HOST) {
513      enable_blocked_buttons = static_cast<CookieTreeHostNode*>(
514          cookie_node)->CanCreateContentException();
515    }
516  }
517  allow_blocked_button_->SetEnabled(enable_blocked_buttons);
518  for_session_blocked_button_->SetEnabled(enable_blocked_buttons);
519}
520
521void CollectedCookiesViews::ShowCookieInfo() {
522  ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
523  if (!node)
524    node = blocked_cookies_tree_->GetSelectedNode();
525
526  if (node) {
527    CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
528    const CookieTreeNode::DetailedInfo detailed_info =
529        cookie_node->GetDetailedInfo();
530
531    if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) {
532      cookie_info_view_->SetCookie(detailed_info.cookie->Domain(),
533                                   *detailed_info.cookie);
534    } else {
535      cookie_info_view_->ClearCookieDisplay();
536    }
537  } else {
538    cookie_info_view_->ClearCookieDisplay();
539  }
540}
541
542void CollectedCookiesViews::AddContentException(views::TreeView* tree_view,
543                                                ContentSetting setting) {
544  CookieTreeHostNode* host_node =
545      static_cast<CookieTreeHostNode*>(tree_view->GetSelectedNode());
546  Profile* profile =
547      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
548  host_node->CreateContentException(
549      CookieSettings::Factory::GetForProfile(profile).get(), setting);
550  infobar_->UpdateVisibility(true, setting, host_node->GetTitle());
551  status_changed_ = true;
552}
553
554///////////////////////////////////////////////////////////////////////////////
555// CollectedCookiesViews, content::NotificationObserver implementation:
556
557void CollectedCookiesViews::Observe(
558    int type,
559    const content::NotificationSource& source,
560    const content::NotificationDetails& details) {
561  DCHECK_EQ(chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, type);
562  window_->Close();
563}
564