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