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/website_settings/website_settings_popup_view.h" 6 7 #include <algorithm> 8 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/certificate_viewer.h" 12 #include "chrome/browser/infobars/infobar_service.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser_dialogs.h" 16 #include "chrome/browser/ui/views/collected_cookies_views.h" 17 #include "chrome/browser/ui/views/website_settings/permission_selector_view.h" 18 #include "chrome/browser/ui/website_settings/website_settings.h" 19 #include "chrome/browser/ui/website_settings/website_settings_utils.h" 20 #include "chrome/common/url_constants.h" 21 #include "chrome/grit/chromium_strings.h" 22 #include "chrome/grit/generated_resources.h" 23 #include "components/content_settings/core/common/content_settings_types.h" 24 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/cert_store.h" 26 #include "content/public/browser/user_metrics.h" 27 #include "grit/theme_resources.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/models/simple_menu_model.h" 30 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/gfx/canvas.h" 32 #include "ui/gfx/font_list.h" 33 #include "ui/gfx/image/image.h" 34 #include "ui/gfx/insets.h" 35 #include "ui/resources/grit/ui_resources.h" 36 #include "ui/views/controls/button/image_button.h" 37 #include "ui/views/controls/button/menu_button.h" 38 #include "ui/views/controls/button/menu_button_listener.h" 39 #include "ui/views/controls/image_view.h" 40 #include "ui/views/controls/label.h" 41 #include "ui/views/controls/link.h" 42 #include "ui/views/controls/menu/menu_model_adapter.h" 43 #include "ui/views/controls/menu/menu_runner.h" 44 #include "ui/views/controls/separator.h" 45 #include "ui/views/controls/tabbed_pane/tabbed_pane.h" 46 #include "ui/views/layout/box_layout.h" 47 #include "ui/views/layout/grid_layout.h" 48 #include "ui/views/layout/layout_manager.h" 49 #include "ui/views/view.h" 50 #include "ui/views/widget/widget.h" 51 #include "url/gurl.h" 52 53 namespace { 54 55 // NOTE(jdonnelly): This use of this process-wide variable assumes that there's 56 // never more than one website settings popup shown and that it's associated 57 // with the current window. If this assumption fails in the future, we'll need 58 // to return a weak pointer from ShowPopup so callers can associate it with the 59 // current window (or other context) and check if the popup they care about is 60 // showing. 61 bool is_popup_showing = false; 62 63 // Padding values for sections on the connection tab. 64 const int kConnectionSectionPaddingBottom = 16; 65 const int kConnectionSectionPaddingLeft = 18; 66 const int kConnectionSectionPaddingTop = 16; 67 const int kConnectionSectionPaddingRight = 18; 68 69 // The text color that is used for the site identity status text, if the site's 70 // identity was sucessfully verified. 71 const SkColor kIdentityVerifiedTextColor = 0xFF298a27; 72 73 // Left icon margin. 74 const int kIconMarginLeft = 6; 75 76 // Margin and padding values for the |PopupHeaderView|. 77 const int kHeaderMarginBottom = 10; 78 const int kHeaderPaddingBottom = 12; 79 const int kHeaderPaddingLeft = 18; 80 const int kHeaderPaddingRight = 8; 81 const int kHeaderPaddingTop = 12; 82 83 // Spacing between the site identity label and the site identity status text in 84 // the popup header. 85 const int kHeaderRowSpacing = 4; 86 87 // To make the bubble's arrow point directly at the location icon rather than at 88 // the Omnibox's edge, inset the bubble's anchor rect by this amount of pixels. 89 const int kLocationIconVerticalMargin = 5; 90 91 // The max possible width of the popup. 92 const int kMaxPopupWidth = 500; 93 94 // The margins between the popup border and the popup content. 95 const int kPopupMarginTop = 4; 96 const int kPopupMarginLeft = 0; 97 const int kPopupMarginBottom = 10; 98 const int kPopupMarginRight = 0; 99 100 // Padding values for sections on the permissions tab. 101 const int kPermissionsSectionContentMinWidth = 300; 102 const int kPermissionsSectionPaddingBottom = 6; 103 const int kPermissionsSectionPaddingLeft = 18; 104 const int kPermissionsSectionPaddingTop = 16; 105 106 // Space between the headline and the content of a section on the permissions 107 // tab. 108 const int kPermissionsSectionHeadlineMarginBottom = 10; 109 // The content of the "Permissions" section and the "Cookies and Site Data" 110 // section is structured in individual rows. |kPermissionsSectionRowSpacing| 111 // is the space between these rows. 112 const int kPermissionsSectionRowSpacing = 2; 113 114 const int kSiteDataIconColumnWidth = 20; 115 const int kSiteDataSectionRowSpacing = 11; 116 117 } // namespace 118 119 // |PopupHeaderView| is the UI element (view) that represents the header of the 120 // |WebsiteSettingsPopupView|. The header shows the status of the site's 121 // identity check and the name of the site's identity. 122 class PopupHeaderView : public views::View { 123 public: 124 explicit PopupHeaderView(views::ButtonListener* close_button_listener); 125 virtual ~PopupHeaderView(); 126 127 // Sets the name of the site's identity. 128 void SetIdentityName(const base::string16& name); 129 130 // Sets the |status_text| for the identity check of this site and the 131 // |text_color|. 132 void SetIdentityStatus(const base::string16& status_text, SkColor text_color); 133 134 private: 135 // The label that displays the name of the site's identity. 136 views::Label* name_; 137 // The label that displays the status of the identity check for this site. 138 views::Label* status_; 139 140 DISALLOW_COPY_AND_ASSIGN(PopupHeaderView); 141 }; 142 143 // Website Settings are not supported for internal Chrome pages. Instead of the 144 // |WebsiteSettingsPopupView|, the |InternalPageInfoPopupView| is 145 // displayed. 146 class InternalPageInfoPopupView : public views::BubbleDelegateView { 147 public: 148 explicit InternalPageInfoPopupView(views::View* anchor_view); 149 virtual ~InternalPageInfoPopupView(); 150 151 // views::BubbleDelegateView: 152 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; 153 154 private: 155 DISALLOW_COPY_AND_ASSIGN(InternalPageInfoPopupView); 156 }; 157 158 //////////////////////////////////////////////////////////////////////////////// 159 // Popup Header 160 //////////////////////////////////////////////////////////////////////////////// 161 162 PopupHeaderView::PopupHeaderView(views::ButtonListener* close_button_listener) 163 : name_(NULL), status_(NULL) { 164 views::GridLayout* layout = new views::GridLayout(this); 165 SetLayoutManager(layout); 166 167 const int label_column = 0; 168 views::ColumnSet* column_set = layout->AddColumnSet(label_column); 169 column_set->AddPaddingColumn(0, kHeaderPaddingLeft); 170 column_set->AddColumn(views::GridLayout::FILL, 171 views::GridLayout::FILL, 172 1, 173 views::GridLayout::USE_PREF, 174 0, 175 0); 176 column_set->AddPaddingColumn(1, 0); 177 column_set->AddColumn(views::GridLayout::FILL, 178 views::GridLayout::FILL, 179 1, 180 views::GridLayout::USE_PREF, 181 0, 182 0); 183 column_set->AddPaddingColumn(0, kHeaderPaddingRight); 184 185 layout->AddPaddingRow(0, kHeaderPaddingTop); 186 187 layout->StartRow(0, label_column); 188 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 189 name_ = new views::Label( 190 base::string16(), rb.GetFontList(ui::ResourceBundle::BoldFont)); 191 layout->AddView(name_, 1, 1, views::GridLayout::LEADING, 192 views::GridLayout::TRAILING); 193 views::ImageButton* close_button = 194 new views::ImageButton(close_button_listener); 195 close_button->SetImage(views::CustomButton::STATE_NORMAL, 196 rb.GetImageNamed(IDR_CLOSE_2).ToImageSkia()); 197 close_button->SetImage(views::CustomButton::STATE_HOVERED, 198 rb.GetImageNamed(IDR_CLOSE_2_H).ToImageSkia()); 199 close_button->SetImage(views::CustomButton::STATE_PRESSED, 200 rb.GetImageNamed(IDR_CLOSE_2_P).ToImageSkia()); 201 layout->AddView(close_button, 1, 1, views::GridLayout::TRAILING, 202 views::GridLayout::LEADING); 203 204 layout->AddPaddingRow(0, kHeaderRowSpacing); 205 206 layout->StartRow(0, label_column); 207 status_ = new views::Label(base::string16()); 208 layout->AddView(status_, 209 1, 210 1, 211 views::GridLayout::LEADING, 212 views::GridLayout::CENTER); 213 214 layout->AddPaddingRow(0, kHeaderPaddingBottom); 215 } 216 217 PopupHeaderView::~PopupHeaderView() { 218 } 219 220 void PopupHeaderView::SetIdentityName(const base::string16& name) { 221 name_->SetText(name); 222 } 223 224 void PopupHeaderView::SetIdentityStatus(const base::string16& status, 225 SkColor text_color) { 226 status_->SetText(status); 227 status_->SetEnabledColor(text_color); 228 } 229 230 //////////////////////////////////////////////////////////////////////////////// 231 // InternalPageInfoPopupView 232 //////////////////////////////////////////////////////////////////////////////// 233 234 InternalPageInfoPopupView::InternalPageInfoPopupView(views::View* anchor_view) 235 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT) { 236 // Compensate for built-in vertical padding in the anchor view's image. 237 set_anchor_view_insets(gfx::Insets(kLocationIconVerticalMargin, 0, 238 kLocationIconVerticalMargin, 0)); 239 240 const int kSpacing = 4; 241 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, kSpacing, 242 kSpacing, kSpacing)); 243 views::ImageView* icon_view = new views::ImageView(); 244 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 245 icon_view->SetImage(rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_26)); 246 AddChildView(icon_view); 247 248 views::Label* label = 249 new views::Label(l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE)); 250 label->SetMultiLine(true); 251 label->SetAllowCharacterBreak(true); 252 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 253 AddChildView(label); 254 255 views::BubbleDelegateView::CreateBubble(this)->Show(); 256 SizeToContents(); 257 } 258 259 InternalPageInfoPopupView::~InternalPageInfoPopupView() { 260 } 261 262 void InternalPageInfoPopupView::OnWidgetDestroying(views::Widget* widget) { 263 is_popup_showing = false; 264 } 265 266 //////////////////////////////////////////////////////////////////////////////// 267 // WebsiteSettingsPopupView 268 //////////////////////////////////////////////////////////////////////////////// 269 270 WebsiteSettingsPopupView::~WebsiteSettingsPopupView() { 271 } 272 273 // static 274 void WebsiteSettingsPopupView::ShowPopup(views::View* anchor_view, 275 Profile* profile, 276 content::WebContents* web_contents, 277 const GURL& url, 278 const content::SSLStatus& ssl, 279 Browser* browser) { 280 is_popup_showing = true; 281 if (InternalChromePage(url)) { 282 new InternalPageInfoPopupView(anchor_view); 283 } else { 284 new WebsiteSettingsPopupView(anchor_view, profile, web_contents, url, ssl, 285 browser); 286 } 287 } 288 289 // static 290 bool WebsiteSettingsPopupView::IsPopupShowing() { 291 return is_popup_showing; 292 } 293 294 WebsiteSettingsPopupView::WebsiteSettingsPopupView( 295 views::View* anchor_view, 296 Profile* profile, 297 content::WebContents* web_contents, 298 const GURL& url, 299 const content::SSLStatus& ssl, 300 Browser* browser) 301 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT), 302 web_contents_(web_contents), 303 browser_(browser), 304 header_(NULL), 305 tabbed_pane_(NULL), 306 site_data_content_(NULL), 307 cookie_dialog_link_(NULL), 308 permissions_content_(NULL), 309 connection_tab_(NULL), 310 identity_info_content_(NULL), 311 certificate_dialog_link_(NULL), 312 signed_certificate_timestamps_link_(NULL), 313 reset_decisions_button_(NULL), 314 cert_id_(0), 315 help_center_link_(NULL), 316 connection_info_content_(NULL), 317 page_info_content_(NULL), 318 weak_factory_(this) { 319 // Compensate for built-in vertical padding in the anchor view's image. 320 set_anchor_view_insets(gfx::Insets(kLocationIconVerticalMargin, 0, 321 kLocationIconVerticalMargin, 0)); 322 323 views::GridLayout* layout = new views::GridLayout(this); 324 SetLayoutManager(layout); 325 const int content_column = 0; 326 views::ColumnSet* column_set = layout->AddColumnSet(content_column); 327 column_set->AddColumn(views::GridLayout::FILL, 328 views::GridLayout::FILL, 329 1, 330 views::GridLayout::USE_PREF, 331 0, 332 0); 333 334 header_ = new PopupHeaderView(this); 335 layout->StartRow(1, content_column); 336 layout->AddView(header_); 337 338 layout->AddPaddingRow(1, kHeaderMarginBottom); 339 tabbed_pane_ = new views::TabbedPane(); 340 layout->StartRow(1, content_column); 341 layout->AddView(tabbed_pane_); 342 // Tabs must be added after the tabbed_pane_ was added to the views 343 // hierachy. Adding the |tabbed_pane_| to the views hierachy triggers the 344 // initialization of the native tab UI element. If the native tab UI 345 // element is not initalized adding a tab will result in a NULL pointer 346 // exception. 347 tabbed_pane_->AddTabAtIndex( 348 TAB_ID_PERMISSIONS, 349 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS), 350 CreatePermissionsTab()); 351 connection_tab_ = CreateConnectionTab(); 352 tabbed_pane_->AddTabAtIndex( 353 TAB_ID_CONNECTION, 354 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION), 355 connection_tab_); 356 DCHECK_EQ(tabbed_pane_->GetTabCount(), NUM_TAB_IDS); 357 tabbed_pane_->set_listener(this); 358 359 set_margins(gfx::Insets(kPopupMarginTop, kPopupMarginLeft, 360 kPopupMarginBottom, kPopupMarginRight)); 361 362 views::BubbleDelegateView::CreateBubble(this)->Show(); 363 SizeToContents(); 364 365 presenter_.reset(new WebsiteSettings( 366 this, profile, 367 TabSpecificContentSettings::FromWebContents(web_contents), 368 InfoBarService::FromWebContents(web_contents), url, ssl, 369 content::CertStore::GetInstance())); 370 } 371 372 void WebsiteSettingsPopupView::OnPermissionChanged( 373 const WebsiteSettingsUI::PermissionInfo& permission) { 374 presenter_->OnSitePermissionChanged(permission.type, permission.setting); 375 } 376 377 void WebsiteSettingsPopupView::OnWidgetDestroying(views::Widget* widget) { 378 is_popup_showing = false; 379 presenter_->OnUIClosing(); 380 } 381 382 void WebsiteSettingsPopupView::ButtonPressed(views::Button* button, 383 const ui::Event& event) { 384 if (button == reset_decisions_button_) 385 presenter_->OnRevokeSSLErrorBypassButtonPressed(); 386 GetWidget()->Close(); 387 } 388 389 void WebsiteSettingsPopupView::LinkClicked(views::Link* source, 390 int event_flags) { 391 if (source == cookie_dialog_link_) { 392 // Count how often the Collected Cookies dialog is opened. 393 content::RecordAction( 394 base::UserMetricsAction("WebsiteSettings_CookiesDialogOpened")); 395 new CollectedCookiesViews(web_contents_); 396 } else if (source == certificate_dialog_link_) { 397 gfx::NativeWindow parent = GetAnchorView() ? 398 GetAnchorView()->GetWidget()->GetNativeWindow() : NULL; 399 ShowCertificateViewerByID(web_contents_, parent, cert_id_); 400 } else if (source == signed_certificate_timestamps_link_) { 401 chrome::ShowSignedCertificateTimestampsViewer( 402 web_contents_, signed_certificate_timestamp_ids_); 403 } else if (source == help_center_link_) { 404 browser_->OpenURL( 405 content::OpenURLParams(GURL(chrome::kPageInfoHelpCenterURL), 406 content::Referrer(), 407 NEW_FOREGROUND_TAB, 408 ui::PAGE_TRANSITION_LINK, 409 false)); 410 } 411 } 412 413 void WebsiteSettingsPopupView::TabSelectedAt(int index) { 414 tabbed_pane_->GetSelectedTab()->Layout(); 415 SizeToContents(); 416 } 417 418 gfx::Size WebsiteSettingsPopupView::GetPreferredSize() const { 419 if (header_ == NULL && tabbed_pane_ == NULL) 420 return views::View::GetPreferredSize(); 421 422 int height = 0; 423 if (header_) 424 height += header_->GetPreferredSize().height(); 425 if (tabbed_pane_) 426 height += tabbed_pane_->GetPreferredSize().height(); 427 428 int width = kPermissionsSectionContentMinWidth; 429 if (site_data_content_) 430 width = std::max(width, site_data_content_->GetPreferredSize().width()); 431 if (permissions_content_) 432 width = std::max(width, permissions_content_->GetPreferredSize().width()); 433 width += kPermissionsSectionPaddingLeft; 434 width = std::min(width, kMaxPopupWidth); 435 436 return gfx::Size(width, height); 437 } 438 439 void WebsiteSettingsPopupView::SetCookieInfo( 440 const CookieInfoList& cookie_info_list) { 441 site_data_content_->RemoveAllChildViews(true); 442 443 views::GridLayout* layout = new views::GridLayout(site_data_content_); 444 site_data_content_->SetLayoutManager(layout); 445 446 const int site_data_content_column = 0; 447 views::ColumnSet* column_set = 448 layout->AddColumnSet(site_data_content_column); 449 column_set->AddColumn(views::GridLayout::FILL, 450 views::GridLayout::FILL, 451 1, 452 views::GridLayout::FIXED, 453 kSiteDataIconColumnWidth, 454 0); 455 column_set->AddPaddingColumn(0, kIconMarginLeft); 456 column_set->AddColumn(views::GridLayout::FILL, 457 views::GridLayout::FILL, 458 1, 459 views::GridLayout::USE_PREF, 460 0, 461 0); 462 463 layout->AddPaddingRow(1, 5); 464 for (CookieInfoList::const_iterator i(cookie_info_list.begin()); 465 i != cookie_info_list.end(); 466 ++i) { 467 base::string16 label_text = l10n_util::GetStringFUTF16( 468 IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE, 469 base::UTF8ToUTF16(i->cookie_source), 470 base::IntToString16(i->allowed), 471 base::IntToString16(i->blocked)); 472 if (i != cookie_info_list.begin()) 473 layout->AddPaddingRow(1, kSiteDataSectionRowSpacing); 474 layout->StartRow(1, site_data_content_column); 475 WebsiteSettingsUI::PermissionInfo info; 476 info.type = CONTENT_SETTINGS_TYPE_COOKIES; 477 info.setting = CONTENT_SETTING_ALLOW; 478 views::ImageView* icon = new views::ImageView(); 479 const gfx::Image& image = WebsiteSettingsUI::GetPermissionIcon(info); 480 icon->SetImage(image.ToImageSkia()); 481 layout->AddView(icon, 1, 1, views::GridLayout::CENTER, 482 views::GridLayout::CENTER); 483 layout->AddView(new views::Label(label_text), 1, 1, 484 views::GridLayout::LEADING, views::GridLayout::CENTER); 485 } 486 layout->AddPaddingRow(1, 6); 487 488 layout->Layout(site_data_content_); 489 SizeToContents(); 490 } 491 492 void WebsiteSettingsPopupView::SetPermissionInfo( 493 const PermissionInfoList& permission_info_list) { 494 permissions_content_->RemoveAllChildViews(true); 495 496 views::GridLayout* layout = 497 new views::GridLayout(permissions_content_); 498 permissions_content_->SetLayoutManager(layout); 499 const int content_column = 0; 500 views::ColumnSet* column_set = 501 layout->AddColumnSet(content_column); 502 column_set->AddColumn(views::GridLayout::FILL, 503 views::GridLayout::FILL, 504 1, 505 views::GridLayout::USE_PREF, 506 0, 507 0); 508 for (PermissionInfoList::const_iterator permission = 509 permission_info_list.begin(); 510 permission != permission_info_list.end(); 511 ++permission) { 512 layout->StartRow(1, content_column); 513 PermissionSelectorView* selector = new PermissionSelectorView( 514 web_contents_ ? web_contents_->GetURL() : GURL::EmptyGURL(), 515 *permission); 516 selector->AddObserver(this); 517 layout->AddView(selector, 518 1, 519 1, 520 views::GridLayout::LEADING, 521 views::GridLayout::CENTER); 522 layout->AddPaddingRow(1, kPermissionsSectionRowSpacing); 523 } 524 525 SizeToContents(); 526 } 527 528 void WebsiteSettingsPopupView::SetIdentityInfo( 529 const IdentityInfo& identity_info) { 530 base::string16 identity_status_text; 531 SkColor text_color = SK_ColorBLACK; 532 switch (identity_info.identity_status) { 533 case WebsiteSettings::SITE_IDENTITY_STATUS_CERT: 534 case WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT: 535 identity_status_text = 536 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_IDENTITY_VERIFIED); 537 text_color = kIdentityVerifiedTextColor; 538 break; 539 case WebsiteSettings::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT: 540 identity_status_text = 541 l10n_util::GetStringUTF16(IDS_CERT_POLICY_PROVIDED_CERT_HEADER); 542 break; 543 default: 544 identity_status_text = 545 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_IDENTITY_NOT_VERIFIED); 546 break; 547 } 548 header_->SetIdentityName(base::UTF8ToUTF16(identity_info.site_identity)); 549 header_->SetIdentityStatus(identity_status_text, text_color); 550 551 // The headline and the certificate dialog link of the site's identity 552 // section is only displayed if the site's identity was verified. If the 553 // site's identity was verified, then the headline contains the organization 554 // name from the provided certificate. If the organization name is not 555 // available than the hostname of the site is used instead. 556 base::string16 headline; 557 if (identity_info.cert_id) { 558 cert_id_ = identity_info.cert_id; 559 signed_certificate_timestamp_ids_.assign( 560 identity_info.signed_certificate_timestamp_ids.begin(), 561 identity_info.signed_certificate_timestamp_ids.end()); 562 563 certificate_dialog_link_ = new views::Link( 564 l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON)); 565 certificate_dialog_link_->set_listener(this); 566 567 if (!signed_certificate_timestamp_ids_.empty()) { 568 signed_certificate_timestamps_link_ = 569 new views::Link(l10n_util::GetStringUTF16( 570 IDS_PAGEINFO_CERT_TRANSPARENCY_INFO_BUTTON)); 571 signed_certificate_timestamps_link_->set_listener(this); 572 } 573 574 if (identity_info.show_ssl_decision_revoke_button) { 575 reset_decisions_button_ = new views::LabelButton( 576 this, 577 l10n_util::GetStringUTF16( 578 IDS_PAGEINFO_RESET_INVALID_CERTIFICATE_DECISIONS_BUTTON)); 579 reset_decisions_button_->SetStyle(views::Button::STYLE_BUTTON); 580 } 581 582 headline = base::UTF8ToUTF16(identity_info.site_identity); 583 } 584 ResetConnectionSection( 585 identity_info_content_, 586 WebsiteSettingsUI::GetIdentityIcon(identity_info.identity_status), 587 base::string16(), // The identity section has no headline. 588 base::UTF8ToUTF16(identity_info.identity_status_description), 589 certificate_dialog_link_, 590 signed_certificate_timestamps_link_, 591 reset_decisions_button_); 592 593 ResetConnectionSection( 594 connection_info_content_, 595 WebsiteSettingsUI::GetConnectionIcon(identity_info.connection_status), 596 base::string16(), // The connection section has no headline. 597 base::UTF8ToUTF16(identity_info.connection_status_description), 598 NULL, 599 NULL, 600 NULL); 601 602 connection_tab_->InvalidateLayout(); 603 Layout(); 604 SizeToContents(); 605 } 606 607 void WebsiteSettingsPopupView::SetFirstVisit( 608 const base::string16& first_visit) { 609 ResetConnectionSection( 610 page_info_content_, 611 WebsiteSettingsUI::GetFirstVisitIcon(first_visit), 612 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE), 613 first_visit, 614 NULL, 615 NULL, 616 NULL); 617 connection_tab_->InvalidateLayout(); 618 Layout(); 619 SizeToContents(); 620 } 621 622 void WebsiteSettingsPopupView::SetSelectedTab(TabId tab_id) { 623 tabbed_pane_->SelectTabAt(tab_id); 624 } 625 626 views::View* WebsiteSettingsPopupView::CreatePermissionsTab() { 627 views::View* pane = new views::View(); 628 pane->SetLayoutManager( 629 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); 630 // Add cookies and site data section. 631 cookie_dialog_link_ = new views::Link( 632 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA)); 633 cookie_dialog_link_->set_listener(this); 634 site_data_content_ = new views::View(); 635 views::View* site_data_section = 636 CreateSection(l10n_util::GetStringUTF16( 637 IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA), 638 site_data_content_, 639 cookie_dialog_link_); 640 pane->AddChildView(site_data_section); 641 // Add permissions section. 642 permissions_content_ = new views::View(); 643 views::View* permissions_section = 644 CreateSection(l10n_util::GetStringUTF16( 645 IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS), 646 permissions_content_, 647 NULL); 648 pane->AddChildView(permissions_section); 649 return pane; 650 } 651 652 views::View* WebsiteSettingsPopupView::CreateConnectionTab() { 653 views::View* pane = new views::View(); 654 pane->SetLayoutManager( 655 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); 656 // Add site identity section. 657 identity_info_content_ = new views::View(); 658 pane->AddChildView(identity_info_content_); 659 660 // Add connection section. 661 pane->AddChildView(new views::Separator(views::Separator::HORIZONTAL)); 662 connection_info_content_ = new views::View(); 663 pane->AddChildView(connection_info_content_); 664 665 // Add page info section. 666 pane->AddChildView(new views::Separator(views::Separator::HORIZONTAL)); 667 page_info_content_ = new views::View(); 668 pane->AddChildView(page_info_content_); 669 670 // Add help center link. 671 pane->AddChildView(new views::Separator(views::Separator::HORIZONTAL)); 672 help_center_link_ = new views::Link( 673 l10n_util::GetStringUTF16(IDS_PAGE_INFO_HELP_CENTER_LINK)); 674 help_center_link_->set_listener(this); 675 views::View* link_section = new views::View(); 676 const int kLinkMarginTop = 4; 677 link_section->SetLayoutManager( 678 new views::BoxLayout(views::BoxLayout::kHorizontal, 679 kConnectionSectionPaddingLeft, 680 kLinkMarginTop, 681 0)); 682 link_section->AddChildView(help_center_link_); 683 pane->AddChildView(link_section); 684 return pane; 685 } 686 687 views::View* WebsiteSettingsPopupView::CreateSection( 688 const base::string16& headline_text, 689 views::View* content, 690 views::Link* link) { 691 views::View* container = new views::View(); 692 views::GridLayout* layout = new views::GridLayout(container); 693 container->SetLayoutManager(layout); 694 const int content_column = 0; 695 views::ColumnSet* column_set = layout->AddColumnSet(content_column); 696 column_set->AddPaddingColumn(0, kPermissionsSectionPaddingLeft); 697 column_set->AddColumn(views::GridLayout::FILL, 698 views::GridLayout::FILL, 699 1, 700 views::GridLayout::USE_PREF, 701 0, 702 0); 703 704 layout->AddPaddingRow(1, kPermissionsSectionPaddingTop); 705 layout->StartRow(1, content_column); 706 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 707 views::Label* headline = new views::Label( 708 headline_text, rb.GetFontList(ui::ResourceBundle::BoldFont)); 709 layout->AddView(headline, 1, 1, views::GridLayout::LEADING, 710 views::GridLayout::CENTER); 711 712 layout->AddPaddingRow(1, kPermissionsSectionHeadlineMarginBottom); 713 layout->StartRow(1, content_column); 714 layout->AddView(content, 1, 1, views::GridLayout::LEADING, 715 views::GridLayout::CENTER); 716 717 if (link) { 718 layout->AddPaddingRow(1, 4); 719 layout->StartRow(1, content_column); 720 layout->AddView(link, 1, 1, views::GridLayout::LEADING, 721 views::GridLayout::CENTER); 722 } 723 724 layout->AddPaddingRow(1, kPermissionsSectionPaddingBottom); 725 return container; 726 } 727 728 void WebsiteSettingsPopupView::ResetConnectionSection( 729 views::View* section_container, 730 const gfx::Image& icon, 731 const base::string16& headline, 732 const base::string16& text, 733 views::Link* link, 734 views::Link* secondary_link, 735 views::LabelButton* reset_decisions_button) { 736 section_container->RemoveAllChildViews(true); 737 738 views::GridLayout* layout = new views::GridLayout(section_container); 739 section_container->SetLayoutManager(layout); 740 views::ColumnSet* column_set = layout->AddColumnSet(0); 741 column_set->AddPaddingColumn(0, kConnectionSectionPaddingLeft); 742 column_set->AddColumn(views::GridLayout::LEADING, 743 views::GridLayout::LEADING, 744 0, 745 views::GridLayout::USE_PREF, 746 0, 747 0); 748 column_set->AddPaddingColumn(0, kIconMarginLeft); 749 column_set->AddColumn(views::GridLayout::FILL, 750 views::GridLayout::FILL, 751 1, 752 views::GridLayout::USE_PREF, 753 0, 754 0); 755 column_set->AddPaddingColumn(0, kConnectionSectionPaddingRight); 756 757 758 layout->AddPaddingRow(0, kConnectionSectionPaddingTop); 759 layout->StartRow(1, 0); 760 761 // Add status icon. 762 views::ImageView* icon_view = new views::ImageView(); 763 icon_view->SetImage(*icon.ToImageSkia()); 764 layout->AddView(icon_view, 1, 1, views::GridLayout::LEADING, 765 views::GridLayout::LEADING); 766 767 // Add section content. 768 views::View* content_pane = new views::View(); 769 views::GridLayout* content_layout = new views::GridLayout(content_pane); 770 content_pane->SetLayoutManager(content_layout); 771 views::ColumnSet* content_column_set = content_layout->AddColumnSet(0); 772 content_column_set->AddColumn(views::GridLayout::LEADING, 773 views::GridLayout::LEADING, 774 1, 775 views::GridLayout::USE_PREF, 776 0, 777 0); 778 if (!headline.empty()) { 779 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 780 views::Label* headline_label = new views::Label( 781 headline, rb.GetFontList(ui::ResourceBundle::BoldFont)); 782 headline_label->SetMultiLine(true); 783 headline_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 784 // Allow linebreaking in the middle of words if necessary, so that extremely 785 // long hostnames (longer than one line) will still be completely shown. 786 headline_label->SetAllowCharacterBreak(true); 787 content_layout->StartRow(1, 0); 788 content_layout->AddView(headline_label); 789 } 790 791 views::Label* description_label = new views::Label(text); 792 description_label->SetMultiLine(true); 793 description_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 794 description_label->SetAllowCharacterBreak(true); 795 content_layout->StartRow(1, 0); 796 content_layout->AddView(description_label); 797 798 if (link) { 799 content_layout->StartRow(1, 0); 800 content_layout->AddView(link); 801 } 802 803 if (secondary_link) { 804 content_layout->StartRow(1, 0); 805 content_layout->AddView(secondary_link); 806 } 807 808 if (reset_decisions_button) { 809 content_layout->StartRow(1, 0); 810 content_layout->AddView(reset_decisions_button); 811 } 812 813 layout->AddView(content_pane, 1, 1, views::GridLayout::LEADING, 814 views::GridLayout::LEADING); 815 layout->AddPaddingRow(0, kConnectionSectionPaddingBottom); 816 } 817