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