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.
5 #include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h"
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/geometry/insets.h"
34 #include "ui/gfx/image/image.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"
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
61 bool is_popup_showing
= false;
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;
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;
74 const int kIconMarginLeft
= 6;
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;
83 // Spacing between the site identity label and the site identity status text in
85 const int kHeaderRowSpacing
= 4;
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;
91 // The max possible width of the popup.
92 const int kMaxPopupWidth
= 500;
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;
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;
106 // Space between the headline and the content of a section on the permissions
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;
114 const int kSiteDataIconColumnWidth
= 20;
115 const int kSiteDataSectionRowSpacing
= 11;
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
{
124 explicit PopupHeaderView(views::ButtonListener
* close_button_listener
);
125 ~PopupHeaderView() override
;
127 // Sets the name of the site's identity.
128 void SetIdentityName(const base::string16
& name
);
130 // Sets the |status_text| for the identity check of this site and the
132 void SetIdentityStatus(const base::string16
& status_text
, SkColor text_color
);
135 // The label that displays the name of the site's identity.
137 // The label that displays the status of the identity check for this site.
138 views::Label
* status_
;
140 DISALLOW_COPY_AND_ASSIGN(PopupHeaderView
);
143 // Website Settings are not supported for internal Chrome pages. Instead of the
144 // |WebsiteSettingsPopupView|, the |InternalPageInfoPopupView| is
146 class InternalPageInfoPopupView
: public views::BubbleDelegateView
{
148 explicit InternalPageInfoPopupView(views::View
* anchor_view
);
149 ~InternalPageInfoPopupView() override
;
151 // views::BubbleDelegateView:
152 void OnWidgetDestroying(views::Widget
* widget
) override
;
155 DISALLOW_COPY_AND_ASSIGN(InternalPageInfoPopupView
);
158 ////////////////////////////////////////////////////////////////////////////////
160 ////////////////////////////////////////////////////////////////////////////////
162 PopupHeaderView::PopupHeaderView(views::ButtonListener
* close_button_listener
)
163 : name_(nullptr), status_(nullptr) {
164 views::GridLayout
* layout
= new views::GridLayout(this);
165 SetLayoutManager(layout
);
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
,
173 views::GridLayout::USE_PREF
,
176 column_set
->AddPaddingColumn(1, 0);
177 column_set
->AddColumn(views::GridLayout::FILL
,
178 views::GridLayout::FILL
,
180 views::GridLayout::USE_PREF
,
183 column_set
->AddPaddingColumn(0, kHeaderPaddingRight
);
185 layout
->AddPaddingRow(0, kHeaderPaddingTop
);
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
);
204 layout
->AddPaddingRow(0, kHeaderRowSpacing
);
206 layout
->StartRow(1, label_column
);
207 status_
= new views::Label(base::string16());
208 status_
->SetMultiLine(true);
209 status_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
210 layout
->AddView(status_
,
213 views::GridLayout::LEADING
,
214 views::GridLayout::LEADING
);
216 layout
->AddPaddingRow(1, kHeaderPaddingBottom
);
219 PopupHeaderView::~PopupHeaderView() {
222 void PopupHeaderView::SetIdentityName(const base::string16
& name
) {
223 name_
->SetText(name
);
226 void PopupHeaderView::SetIdentityStatus(const base::string16
& status
,
227 SkColor text_color
) {
228 status_
->SetText(status
);
229 status_
->SetEnabledColor(text_color
);
232 ////////////////////////////////////////////////////////////////////////////////
233 // InternalPageInfoPopupView
234 ////////////////////////////////////////////////////////////////////////////////
236 InternalPageInfoPopupView::InternalPageInfoPopupView(views::View
* anchor_view
)
237 : BubbleDelegateView(anchor_view
, views::BubbleBorder::TOP_LEFT
) {
238 // Compensate for built-in vertical padding in the anchor view's image.
239 set_anchor_view_insets(gfx::Insets(kLocationIconVerticalMargin
, 0,
240 kLocationIconVerticalMargin
, 0));
242 const int kSpacing
= 4;
243 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal
, kSpacing
,
244 kSpacing
, kSpacing
));
245 views::ImageView
* icon_view
= new views::ImageView();
246 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
247 icon_view
->SetImage(rb
.GetImageSkiaNamed(IDR_PRODUCT_LOGO_26
));
248 AddChildView(icon_view
);
250 views::Label
* label
=
251 new views::Label(l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE
));
252 label
->SetMultiLine(true);
253 label
->SetAllowCharacterBreak(true);
254 label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
257 views::BubbleDelegateView::CreateBubble(this)->Show();
261 InternalPageInfoPopupView::~InternalPageInfoPopupView() {
264 void InternalPageInfoPopupView::OnWidgetDestroying(views::Widget
* widget
) {
265 is_popup_showing
= false;
268 ////////////////////////////////////////////////////////////////////////////////
269 // WebsiteSettingsPopupView
270 ////////////////////////////////////////////////////////////////////////////////
272 WebsiteSettingsPopupView::~WebsiteSettingsPopupView() {
276 void WebsiteSettingsPopupView::ShowPopup(views::View
* anchor_view
,
278 content::WebContents
* web_contents
,
280 const content::SSLStatus
& ssl
,
282 is_popup_showing
= true;
283 if (InternalChromePage(url
)) {
284 new InternalPageInfoPopupView(anchor_view
);
286 new WebsiteSettingsPopupView(anchor_view
, profile
, web_contents
, url
, ssl
,
292 bool WebsiteSettingsPopupView::IsPopupShowing() {
293 return is_popup_showing
;
296 WebsiteSettingsPopupView::WebsiteSettingsPopupView(
297 views::View
* anchor_view
,
299 content::WebContents
* web_contents
,
301 const content::SSLStatus
& ssl
,
303 : BubbleDelegateView(anchor_view
, views::BubbleBorder::TOP_LEFT
),
304 web_contents_(web_contents
),
307 tabbed_pane_(nullptr),
308 permissions_tab_(nullptr),
309 site_data_content_(nullptr),
310 cookie_dialog_link_(nullptr),
311 permissions_content_(nullptr),
312 connection_tab_(nullptr),
313 identity_info_content_(nullptr),
314 certificate_dialog_link_(nullptr),
315 signed_certificate_timestamps_link_(nullptr),
316 reset_decisions_button_(nullptr),
318 help_center_link_(nullptr),
319 connection_info_content_(nullptr),
320 page_info_content_(nullptr),
321 weak_factory_(this) {
322 // Compensate for built-in vertical padding in the anchor view's image.
323 set_anchor_view_insets(gfx::Insets(kLocationIconVerticalMargin
, 0,
324 kLocationIconVerticalMargin
, 0));
326 views::GridLayout
* layout
= new views::GridLayout(this);
327 SetLayoutManager(layout
);
328 const int content_column
= 0;
329 views::ColumnSet
* column_set
= layout
->AddColumnSet(content_column
);
330 column_set
->AddColumn(views::GridLayout::FILL
,
331 views::GridLayout::FILL
,
333 views::GridLayout::USE_PREF
,
337 header_
= new PopupHeaderView(this);
338 layout
->StartRow(1, content_column
);
339 layout
->AddView(header_
);
341 layout
->AddPaddingRow(1, kHeaderMarginBottom
);
342 tabbed_pane_
= new views::TabbedPane();
343 layout
->StartRow(1, content_column
);
344 layout
->AddView(tabbed_pane_
);
346 // Tabs must be added after the tabbed_pane_ was added to the views hierarchy.
347 // Adding the |tabbed_pane_| to the views hierarchy triggers the
348 // initialization of the native tab UI element. If the native tab UI element
349 // is not initalized, adding a tab will result in a NULL pointer exception.
350 permissions_tab_
= CreatePermissionsTab();
351 tabbed_pane_
->AddTabAtIndex(
353 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS
),
355 connection_tab_
= CreateConnectionTab();
356 tabbed_pane_
->AddTabAtIndex(
358 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION
),
360 DCHECK_EQ(tabbed_pane_
->GetTabCount(), NUM_TAB_IDS
);
361 tabbed_pane_
->set_listener(this);
363 set_margins(gfx::Insets(kPopupMarginTop
, kPopupMarginLeft
,
364 kPopupMarginBottom
, kPopupMarginRight
));
366 views::BubbleDelegateView::CreateBubble(this)->Show();
369 presenter_
.reset(new WebsiteSettings(
371 TabSpecificContentSettings::FromWebContents(web_contents
),
372 InfoBarService::FromWebContents(web_contents
), url
, ssl
,
373 content::CertStore::GetInstance()));
376 void WebsiteSettingsPopupView::OnPermissionChanged(
377 const WebsiteSettingsUI::PermissionInfo
& permission
) {
378 presenter_
->OnSitePermissionChanged(permission
.type
, permission
.setting
);
381 void WebsiteSettingsPopupView::OnWidgetDestroying(views::Widget
* widget
) {
382 is_popup_showing
= false;
383 presenter_
->OnUIClosing();
386 void WebsiteSettingsPopupView::ButtonPressed(views::Button
* button
,
387 const ui::Event
& event
) {
388 if (button
== reset_decisions_button_
)
389 presenter_
->OnRevokeSSLErrorBypassButtonPressed();
390 GetWidget()->Close();
393 void WebsiteSettingsPopupView::LinkClicked(views::Link
* source
,
395 // The popup closes automatically when the collected cookies dialog or the
396 // certificate viewer opens. So delay handling of the link clicked to avoid
397 // a crash in the base class which needs to complete the mouse event handling.
398 content::BrowserThread::PostTask(
399 content::BrowserThread::UI
, FROM_HERE
,
400 base::Bind(&WebsiteSettingsPopupView::HandleLinkClickedAsync
,
401 weak_factory_
.GetWeakPtr(), source
));
404 void WebsiteSettingsPopupView::TabSelectedAt(int index
) {
406 case TAB_ID_PERMISSIONS
:
407 presenter_
->RecordWebsiteSettingsAction(
408 WebsiteSettings::WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED
);
410 case TAB_ID_CONNECTION
:
411 // If the Connection tab is selected first, we're still inside the
412 // construction of presenter_. In that case, the action is already logged
413 // by WEBSITE_SETTINGS_CONNECTION_TAB_SHOWN_IMMEDIATELY.
415 presenter_
->RecordWebsiteSettingsAction(
416 WebsiteSettings::WEBSITE_SETTINGS_CONNECTION_TAB_SELECTED
);
422 tabbed_pane_
->GetSelectedTab()->Layout();
426 gfx::Size
WebsiteSettingsPopupView::GetPreferredSize() const {
427 if (header_
== nullptr && tabbed_pane_
== nullptr)
428 return views::View::GetPreferredSize();
432 height
+= header_
->GetPreferredSize().height();
434 height
+= tabbed_pane_
->GetPreferredSize().height();
436 int width
= kPermissionsSectionContentMinWidth
;
437 if (site_data_content_
)
438 width
= std::max(width
, site_data_content_
->GetPreferredSize().width());
439 if (permissions_content_
)
440 width
= std::max(width
, permissions_content_
->GetPreferredSize().width());
441 width
+= kPermissionsSectionPaddingLeft
;
442 width
= std::min(width
, kMaxPopupWidth
);
444 return gfx::Size(width
, height
);
447 void WebsiteSettingsPopupView::SetCookieInfo(
448 const CookieInfoList
& cookie_info_list
) {
449 site_data_content_
->RemoveAllChildViews(true);
451 views::GridLayout
* layout
= new views::GridLayout(site_data_content_
);
452 site_data_content_
->SetLayoutManager(layout
);
454 const int site_data_content_column
= 0;
455 views::ColumnSet
* column_set
=
456 layout
->AddColumnSet(site_data_content_column
);
457 column_set
->AddColumn(views::GridLayout::FILL
,
458 views::GridLayout::FILL
,
460 views::GridLayout::FIXED
,
461 kSiteDataIconColumnWidth
,
463 column_set
->AddPaddingColumn(0, kIconMarginLeft
);
464 column_set
->AddColumn(views::GridLayout::FILL
,
465 views::GridLayout::FILL
,
467 views::GridLayout::USE_PREF
,
471 layout
->AddPaddingRow(1, 5);
472 for (CookieInfoList::const_iterator
i(cookie_info_list
.begin());
473 i
!= cookie_info_list
.end();
475 base::string16 label_text
= l10n_util::GetStringFUTF16(
476 IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE
,
477 base::UTF8ToUTF16(i
->cookie_source
),
478 base::IntToString16(i
->allowed
),
479 base::IntToString16(i
->blocked
));
480 if (i
!= cookie_info_list
.begin())
481 layout
->AddPaddingRow(1, kSiteDataSectionRowSpacing
);
482 layout
->StartRow(1, site_data_content_column
);
483 WebsiteSettingsUI::PermissionInfo info
;
484 info
.type
= CONTENT_SETTINGS_TYPE_COOKIES
;
485 info
.setting
= CONTENT_SETTING_ALLOW
;
486 views::ImageView
* icon
= new views::ImageView();
487 const gfx::Image
& image
= WebsiteSettingsUI::GetPermissionIcon(info
);
488 icon
->SetImage(image
.ToImageSkia());
489 layout
->AddView(icon
, 1, 1, views::GridLayout::CENTER
,
490 views::GridLayout::CENTER
);
491 layout
->AddView(new views::Label(label_text
), 1, 1,
492 views::GridLayout::LEADING
, views::GridLayout::CENTER
);
494 layout
->AddPaddingRow(1, 6);
496 layout
->Layout(site_data_content_
);
500 void WebsiteSettingsPopupView::SetPermissionInfo(
501 const PermissionInfoList
& permission_info_list
) {
502 permissions_content_
= new views::View();
503 views::GridLayout
* layout
= new views::GridLayout(permissions_content_
);
504 permissions_content_
->SetLayoutManager(layout
);
506 base::string16 headline
=
507 permission_info_list
.empty()
509 : l10n_util::GetStringUTF16(
510 IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS
);
511 views::View
* permissions_section
=
512 CreateSection(headline
, permissions_content_
, nullptr);
513 permissions_tab_
->AddChildView(permissions_section
);
515 const int content_column
= 0;
516 views::ColumnSet
* column_set
= layout
->AddColumnSet(content_column
);
517 column_set
->AddColumn(views::GridLayout::FILL
,
518 views::GridLayout::FILL
,
520 views::GridLayout::USE_PREF
,
523 for (PermissionInfoList::const_iterator permission
=
524 permission_info_list
.begin();
525 permission
!= permission_info_list
.end();
527 layout
->StartRow(1, content_column
);
528 PermissionSelectorView
* selector
= new PermissionSelectorView(
529 web_contents_
? web_contents_
->GetURL() : GURL::EmptyGURL(),
531 selector
->AddObserver(this);
532 layout
->AddView(selector
,
535 views::GridLayout::LEADING
,
536 views::GridLayout::CENTER
);
537 layout
->AddPaddingRow(1, kPermissionsSectionRowSpacing
);
540 layout
->Layout(permissions_content_
);
542 // Add site settings link.
543 site_settings_link_
= new views::Link(
544 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_SETTINGS_LINK
));
545 site_settings_link_
->set_listener(this);
546 views::View
* link_section
= new views::View();
547 const int kLinkMarginTop
= 4;
548 link_section
->SetLayoutManager(
549 new views::BoxLayout(views::BoxLayout::kHorizontal
,
550 kConnectionSectionPaddingLeft
, kLinkMarginTop
, 0));
551 link_section
->AddChildView(site_settings_link_
);
552 permissions_tab_
->AddChildView(link_section
);
557 void WebsiteSettingsPopupView::SetIdentityInfo(
558 const IdentityInfo
& identity_info
) {
559 base::string16 identity_status_text
= identity_info
.GetIdentityStatusText();
560 SkColor text_color
= SK_ColorBLACK
;
561 if (identity_info
.identity_status
==
562 WebsiteSettings::SITE_IDENTITY_STATUS_CERT
||
563 identity_info
.identity_status
==
564 WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT
) {
565 text_color
= kIdentityVerifiedTextColor
;
567 header_
->SetIdentityName(base::UTF8ToUTF16(identity_info
.site_identity
));
568 header_
->SetIdentityStatus(identity_status_text
, text_color
);
570 // The headline and the certificate dialog link of the site's identity
571 // section is only displayed if the site's identity was verified. If the
572 // site's identity was verified, then the headline contains the organization
573 // name from the provided certificate. If the organization name is not
574 // available than the hostname of the site is used instead.
575 base::string16 headline
;
576 if (identity_info
.cert_id
) {
577 cert_id_
= identity_info
.cert_id
;
578 signed_certificate_timestamp_ids_
.assign(
579 identity_info
.signed_certificate_timestamp_ids
.begin(),
580 identity_info
.signed_certificate_timestamp_ids
.end());
582 certificate_dialog_link_
= new views::Link(
583 l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON
));
584 certificate_dialog_link_
->set_listener(this);
586 if (!signed_certificate_timestamp_ids_
.empty()) {
587 signed_certificate_timestamps_link_
=
588 new views::Link(l10n_util::GetStringUTF16(
589 IDS_PAGEINFO_CERT_TRANSPARENCY_INFO_BUTTON
));
590 signed_certificate_timestamps_link_
->set_listener(this);
593 if (identity_info
.show_ssl_decision_revoke_button
) {
594 reset_decisions_button_
= new views::LabelButton(
596 l10n_util::GetStringUTF16(
597 IDS_PAGEINFO_RESET_INVALID_CERTIFICATE_DECISIONS_BUTTON
));
598 reset_decisions_button_
->SetStyle(views::Button::STYLE_BUTTON
);
601 headline
= base::UTF8ToUTF16(identity_info
.site_identity
);
603 ResetConnectionSection(
604 identity_info_content_
,
605 WebsiteSettingsUI::GetIdentityIcon(identity_info
.identity_status
),
606 base::string16(), // The identity section has no headline.
607 base::UTF8ToUTF16(identity_info
.identity_status_description
),
608 certificate_dialog_link_
,
609 signed_certificate_timestamps_link_
,
610 reset_decisions_button_
);
612 ResetConnectionSection(
613 connection_info_content_
,
614 WebsiteSettingsUI::GetConnectionIcon(identity_info
.connection_status
),
615 base::string16(), // The connection section has no headline.
616 base::UTF8ToUTF16(identity_info
.connection_status_description
),
621 connection_tab_
->InvalidateLayout();
626 void WebsiteSettingsPopupView::SetFirstVisit(
627 const base::string16
& first_visit
) {
628 ResetConnectionSection(
630 WebsiteSettingsUI::GetFirstVisitIcon(first_visit
),
631 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE
),
636 connection_tab_
->InvalidateLayout();
641 void WebsiteSettingsPopupView::SetSelectedTab(TabId tab_id
) {
642 tabbed_pane_
->SelectTabAt(tab_id
);
645 views::View
* WebsiteSettingsPopupView::CreatePermissionsTab() {
646 views::View
* pane
= new views::View();
647 pane
->SetLayoutManager(
648 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 1));
650 // Add cookies and site data section.
651 cookie_dialog_link_
= new views::Link(
652 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA
));
653 cookie_dialog_link_
->set_listener(this);
654 site_data_content_
= new views::View();
655 views::View
* site_data_section
=
656 CreateSection(l10n_util::GetStringUTF16(
657 IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA
),
659 cookie_dialog_link_
);
660 pane
->AddChildView(site_data_section
);
665 views::View
* WebsiteSettingsPopupView::CreateConnectionTab() {
666 views::View
* pane
= new views::View();
667 pane
->SetLayoutManager(
668 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 1));
669 // Add site identity section.
670 identity_info_content_
= new views::View();
671 pane
->AddChildView(identity_info_content_
);
673 // Add connection section.
674 pane
->AddChildView(new views::Separator(views::Separator::HORIZONTAL
));
675 connection_info_content_
= new views::View();
676 pane
->AddChildView(connection_info_content_
);
678 // Add page info section.
679 pane
->AddChildView(new views::Separator(views::Separator::HORIZONTAL
));
680 page_info_content_
= new views::View();
681 pane
->AddChildView(page_info_content_
);
683 // Add help center link.
684 pane
->AddChildView(new views::Separator(views::Separator::HORIZONTAL
));
685 help_center_link_
= new views::Link(
686 l10n_util::GetStringUTF16(IDS_PAGE_INFO_HELP_CENTER_LINK
));
687 help_center_link_
->set_listener(this);
688 views::View
* link_section
= new views::View();
689 const int kLinkMarginTop
= 4;
690 link_section
->SetLayoutManager(
691 new views::BoxLayout(views::BoxLayout::kHorizontal
,
692 kConnectionSectionPaddingLeft
,
695 link_section
->AddChildView(help_center_link_
);
696 pane
->AddChildView(link_section
);
700 views::View
* WebsiteSettingsPopupView::CreateSection(
701 const base::string16
& headline_text
,
702 views::View
* content
,
704 views::View
* container
= new views::View();
705 views::GridLayout
* layout
= new views::GridLayout(container
);
706 container
->SetLayoutManager(layout
);
707 const int content_column
= 0;
708 views::ColumnSet
* column_set
= layout
->AddColumnSet(content_column
);
709 column_set
->AddPaddingColumn(0, kPermissionsSectionPaddingLeft
);
710 column_set
->AddColumn(views::GridLayout::FILL
,
711 views::GridLayout::FILL
,
713 views::GridLayout::USE_PREF
,
717 if (headline_text
.length() > 0) {
718 layout
->AddPaddingRow(1, kPermissionsSectionPaddingTop
);
719 layout
->StartRow(1, content_column
);
720 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
721 views::Label
* headline
= new views::Label(
722 headline_text
, rb
.GetFontList(ui::ResourceBundle::BoldFont
));
723 layout
->AddView(headline
, 1, 1, views::GridLayout::LEADING
,
724 views::GridLayout::CENTER
);
727 layout
->AddPaddingRow(1, kPermissionsSectionHeadlineMarginBottom
);
728 layout
->StartRow(1, content_column
);
729 layout
->AddView(content
, 1, 1, views::GridLayout::LEADING
,
730 views::GridLayout::CENTER
);
733 layout
->AddPaddingRow(1, 4);
734 layout
->StartRow(1, content_column
);
735 layout
->AddView(link
, 1, 1, views::GridLayout::LEADING
,
736 views::GridLayout::CENTER
);
739 layout
->AddPaddingRow(1, kPermissionsSectionPaddingBottom
);
743 void WebsiteSettingsPopupView::ResetConnectionSection(
744 views::View
* section_container
,
745 const gfx::Image
& icon
,
746 const base::string16
& headline
,
747 const base::string16
& text
,
749 views::Link
* secondary_link
,
750 views::LabelButton
* reset_decisions_button
) {
751 section_container
->RemoveAllChildViews(true);
753 views::GridLayout
* layout
= new views::GridLayout(section_container
);
754 section_container
->SetLayoutManager(layout
);
755 views::ColumnSet
* column_set
= layout
->AddColumnSet(0);
756 column_set
->AddPaddingColumn(0, kConnectionSectionPaddingLeft
);
757 column_set
->AddColumn(views::GridLayout::LEADING
,
758 views::GridLayout::LEADING
,
760 views::GridLayout::USE_PREF
,
763 column_set
->AddPaddingColumn(0, kIconMarginLeft
);
764 column_set
->AddColumn(views::GridLayout::FILL
,
765 views::GridLayout::FILL
,
767 views::GridLayout::USE_PREF
,
770 column_set
->AddPaddingColumn(0, kConnectionSectionPaddingRight
);
773 layout
->AddPaddingRow(0, kConnectionSectionPaddingTop
);
774 layout
->StartRow(1, 0);
777 views::ImageView
* icon_view
= new views::ImageView();
778 icon_view
->SetImage(*icon
.ToImageSkia());
779 layout
->AddView(icon_view
, 1, 1, views::GridLayout::LEADING
,
780 views::GridLayout::LEADING
);
782 // Add section content.
783 views::View
* content_pane
= new views::View();
784 views::GridLayout
* content_layout
= new views::GridLayout(content_pane
);
785 content_pane
->SetLayoutManager(content_layout
);
786 views::ColumnSet
* content_column_set
= content_layout
->AddColumnSet(0);
787 content_column_set
->AddColumn(views::GridLayout::LEADING
,
788 views::GridLayout::LEADING
,
790 views::GridLayout::USE_PREF
,
793 if (!headline
.empty()) {
794 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
795 views::Label
* headline_label
= new views::Label(
796 headline
, rb
.GetFontList(ui::ResourceBundle::BoldFont
));
797 headline_label
->SetMultiLine(true);
798 headline_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
799 // Allow linebreaking in the middle of words if necessary, so that extremely
800 // long hostnames (longer than one line) will still be completely shown.
801 headline_label
->SetAllowCharacterBreak(true);
802 content_layout
->StartRow(1, 0);
803 content_layout
->AddView(headline_label
);
806 views::Label
* description_label
= new views::Label(text
);
807 description_label
->SetMultiLine(true);
808 description_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
809 description_label
->SetAllowCharacterBreak(true);
810 content_layout
->StartRow(1, 0);
811 content_layout
->AddView(description_label
);
814 content_layout
->StartRow(1, 0);
815 content_layout
->AddView(link
);
818 if (secondary_link
) {
819 content_layout
->StartRow(1, 0);
820 content_layout
->AddView(secondary_link
);
823 if (reset_decisions_button
) {
824 content_layout
->StartRow(1, 0);
825 content_layout
->AddView(reset_decisions_button
);
828 layout
->AddView(content_pane
, 1, 1, views::GridLayout::LEADING
,
829 views::GridLayout::LEADING
);
830 layout
->AddPaddingRow(0, kConnectionSectionPaddingBottom
);
833 void WebsiteSettingsPopupView::HandleLinkClickedAsync(views::Link
* source
) {
834 if (source
== cookie_dialog_link_
) {
835 // Count how often the Collected Cookies dialog is opened.
836 presenter_
->RecordWebsiteSettingsAction(
837 WebsiteSettings::WEBSITE_SETTINGS_COOKIES_DIALOG_OPENED
);
839 new CollectedCookiesViews(web_contents_
);
840 } else if (source
== certificate_dialog_link_
) {
841 gfx::NativeWindow parent
= GetAnchorView() ?
842 GetAnchorView()->GetWidget()->GetNativeWindow() : nullptr;
843 presenter_
->RecordWebsiteSettingsAction(
844 WebsiteSettings::WEBSITE_SETTINGS_CERTIFICATE_DIALOG_OPENED
);
845 ShowCertificateViewerByID(web_contents_
, parent
, cert_id_
);
846 } else if (source
== signed_certificate_timestamps_link_
) {
847 chrome::ShowSignedCertificateTimestampsViewer(
848 web_contents_
, signed_certificate_timestamp_ids_
);
849 presenter_
->RecordWebsiteSettingsAction(
850 WebsiteSettings::WEBSITE_SETTINGS_TRANSPARENCY_VIEWER_OPENED
);
851 } else if (source
== help_center_link_
) {
853 content::OpenURLParams(GURL(chrome::kPageInfoHelpCenterURL
),
856 ui::PAGE_TRANSITION_LINK
,
858 presenter_
->RecordWebsiteSettingsAction(
859 WebsiteSettings::WEBSITE_SETTINGS_CONNECTION_HELP_OPENED
);
860 } else if (source
== site_settings_link_
) {
861 // TODO(palmer): This opens the general Content Settings pane, which is OK
862 // for now. But on Android, it opens a page specific to a given origin that
863 // shows all of the settings for that origin. If/when that's available on
864 // desktop we should link to that here, too.
865 browser_
->OpenURL(content::OpenURLParams(
866 GURL(chrome::kChromeUIContentSettingsURL
), content::Referrer(),
867 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_LINK
, false));
868 presenter_
->RecordWebsiteSettingsAction(
869 WebsiteSettings::WEBSITE_SETTINGS_SITE_SETTINGS_OPENED
);