website_settings_popup_view.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
53namespace {
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.
61bool is_popup_showing = false;
62
63// Padding values for sections on the connection tab.
64const int kConnectionSectionPaddingBottom = 16;
65const int kConnectionSectionPaddingLeft = 18;
66const int kConnectionSectionPaddingTop = 16;
67const 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.
71const SkColor kIdentityVerifiedTextColor = 0xFF298a27;
72
73// Left icon margin.
74const int kIconMarginLeft = 6;
75
76// Margin and padding values for the |PopupHeaderView|.
77const int kHeaderMarginBottom = 10;
78const int kHeaderPaddingBottom = 12;
79const int kHeaderPaddingLeft = 18;
80const int kHeaderPaddingRight = 8;
81const int kHeaderPaddingTop = 12;
82
83// Spacing between the site identity label and the site identity status text in
84// the popup header.
85const 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.
89const int kLocationIconVerticalMargin = 5;
90
91// The max possible width of the popup.
92const int kMaxPopupWidth = 500;
93
94// The margins between the popup border and the popup content.
95const int kPopupMarginTop = 4;
96const int kPopupMarginLeft = 0;
97const int kPopupMarginBottom = 10;
98const int kPopupMarginRight = 0;
99
100// Padding values for sections on the permissions tab.
101const int kPermissionsSectionContentMinWidth = 300;
102const int kPermissionsSectionPaddingBottom = 6;
103const int kPermissionsSectionPaddingLeft = 18;
104const int kPermissionsSectionPaddingTop = 16;
105
106// Space between the headline and the content of a section on the permissions
107// tab.
108const 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.
112const int kPermissionsSectionRowSpacing = 2;
113
114const int kSiteDataIconColumnWidth = 20;
115const 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.
122class 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.
146class 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
162PopupHeaderView::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
217PopupHeaderView::~PopupHeaderView() {
218}
219
220void PopupHeaderView::SetIdentityName(const base::string16& name) {
221  name_->SetText(name);
222}
223
224void 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
234InternalPageInfoPopupView::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
259InternalPageInfoPopupView::~InternalPageInfoPopupView() {
260}
261
262void InternalPageInfoPopupView::OnWidgetDestroying(views::Widget* widget) {
263  is_popup_showing = false;
264}
265
266////////////////////////////////////////////////////////////////////////////////
267// WebsiteSettingsPopupView
268////////////////////////////////////////////////////////////////////////////////
269
270WebsiteSettingsPopupView::~WebsiteSettingsPopupView() {
271}
272
273// static
274void 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
290bool WebsiteSettingsPopupView::IsPopupShowing() {
291  return is_popup_showing;
292}
293
294WebsiteSettingsPopupView::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
372void WebsiteSettingsPopupView::OnPermissionChanged(
373    const WebsiteSettingsUI::PermissionInfo& permission) {
374  presenter_->OnSitePermissionChanged(permission.type, permission.setting);
375}
376
377void WebsiteSettingsPopupView::OnWidgetDestroying(views::Widget* widget) {
378  is_popup_showing = false;
379  presenter_->OnUIClosing();
380}
381
382void WebsiteSettingsPopupView::ButtonPressed(views::Button* button,
383                                             const ui::Event& event) {
384  if (button == reset_decisions_button_)
385    presenter_->OnRevokeSSLErrorBypassButtonPressed();
386  GetWidget()->Close();
387}
388
389void 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
413void WebsiteSettingsPopupView::TabSelectedAt(int index) {
414  tabbed_pane_->GetSelectedTab()->Layout();
415  SizeToContents();
416}
417
418gfx::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
439void 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
492void 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
528void 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
607void 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
622void WebsiteSettingsPopupView::SetSelectedTab(TabId tab_id) {
623  tabbed_pane_->SelectTabAt(tab_id);
624}
625
626views::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
652views::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
687views::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
728void 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