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