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 "content/public/browser/notification_details.h" 27 #include "content/public/browser/notification_source.h" 28 #include "content/public/browser/web_contents.h" 29 #include "grit/generated_resources.h" 30 #include "grit/locale_settings.h" 31 #include "grit/theme_resources.h" 32 #include "net/cookies/canonical_cookie.h" 33 #include "ui/base/l10n/l10n_util.h" 34 #include "ui/base/resource/resource_bundle.h" 35 #include "ui/gfx/color_utils.h" 36 #include "ui/views/border.h" 37 #include "ui/views/controls/button/label_button.h" 38 #include "ui/views/controls/image_view.h" 39 #include "ui/views/controls/label.h" 40 #include "ui/views/controls/scroll_view.h" 41 #include "ui/views/controls/tabbed_pane/tabbed_pane.h" 42 #include "ui/views/controls/tree/tree_view.h" 43 #include "ui/views/layout/box_layout.h" 44 #include "ui/views/layout/grid_layout.h" 45 #include "ui/views/layout/layout_constants.h" 46 #include "ui/views/widget/widget.h" 47 48 namespace chrome { 49 50 // Declared in browser_dialogs.h so others don't have to depend on our header. 51 void ShowCollectedCookiesDialog(content::WebContents* web_contents) { 52 // Deletes itself on close. 53 new CollectedCookiesViews(web_contents); 54 } 55 56 } // namespace chrome 57 58 namespace { 59 60 // Spacing between the infobar frame and its contents. 61 const int kInfobarVerticalPadding = 3; 62 const int kInfobarHorizontalPadding = 8; 63 64 // Width of the infobar frame. 65 const int kInfobarBorderSize = 1; 66 67 // Dimensions of the tree views. 68 const int kTreeViewWidth = 400; 69 const int kTreeViewHeight = 125; 70 71 // The color of the border around the cookies tree view. 72 const SkColor kCookiesBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8); 73 74 // Spacing constants used with the new dialog style. 75 const int kTabbedPaneTopPadding = 14; 76 const int kLabelBottomPadding = 17; 77 const int kCookieInfoBottomPadding = 4; 78 const int kVPanelPadding = 15; 79 80 } // namespace 81 82 // A custom view that conditionally displays an infobar. 83 class InfobarView : public views::View { 84 public: 85 InfobarView() { 86 content_ = new views::View; 87 SkColor border_color = SK_ColorGRAY; 88 content_->SetBorder( 89 views::Border::CreateSolidBorder(kInfobarBorderSize, border_color)); 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 base::string16& domain_name) { 103 if (!is_visible) { 104 SetVisible(false); 105 return; 106 } 107 108 base::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, base::string16()); 145 } 146 147 // views::View overrides. 148 virtual gfx::Size GetPreferredSize() const 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 183 CollectedCookiesViews::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 delete_allowed_button_(NULL), 191 allow_blocked_button_(NULL), 192 for_session_blocked_button_(NULL), 193 cookie_info_view_(NULL), 194 infobar_(NULL), 195 status_changed_(false) { 196 TabSpecificContentSettings* content_settings = 197 TabSpecificContentSettings::FromWebContents(web_contents); 198 registrar_.Add(this, chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, 199 content::Source<TabSpecificContentSettings>(content_settings)); 200 ShowWebModalDialogViews(this, web_contents); 201 } 202 203 /////////////////////////////////////////////////////////////////////////////// 204 // CollectedCookiesViews, views::DialogDelegate implementation: 205 206 base::string16 CollectedCookiesViews::GetWindowTitle() const { 207 return l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE); 208 } 209 210 int CollectedCookiesViews::GetDialogButtons() const { 211 return ui::DIALOG_BUTTON_CANCEL; 212 } 213 214 base::string16 CollectedCookiesViews::GetDialogButtonLabel( 215 ui::DialogButton button) const { 216 return l10n_util::GetStringUTF16(IDS_CLOSE); 217 } 218 219 bool CollectedCookiesViews::Cancel() { 220 if (status_changed_) { 221 CollectedCookiesInfoBarDelegate::Create( 222 InfoBarService::FromWebContents(web_contents_)); 223 } 224 return true; 225 } 226 227 ui::ModalType CollectedCookiesViews::GetModalType() const { 228 return ui::MODAL_TYPE_CHILD; 229 } 230 231 /////////////////////////////////////////////////////////////////////////////// 232 // CollectedCookiesViews, views::ButtonListener implementation: 233 234 void CollectedCookiesViews::ButtonPressed(views::Button* sender, 235 const ui::Event& event) { 236 if (sender == block_allowed_button_) { 237 AddContentException(allowed_cookies_tree_, CONTENT_SETTING_BLOCK); 238 } else if (sender == delete_allowed_button_) { 239 allowed_cookies_tree_model_->DeleteCookieNode( 240 static_cast<CookieTreeNode*>(allowed_cookies_tree_->GetSelectedNode())); 241 } else if (sender == allow_blocked_button_) { 242 AddContentException(blocked_cookies_tree_, CONTENT_SETTING_ALLOW); 243 } else if (sender == for_session_blocked_button_) { 244 AddContentException(blocked_cookies_tree_, CONTENT_SETTING_SESSION_ONLY); 245 } 246 } 247 248 /////////////////////////////////////////////////////////////////////////////// 249 // CollectedCookiesViews, views::TabbedPaneListener implementation: 250 251 void CollectedCookiesViews::TabSelectedAt(int index) { 252 EnableControls(); 253 ShowCookieInfo(); 254 } 255 256 /////////////////////////////////////////////////////////////////////////////// 257 // CollectedCookiesViews, views::TreeViewController implementation: 258 259 void CollectedCookiesViews::OnTreeViewSelectionChanged( 260 views::TreeView* tree_view) { 261 EnableControls(); 262 ShowCookieInfo(); 263 } 264 265 /////////////////////////////////////////////////////////////////////////////// 266 // CollectedCookiesViews, views::View overrides: 267 268 gfx::Size CollectedCookiesViews::GetMinimumSize() const { 269 // Allow UpdateWebContentsModalDialogPosition to clamp the dialog width. 270 return gfx::Size(0, View::GetMinimumSize().height()); 271 } 272 273 void CollectedCookiesViews::ViewHierarchyChanged( 274 const ViewHierarchyChangedDetails& details) { 275 if (details.is_add && details.child == this) 276 Init(); 277 } 278 279 //////////////////////////////////////////////////////////////////////////////// 280 // CollectedCookiesViews, private: 281 282 CollectedCookiesViews::~CollectedCookiesViews() { 283 allowed_cookies_tree_->SetModel(NULL); 284 blocked_cookies_tree_->SetModel(NULL); 285 } 286 287 void CollectedCookiesViews::Init() { 288 using views::GridLayout; 289 290 GridLayout* layout = GridLayout::CreatePanel(this); 291 SetLayoutManager(layout); 292 293 const int single_column_layout_id = 0; 294 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); 295 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, 296 GridLayout::USE_PREF, 0, 0); 297 298 layout->StartRow(0, single_column_layout_id); 299 views::TabbedPane* tabbed_pane = new views::TabbedPane(); 300 layout->SetInsets(gfx::Insets(kTabbedPaneTopPadding, 0, 0, 0)); 301 302 layout->AddView(tabbed_pane); 303 // NOTE: Panes must be added after |tabbed_pane| has been added to its parent. 304 base::string16 label_allowed = l10n_util::GetStringUTF16( 305 IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL); 306 base::string16 label_blocked = l10n_util::GetStringUTF16( 307 IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_TAB_LABEL); 308 tabbed_pane->AddTab(label_allowed, CreateAllowedPane()); 309 tabbed_pane->AddTab(label_blocked, CreateBlockedPane()); 310 tabbed_pane->SelectTabAt(0); 311 tabbed_pane->set_listener(this); 312 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 313 314 layout->StartRow(0, single_column_layout_id); 315 cookie_info_view_ = new CookieInfoView(); 316 layout->AddView(cookie_info_view_); 317 layout->AddPaddingRow(0, kCookieInfoBottomPadding); 318 319 layout->StartRow(0, single_column_layout_id); 320 infobar_ = new InfobarView(); 321 layout->AddView(infobar_); 322 323 EnableControls(); 324 ShowCookieInfo(); 325 } 326 327 views::View* CollectedCookiesViews::CreateAllowedPane() { 328 TabSpecificContentSettings* content_settings = 329 TabSpecificContentSettings::FromWebContents(web_contents_); 330 331 // Create the controls that go into the pane. 332 allowed_label_ = new views::Label(l10n_util::GetStringUTF16( 333 IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL)); 334 335 const LocalSharedObjectsContainer& allowed_data = 336 content_settings->allowed_local_shared_objects(); 337 allowed_cookies_tree_model_ = allowed_data.CreateCookiesTreeModel(); 338 allowed_cookies_tree_ = new views::TreeView(); 339 allowed_cookies_tree_->SetModel(allowed_cookies_tree_model_.get()); 340 allowed_cookies_tree_->SetRootShown(false); 341 allowed_cookies_tree_->SetEditable(false); 342 allowed_cookies_tree_->set_auto_expand_children(true); 343 allowed_cookies_tree_->SetController(this); 344 345 block_allowed_button_ = new views::LabelButton(this, 346 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON)); 347 block_allowed_button_->SetStyle(views::Button::STYLE_BUTTON); 348 349 delete_allowed_button_ = new views::LabelButton(this, 350 l10n_util::GetStringUTF16(IDS_COOKIES_REMOVE_LABEL)); 351 delete_allowed_button_->SetStyle(views::Button::STYLE_BUTTON); 352 353 // Create the view that holds all the controls together. This will be the 354 // pane added to the tabbed pane. 355 using views::GridLayout; 356 357 views::View* pane = new views::View(); 358 GridLayout* layout = GridLayout::CreatePanel(pane); 359 layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew, 360 kVPanelPadding, views::kButtonHEdgeMarginNew); 361 pane->SetLayoutManager(layout); 362 363 const int single_column_layout_id = 0; 364 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); 365 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, 366 GridLayout::USE_PREF, 0, 0); 367 368 const int three_columns_layout_id = 1; 369 column_set = layout->AddColumnSet(three_columns_layout_id); 370 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, 371 GridLayout::USE_PREF, 0, 0); 372 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 373 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, 374 GridLayout::USE_PREF, 0, 0); 375 376 layout->StartRow(0, single_column_layout_id); 377 layout->AddView(allowed_label_); 378 layout->AddPaddingRow(0, kLabelBottomPadding); 379 380 layout->StartRow(1, single_column_layout_id); 381 layout->AddView(CreateScrollView(allowed_cookies_tree_), 1, 1, 382 GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, 383 kTreeViewHeight); 384 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 385 386 layout->StartRow(0, three_columns_layout_id); 387 layout->AddView(block_allowed_button_); 388 layout->AddView(delete_allowed_button_); 389 390 return pane; 391 } 392 393 views::View* CollectedCookiesViews::CreateBlockedPane() { 394 TabSpecificContentSettings* content_settings = 395 TabSpecificContentSettings::FromWebContents(web_contents_); 396 397 Profile* profile = 398 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 399 PrefService* prefs = profile->GetPrefs(); 400 401 // Create the controls that go into the pane. 402 blocked_label_ = new views::Label( 403 l10n_util::GetStringUTF16( 404 prefs->GetBoolean(prefs::kBlockThirdPartyCookies) ? 405 IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED : 406 IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL)); 407 blocked_label_->SetMultiLine(true); 408 blocked_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 409 const LocalSharedObjectsContainer& blocked_data = 410 content_settings->blocked_local_shared_objects(); 411 blocked_cookies_tree_model_ = blocked_data.CreateCookiesTreeModel(); 412 blocked_cookies_tree_ = new views::TreeView(); 413 blocked_cookies_tree_->SetModel(blocked_cookies_tree_model_.get()); 414 blocked_cookies_tree_->SetRootShown(false); 415 blocked_cookies_tree_->SetEditable(false); 416 blocked_cookies_tree_->set_auto_expand_children(true); 417 blocked_cookies_tree_->SetController(this); 418 419 allow_blocked_button_ = new views::LabelButton(this, 420 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON)); 421 allow_blocked_button_->SetStyle(views::Button::STYLE_BUTTON); 422 for_session_blocked_button_ = new views::LabelButton(this, 423 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON)); 424 for_session_blocked_button_->SetStyle(views::Button::STYLE_BUTTON); 425 426 // Create the view that holds all the controls together. This will be the 427 // pane added to the tabbed pane. 428 using views::GridLayout; 429 430 views::View* pane = new views::View(); 431 GridLayout* layout = GridLayout::CreatePanel(pane); 432 layout->SetInsets(kVPanelPadding, views::kButtonHEdgeMarginNew, 433 kVPanelPadding, views::kButtonHEdgeMarginNew); 434 pane->SetLayoutManager(layout); 435 436 const int single_column_layout_id = 0; 437 views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id); 438 column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, 439 GridLayout::USE_PREF, 0, 0); 440 441 const int three_columns_layout_id = 1; 442 column_set = layout->AddColumnSet(three_columns_layout_id); 443 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, 444 GridLayout::USE_PREF, 0, 0); 445 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 446 column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, 447 GridLayout::USE_PREF, 0, 0); 448 449 layout->StartRow(0, single_column_layout_id); 450 layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL); 451 layout->AddPaddingRow(0, kLabelBottomPadding); 452 453 layout->StartRow(1, single_column_layout_id); 454 layout->AddView( 455 CreateScrollView(blocked_cookies_tree_), 1, 1, 456 GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight); 457 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 458 459 layout->StartRow(0, three_columns_layout_id); 460 layout->AddView(allow_blocked_button_); 461 layout->AddView(for_session_blocked_button_); 462 463 return pane; 464 } 465 466 views::View* CollectedCookiesViews::CreateScrollView(views::TreeView* pane) { 467 views::ScrollView* scroll_view = new views::ScrollView(); 468 scroll_view->SetContents(pane); 469 scroll_view->SetBorder( 470 views::Border::CreateSolidBorder(1, kCookiesBorderColor)); 471 return scroll_view; 472 } 473 474 void CollectedCookiesViews::EnableControls() { 475 bool enable_allowed_buttons = false; 476 ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode(); 477 if (node) { 478 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); 479 if (cookie_node->GetDetailedInfo().node_type == 480 CookieTreeNode::DetailedInfo::TYPE_HOST) { 481 enable_allowed_buttons = static_cast<CookieTreeHostNode*>( 482 cookie_node)->CanCreateContentException(); 483 } 484 } 485 block_allowed_button_->SetEnabled(enable_allowed_buttons); 486 delete_allowed_button_->SetEnabled(node != NULL); 487 488 bool enable_blocked_buttons = false; 489 node = blocked_cookies_tree_->GetSelectedNode(); 490 if (node) { 491 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); 492 if (cookie_node->GetDetailedInfo().node_type == 493 CookieTreeNode::DetailedInfo::TYPE_HOST) { 494 enable_blocked_buttons = static_cast<CookieTreeHostNode*>( 495 cookie_node)->CanCreateContentException(); 496 } 497 } 498 allow_blocked_button_->SetEnabled(enable_blocked_buttons); 499 for_session_blocked_button_->SetEnabled(enable_blocked_buttons); 500 } 501 502 void CollectedCookiesViews::ShowCookieInfo() { 503 ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode(); 504 if (!node) 505 node = blocked_cookies_tree_->GetSelectedNode(); 506 507 if (node) { 508 CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node); 509 const CookieTreeNode::DetailedInfo detailed_info = 510 cookie_node->GetDetailedInfo(); 511 512 if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) { 513 cookie_info_view_->SetCookie(detailed_info.cookie->Domain(), 514 *detailed_info.cookie); 515 } else { 516 cookie_info_view_->ClearCookieDisplay(); 517 } 518 } else { 519 cookie_info_view_->ClearCookieDisplay(); 520 } 521 } 522 523 void CollectedCookiesViews::AddContentException(views::TreeView* tree_view, 524 ContentSetting setting) { 525 CookieTreeHostNode* host_node = 526 static_cast<CookieTreeHostNode*>(tree_view->GetSelectedNode()); 527 Profile* profile = 528 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 529 host_node->CreateContentException( 530 CookieSettings::Factory::GetForProfile(profile).get(), setting); 531 infobar_->UpdateVisibility(true, setting, host_node->GetTitle()); 532 status_changed_ = true; 533 } 534 535 /////////////////////////////////////////////////////////////////////////////// 536 // CollectedCookiesViews, content::NotificationObserver implementation: 537 538 void CollectedCookiesViews::Observe( 539 int type, 540 const content::NotificationSource& source, 541 const content::NotificationDetails& details) { 542 DCHECK_EQ(chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, type); 543 GetWidget()->Close(); 544 } 545