Index: chrome/browser/gtk/page_info_bubble_gtk.cc |
diff --git a/chrome/browser/gtk/page_info_bubble_gtk.cc b/chrome/browser/gtk/page_info_bubble_gtk.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c47ac519957912aac90efe2d67f8d4091d670bd6 |
--- /dev/null |
+++ b/chrome/browser/gtk/page_info_bubble_gtk.cc |
@@ -0,0 +1,311 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <gtk/gtk.h> |
+ |
+#include "build/build_config.h" |
+ |
+#include "app/l10n_util.h" |
+#include "app/resource_bundle.h" |
+#include "base/i18n/rtl.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/browser_list.h" |
+#include "chrome/browser/certificate_viewer.h" |
+#include "chrome/browser/gtk/browser_toolbar_gtk.h" |
+#include "chrome/browser/gtk/browser_window_gtk.h" |
+#include "chrome/browser/gtk/gtk_chrome_link_button.h" |
+#include "chrome/browser/gtk/gtk_theme_provider.h" |
+#include "chrome/browser/gtk/gtk_util.h" |
+#include "chrome/browser/gtk/info_bubble_gtk.h" |
+#include "chrome/browser/gtk/location_bar_view_gtk.h" |
+#include "chrome/browser/page_info_model.h" |
+#include "chrome/browser/page_info_window.h" |
+#include "chrome/common/notification_observer.h" |
+#include "chrome/common/notification_registrar.h" |
+#include "chrome/common/notification_service.h" |
+#include "gfx/gtk_util.h" |
+#include "googleurl/src/gurl.h" |
+#include "grit/generated_resources.h" |
+#include "grit/locale_settings.h" |
+#include "grit/theme_resources.h" |
+ |
+class Profile; |
+ |
+namespace { |
+ |
+class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, |
+ public InfoBubbleGtkDelegate, |
+ public NotificationObserver { |
+ public: |
+ PageInfoBubbleGtk(gfx::NativeWindow parent, |
+ Profile* profile, |
+ const GURL& url, |
+ const NavigationEntry::SSLStatus& ssl, |
+ bool show_history); |
+ virtual ~PageInfoBubbleGtk(); |
+ |
+ // PageInfoModelObserver implementation: |
+ virtual void ModelChanged(); |
+ |
+ // NotificationObserver implementation: |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details); |
+ |
+ // InfoBubbleGtkDelegate implementation: |
+ virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, |
+ bool closed_by_escape); |
+ |
+ private: |
+ // Layouts the different sections retrieved from the model. |
+ void InitContents(); |
+ |
+ // Returns a widget that contains the UI for the passed |section|. |
+ GtkWidget* CreateSection(const PageInfoModel::SectionInfo& section); |
+ |
+ // Link button callbacks. |
+ CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnViewCertLinkClicked); |
+ CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnHelpLinkClicked); |
+ |
+ // The model containing the different sections to display. |
+ PageInfoModel model_; |
+ |
+ // The url for this dialog. Should be unique among active dialogs. |
+ GURL url_; |
+ |
+ // The id of the certificate for this page. |
+ int cert_id_; |
+ |
+ // Parent window. |
+ GtkWindow* parent_; |
+ |
+ // The virtual box containing the sections. |
+ GtkWidget* contents_; |
+ |
+ // The widget relative to which we are positioned. |
+ GtkWidget* anchor_; |
+ |
+ // Provides colors and stuff. |
+ GtkThemeProvider* theme_provider_; |
+ |
+ // The various elements in the interface we keep track of for theme changes. |
+ std::vector<GtkWidget*> labels_; |
+ std::vector<GtkWidget*> links_; |
+ |
+ InfoBubbleGtk* bubble_; |
+ |
+ NotificationRegistrar registrar_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PageInfoBubbleGtk); |
+}; |
+ |
+PageInfoBubbleGtk::PageInfoBubbleGtk(gfx::NativeWindow parent, |
+ Profile* profile, |
+ const GURL& url, |
+ const NavigationEntry::SSLStatus& ssl, |
+ bool show_history) |
+ : ALLOW_THIS_IN_INITIALIZER_LIST(model_(profile, url, ssl, |
+ show_history, this)), |
+ url_(url), |
+ cert_id_(ssl.cert_id()), |
+ parent_(parent), |
+ contents_(NULL), |
+ theme_provider_(GtkThemeProvider::GetFrom(profile)) { |
+ BrowserWindowGtk* browser_window = |
+ BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent); |
+ |
+ anchor_ = browser_window-> |
+ GetToolbar()->GetLocationBarView()->location_icon_widget(); |
+ |
+ registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
+ NotificationService::AllSources()); |
+ |
+ InitContents(); |
+ |
+ InfoBubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? |
+ InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : |
+ InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; |
+ bubble_ = InfoBubbleGtk::Show(anchor_, |
+ NULL, // |rect| |
+ contents_, |
+ arrow_location, |
+ true, // |match_system_theme| |
+ true, // |grab_input| |
+ theme_provider_, |
+ this); // |delegate| |
+ if (!bubble_) { |
+ NOTREACHED(); |
+ return; |
+ } |
+} |
+ |
+PageInfoBubbleGtk::~PageInfoBubbleGtk() { |
+} |
+ |
+void PageInfoBubbleGtk::ModelChanged() { |
+ InitContents(); |
+} |
+ |
+void PageInfoBubbleGtk::Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); |
+ |
+ for (std::vector<GtkWidget*>::iterator it = links_.begin(); |
+ it != links_.end(); ++it) { |
+ gtk_chrome_link_button_set_use_gtk_theme( |
+ GTK_CHROME_LINK_BUTTON(*it), |
+ theme_provider_->UseGtkTheme()); |
+ } |
+ |
+ if (theme_provider_->UseGtkTheme()) { |
+ for (std::vector<GtkWidget*>::iterator it = labels_.begin(); |
+ it != labels_.end(); ++it) { |
+ gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, NULL); |
+ } |
+ } else { |
+ for (std::vector<GtkWidget*>::iterator it = labels_.begin(); |
+ it != labels_.end(); ++it) { |
+ gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, &gfx::kGdkBlack); |
+ } |
+ } |
+} |
+ |
+void PageInfoBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, |
+ bool closed_by_escape) { |
+ delete this; |
+} |
+ |
+void PageInfoBubbleGtk::InitContents() { |
+ if (!contents_) { |
+ contents_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); |
+ gtk_container_set_border_width(GTK_CONTAINER(contents_), |
+ gtk_util::kContentAreaBorder); |
+ } else { |
+ labels_.clear(); |
+ links_.clear(); |
+ gtk_util::RemoveAllChildren(contents_); |
+ } |
+ |
+ for (int i = 0; i < model_.GetSectionCount(); i++) { |
+ gtk_box_pack_start(GTK_BOX(contents_), |
+ CreateSection(model_.GetSectionInfo(i)), |
+ FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(contents_), |
+ gtk_hseparator_new(), |
+ FALSE, FALSE, 0); |
+ } |
+ |
+ GtkWidget* help_link = gtk_chrome_link_button_new( |
+ l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK).c_str()); |
+ links_.push_back(help_link); |
+ GtkWidget* help_link_hbox = gtk_hbox_new(FALSE, 0); |
+ // Stick it in an hbox so it doesn't expand to the whole width. |
+ gtk_box_pack_start(GTK_BOX(help_link_hbox), help_link, TRUE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(contents_), help_link_hbox, FALSE, FALSE, 0); |
+ g_signal_connect(help_link, "clicked", |
+ G_CALLBACK(OnHelpLinkClickedThunk), this); |
+ |
+ theme_provider_->InitThemesFor(this); |
+ gtk_widget_show_all(contents_); |
+} |
+ |
+GtkWidget* PageInfoBubbleGtk::CreateSection( |
+ const PageInfoModel::SectionInfo& section) { |
+ GtkWidget* section_box = gtk_hbox_new(FALSE, 0); |
+ |
+ if (section.type == PageInfoModel::SECTION_INFO_IDENTITY || |
+ section.type == PageInfoModel::SECTION_INFO_CONNECTION) { |
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
+ GdkPixbuf* pixbuf = NULL; |
+ switch (section.state) { |
+ case PageInfoModel::SECTION_STATE_OK: |
+ pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_GOOD); |
+ break; |
+ case PageInfoModel::SECTION_STATE_WARNING: |
+ DCHECK(section.type == PageInfoModel::SECTION_INFO_CONNECTION); |
+ pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_MIXED); |
+ break; |
+ case PageInfoModel::SECTION_STATE_ERROR: |
+ pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_BAD); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); |
+ gtk_box_pack_start(GTK_BOX(section_box), image, FALSE, FALSE, |
+ gtk_util::kControlSpacing); |
+ gtk_misc_set_alignment(GTK_MISC(image), 0, 0); |
+ } |
+ |
+ GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |
+ gtk_box_pack_start(GTK_BOX(section_box), vbox, TRUE, TRUE, 0); |
+ |
+ if (!section.headline.empty()) { |
+ GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.headline).c_str()); |
+ labels_.push_back(label); |
+ PangoAttrList* attributes = pango_attr_list_new(); |
+ pango_attr_list_insert(attributes, |
+ pango_attr_weight_new(PANGO_WEIGHT_BOLD)); |
+ gtk_label_set_attributes(GTK_LABEL(label), attributes); |
+ pango_attr_list_unref(attributes); |
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
+ // Allow linebreaking in the middle of words if necessary, so that extremely |
+ // long hostnames (longer than one line) will still be completely shown. |
+ gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); |
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); |
+ gtk_widget_set_size_request(label, 400, -1); |
+ } |
+ GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.description).c_str()); |
+ labels_.push_back(label); |
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
+ // Allow linebreaking in the middle of words if necessary, so that extremely |
+ // long hostnames (longer than one line) will still be completely shown. |
+ gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); |
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); |
+ gtk_widget_set_size_request(label, 400, -1); |
+ |
+ if (section.type == PageInfoModel::SECTION_INFO_IDENTITY && cert_id_ > 0) { |
+ GtkWidget* view_cert_link = gtk_chrome_link_button_new( |
+ l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str()); |
+ links_.push_back(view_cert_link); |
+ GtkWidget* cert_link_hbox = gtk_hbox_new(FALSE, 0); |
+ // Stick it in an hbox so it doesn't expand to the whole width. |
+ gtk_box_pack_start(GTK_BOX(cert_link_hbox), view_cert_link, |
+ FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(vbox), cert_link_hbox, FALSE, FALSE, 0); |
+ g_signal_connect(view_cert_link, "clicked", |
+ G_CALLBACK(OnViewCertLinkClickedThunk), this); |
+ } |
+ |
+ return section_box; |
+} |
+ |
+void PageInfoBubbleGtk::OnViewCertLinkClicked(GtkWidget* widget) { |
+ ShowCertificateViewerByID(GTK_WINDOW(parent_), cert_id_); |
+ bubble_->Close(); |
+} |
+ |
+void PageInfoBubbleGtk::OnHelpLinkClicked(GtkWidget* widget) { |
+ GURL url = GURL(l10n_util::GetStringUTF16(IDS_PAGE_INFO_HELP_CENTER)); |
+ Browser* browser = BrowserList::GetLastActive(); |
+ browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
+ bubble_->Close(); |
+} |
+ |
+} // namespace |
+ |
+namespace browser { |
+ |
+void ShowPageInfoBubble(gfx::NativeWindow parent, |
+ Profile* profile, |
+ const GURL& url, |
+ const NavigationEntry::SSLStatus& ssl, |
+ bool show_history) { |
+ new PageInfoBubbleGtk(parent, profile, url, ssl, show_history); |
+} |
+ |
+} // namespace browser |