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