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