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 52 using web_modal::WebContentsModalDialogManager; 53 using web_modal::WebContentsModalDialogManagerDelegate; 54 55 namespace chrome { 56 57 // Declared in browser_dialogs.h so others don't have to depend on our header. 58 void ShowCollectedCookiesDialog(content::WebContents* web_contents) { 59 // Deletes itself on close. 60 new CollectedCookiesViews(web_contents); 61 } 62 63 } // namespace chrome 64 65 namespace { 66 67 // Spacing between the infobar frame and its contents. 68 const int kInfobarVerticalPadding = 3; 69 const int kInfobarHorizontalPadding = 8; 70 71 // Width of the infobar frame. 72 const int kInfobarBorderSize = 1; 73 74 // Dimensions of the tree views. 75 const int kTreeViewWidth = 400; 76 const int kTreeViewHeight = 125; 77 78 // The color of the border around the cookies tree view. 79 const SkColor kCookiesBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8); 80 81 // Spacing constants used with the new dialog style. 82 const int kTabbedPaneTopPadding = 14; 83 const int kLabelBottomPadding = 17; 84 const int kCookieInfoBottomPadding = 4; 85 const int kVPanelPadding = 15; 86 87 } // namespace 88 89 // A custom view that conditionally displays an infobar. 90 class 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 base::string16& domain_name) { 115 if (!is_visible) { 116 SetVisible(false); 117 return; 118 } 119 120 base::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, base::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 195 CollectedCookiesViews::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 224 base::string16 CollectedCookiesViews::GetWindowTitle() const { 225 return l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE); 226 } 227 228 int CollectedCookiesViews::GetDialogButtons() const { 229 return ui::DIALOG_BUTTON_CANCEL; 230 } 231 232 base::string16 CollectedCookiesViews::GetDialogButtonLabel( 233 ui::DialogButton button) const { 234 return l10n_util::GetStringUTF16(IDS_CLOSE); 235 } 236 237 void CollectedCookiesViews::DeleteDelegate() { 238 delete this; 239 } 240 241 bool 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. 252 views::NonClientFrameView* CollectedCookiesViews::CreateNonClientFrameView( 253 views::Widget* widget) { 254 return CreateConstrainedStyleNonClientFrameView( 255 widget, 256 web_contents_->GetBrowserContext()); 257 } 258 259 ui::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 270 void 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 283 void CollectedCookiesViews::TabSelectedAt(int index) { 284 EnableControls(); 285 ShowCookieInfo(); 286 } 287 288 /////////////////////////////////////////////////////////////////////////////// 289 // CollectedCookiesViews, views::TreeViewController implementation: 290 291 void CollectedCookiesViews::OnTreeViewSelectionChanged( 292 views::TreeView* tree_view) { 293 EnableControls(); 294 ShowCookieInfo(); 295 } 296 297 /////////////////////////////////////////////////////////////////////////////// 298 // CollectedCookiesViews, views::View overrides: 299 300 gfx::Size CollectedCookiesViews::GetMinimumSize() { 301 // Allow UpdateWebContentsModalDialogPosition to clamp the dialog width. 302 return gfx::Size(0, View::GetMinimumSize().height()); 303 } 304 305 void CollectedCookiesViews::ViewHierarchyChanged( 306 const ViewHierarchyChangedDetails& details) { 307 if (details.is_add && details.child == this) 308 Init(); 309 } 310 311 //////////////////////////////////////////////////////////////////////////////// 312 // CollectedCookiesViews, private: 313 314 CollectedCookiesViews::~CollectedCookiesViews() { 315 allowed_cookies_tree_->SetModel(NULL); 316 blocked_cookies_tree_->SetModel(NULL); 317 } 318 319 void 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 base::string16 label_allowed = l10n_util::GetStringUTF16( 337 IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL); 338 base::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 359 views::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 413 views::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 486 views::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 494 void 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 521 void 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 542 void 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 557 void 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