OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 <gtk/gtk.h> |
| 6 |
| 7 #include "build/build_config.h" |
| 8 |
| 9 #include "app/l10n_util.h" |
| 10 #include "app/resource_bundle.h" |
| 11 #include "base/i18n/rtl.h" |
| 12 #include "base/utf_string_conversions.h" |
| 13 #include "chrome/browser/browser_list.h" |
| 14 #include "chrome/browser/certificate_viewer.h" |
| 15 #include "chrome/browser/gtk/browser_toolbar_gtk.h" |
| 16 #include "chrome/browser/gtk/browser_window_gtk.h" |
| 17 #include "chrome/browser/gtk/gtk_chrome_link_button.h" |
| 18 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 19 #include "chrome/browser/gtk/gtk_util.h" |
| 20 #include "chrome/browser/gtk/info_bubble_gtk.h" |
| 21 #include "chrome/browser/gtk/location_bar_view_gtk.h" |
| 22 #include "chrome/browser/page_info_model.h" |
| 23 #include "chrome/browser/page_info_window.h" |
| 24 #include "chrome/common/notification_observer.h" |
| 25 #include "chrome/common/notification_registrar.h" |
| 26 #include "chrome/common/notification_service.h" |
| 27 #include "gfx/gtk_util.h" |
| 28 #include "googleurl/src/gurl.h" |
| 29 #include "grit/generated_resources.h" |
| 30 #include "grit/locale_settings.h" |
| 31 #include "grit/theme_resources.h" |
| 32 |
| 33 class Profile; |
| 34 |
| 35 namespace { |
| 36 |
| 37 class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, |
| 38 public InfoBubbleGtkDelegate, |
| 39 public NotificationObserver { |
| 40 public: |
| 41 PageInfoBubbleGtk(gfx::NativeWindow parent, |
| 42 Profile* profile, |
| 43 const GURL& url, |
| 44 const NavigationEntry::SSLStatus& ssl, |
| 45 bool show_history); |
| 46 virtual ~PageInfoBubbleGtk(); |
| 47 |
| 48 // PageInfoModelObserver implementation: |
| 49 virtual void ModelChanged(); |
| 50 |
| 51 // NotificationObserver implementation: |
| 52 virtual void Observe(NotificationType type, |
| 53 const NotificationSource& source, |
| 54 const NotificationDetails& details); |
| 55 |
| 56 // InfoBubbleGtkDelegate implementation: |
| 57 virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, |
| 58 bool closed_by_escape); |
| 59 |
| 60 private: |
| 61 // Layouts the different sections retrieved from the model. |
| 62 void InitContents(); |
| 63 |
| 64 // Returns a widget that contains the UI for the passed |section|. |
| 65 GtkWidget* CreateSection(const PageInfoModel::SectionInfo& section); |
| 66 |
| 67 // Link button callbacks. |
| 68 CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnViewCertLinkClicked); |
| 69 CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnHelpLinkClicked); |
| 70 |
| 71 // The model containing the different sections to display. |
| 72 PageInfoModel model_; |
| 73 |
| 74 // The url for this dialog. Should be unique among active dialogs. |
| 75 GURL url_; |
| 76 |
| 77 // The id of the certificate for this page. |
| 78 int cert_id_; |
| 79 |
| 80 // Parent window. |
| 81 GtkWindow* parent_; |
| 82 |
| 83 // The virtual box containing the sections. |
| 84 GtkWidget* contents_; |
| 85 |
| 86 // The widget relative to which we are positioned. |
| 87 GtkWidget* anchor_; |
| 88 |
| 89 // Provides colors and stuff. |
| 90 GtkThemeProvider* theme_provider_; |
| 91 |
| 92 // The various elements in the interface we keep track of for theme changes. |
| 93 std::vector<GtkWidget*> labels_; |
| 94 std::vector<GtkWidget*> links_; |
| 95 |
| 96 InfoBubbleGtk* bubble_; |
| 97 |
| 98 NotificationRegistrar registrar_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(PageInfoBubbleGtk); |
| 101 }; |
| 102 |
| 103 PageInfoBubbleGtk::PageInfoBubbleGtk(gfx::NativeWindow parent, |
| 104 Profile* profile, |
| 105 const GURL& url, |
| 106 const NavigationEntry::SSLStatus& ssl, |
| 107 bool show_history) |
| 108 : ALLOW_THIS_IN_INITIALIZER_LIST(model_(profile, url, ssl, |
| 109 show_history, this)), |
| 110 url_(url), |
| 111 cert_id_(ssl.cert_id()), |
| 112 parent_(parent), |
| 113 contents_(NULL), |
| 114 theme_provider_(GtkThemeProvider::GetFrom(profile)) { |
| 115 BrowserWindowGtk* browser_window = |
| 116 BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent); |
| 117 |
| 118 anchor_ = browser_window-> |
| 119 GetToolbar()->GetLocationBarView()->location_icon_widget(); |
| 120 |
| 121 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
| 122 NotificationService::AllSources()); |
| 123 |
| 124 InitContents(); |
| 125 |
| 126 InfoBubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? |
| 127 InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : |
| 128 InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; |
| 129 bubble_ = InfoBubbleGtk::Show(anchor_, |
| 130 NULL, // |rect| |
| 131 contents_, |
| 132 arrow_location, |
| 133 true, // |match_system_theme| |
| 134 true, // |grab_input| |
| 135 theme_provider_, |
| 136 this); // |delegate| |
| 137 if (!bubble_) { |
| 138 NOTREACHED(); |
| 139 return; |
| 140 } |
| 141 } |
| 142 |
| 143 PageInfoBubbleGtk::~PageInfoBubbleGtk() { |
| 144 } |
| 145 |
| 146 void PageInfoBubbleGtk::ModelChanged() { |
| 147 InitContents(); |
| 148 } |
| 149 |
| 150 void PageInfoBubbleGtk::Observe(NotificationType type, |
| 151 const NotificationSource& source, |
| 152 const NotificationDetails& details) { |
| 153 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); |
| 154 |
| 155 for (std::vector<GtkWidget*>::iterator it = links_.begin(); |
| 156 it != links_.end(); ++it) { |
| 157 gtk_chrome_link_button_set_use_gtk_theme( |
| 158 GTK_CHROME_LINK_BUTTON(*it), |
| 159 theme_provider_->UseGtkTheme()); |
| 160 } |
| 161 |
| 162 if (theme_provider_->UseGtkTheme()) { |
| 163 for (std::vector<GtkWidget*>::iterator it = labels_.begin(); |
| 164 it != labels_.end(); ++it) { |
| 165 gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, NULL); |
| 166 } |
| 167 } else { |
| 168 for (std::vector<GtkWidget*>::iterator it = labels_.begin(); |
| 169 it != labels_.end(); ++it) { |
| 170 gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, &gfx::kGdkBlack); |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 void PageInfoBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, |
| 176 bool closed_by_escape) { |
| 177 delete this; |
| 178 } |
| 179 |
| 180 void PageInfoBubbleGtk::InitContents() { |
| 181 if (!contents_) { |
| 182 contents_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); |
| 183 gtk_container_set_border_width(GTK_CONTAINER(contents_), |
| 184 gtk_util::kContentAreaBorder); |
| 185 } else { |
| 186 labels_.clear(); |
| 187 links_.clear(); |
| 188 gtk_util::RemoveAllChildren(contents_); |
| 189 } |
| 190 |
| 191 for (int i = 0; i < model_.GetSectionCount(); i++) { |
| 192 gtk_box_pack_start(GTK_BOX(contents_), |
| 193 CreateSection(model_.GetSectionInfo(i)), |
| 194 FALSE, FALSE, 0); |
| 195 gtk_box_pack_start(GTK_BOX(contents_), |
| 196 gtk_hseparator_new(), |
| 197 FALSE, FALSE, 0); |
| 198 } |
| 199 |
| 200 GtkWidget* help_link = gtk_chrome_link_button_new( |
| 201 l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK).c_str()); |
| 202 links_.push_back(help_link); |
| 203 GtkWidget* help_link_hbox = gtk_hbox_new(FALSE, 0); |
| 204 // Stick it in an hbox so it doesn't expand to the whole width. |
| 205 gtk_box_pack_start(GTK_BOX(help_link_hbox), help_link, TRUE, FALSE, 0); |
| 206 gtk_box_pack_start(GTK_BOX(contents_), help_link_hbox, FALSE, FALSE, 0); |
| 207 g_signal_connect(help_link, "clicked", |
| 208 G_CALLBACK(OnHelpLinkClickedThunk), this); |
| 209 |
| 210 theme_provider_->InitThemesFor(this); |
| 211 gtk_widget_show_all(contents_); |
| 212 } |
| 213 |
| 214 GtkWidget* PageInfoBubbleGtk::CreateSection( |
| 215 const PageInfoModel::SectionInfo& section) { |
| 216 GtkWidget* section_box = gtk_hbox_new(FALSE, 0); |
| 217 |
| 218 if (section.type == PageInfoModel::SECTION_INFO_IDENTITY || |
| 219 section.type == PageInfoModel::SECTION_INFO_CONNECTION) { |
| 220 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 221 GdkPixbuf* pixbuf = NULL; |
| 222 switch (section.state) { |
| 223 case PageInfoModel::SECTION_STATE_OK: |
| 224 pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_GOOD); |
| 225 break; |
| 226 case PageInfoModel::SECTION_STATE_WARNING: |
| 227 DCHECK(section.type == PageInfoModel::SECTION_INFO_CONNECTION); |
| 228 pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_MIXED); |
| 229 break; |
| 230 case PageInfoModel::SECTION_STATE_ERROR: |
| 231 pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_BAD); |
| 232 break; |
| 233 default: |
| 234 NOTREACHED(); |
| 235 } |
| 236 GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); |
| 237 gtk_box_pack_start(GTK_BOX(section_box), image, FALSE, FALSE, |
| 238 gtk_util::kControlSpacing); |
| 239 gtk_misc_set_alignment(GTK_MISC(image), 0, 0); |
| 240 } |
| 241 |
| 242 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |
| 243 gtk_box_pack_start(GTK_BOX(section_box), vbox, TRUE, TRUE, 0); |
| 244 |
| 245 if (!section.headline.empty()) { |
| 246 GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.headline).c_str()); |
| 247 labels_.push_back(label); |
| 248 PangoAttrList* attributes = pango_attr_list_new(); |
| 249 pango_attr_list_insert(attributes, |
| 250 pango_attr_weight_new(PANGO_WEIGHT_BOLD)); |
| 251 gtk_label_set_attributes(GTK_LABEL(label), attributes); |
| 252 pango_attr_list_unref(attributes); |
| 253 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
| 254 // Allow linebreaking in the middle of words if necessary, so that extremely |
| 255 // long hostnames (longer than one line) will still be completely shown. |
| 256 gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); |
| 257 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
| 258 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); |
| 259 gtk_widget_set_size_request(label, 400, -1); |
| 260 } |
| 261 GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.description).c_str()); |
| 262 labels_.push_back(label); |
| 263 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
| 264 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |
| 265 // Allow linebreaking in the middle of words if necessary, so that extremely |
| 266 // long hostnames (longer than one line) will still be completely shown. |
| 267 gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); |
| 268 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); |
| 269 gtk_widget_set_size_request(label, 400, -1); |
| 270 |
| 271 if (section.type == PageInfoModel::SECTION_INFO_IDENTITY && cert_id_ > 0) { |
| 272 GtkWidget* view_cert_link = gtk_chrome_link_button_new( |
| 273 l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str()); |
| 274 links_.push_back(view_cert_link); |
| 275 GtkWidget* cert_link_hbox = gtk_hbox_new(FALSE, 0); |
| 276 // Stick it in an hbox so it doesn't expand to the whole width. |
| 277 gtk_box_pack_start(GTK_BOX(cert_link_hbox), view_cert_link, |
| 278 FALSE, FALSE, 0); |
| 279 gtk_box_pack_start(GTK_BOX(vbox), cert_link_hbox, FALSE, FALSE, 0); |
| 280 g_signal_connect(view_cert_link, "clicked", |
| 281 G_CALLBACK(OnViewCertLinkClickedThunk), this); |
| 282 } |
| 283 |
| 284 return section_box; |
| 285 } |
| 286 |
| 287 void PageInfoBubbleGtk::OnViewCertLinkClicked(GtkWidget* widget) { |
| 288 ShowCertificateViewerByID(GTK_WINDOW(parent_), cert_id_); |
| 289 bubble_->Close(); |
| 290 } |
| 291 |
| 292 void PageInfoBubbleGtk::OnHelpLinkClicked(GtkWidget* widget) { |
| 293 GURL url = GURL(l10n_util::GetStringUTF16(IDS_PAGE_INFO_HELP_CENTER)); |
| 294 Browser* browser = BrowserList::GetLastActive(); |
| 295 browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
| 296 bubble_->Close(); |
| 297 } |
| 298 |
| 299 } // namespace |
| 300 |
| 301 namespace browser { |
| 302 |
| 303 void ShowPageInfoBubble(gfx::NativeWindow parent, |
| 304 Profile* profile, |
| 305 const GURL& url, |
| 306 const NavigationEntry::SSLStatus& ssl, |
| 307 bool show_history) { |
| 308 new PageInfoBubbleGtk(parent, profile, url, ssl, show_history); |
| 309 } |
| 310 |
| 311 } // namespace browser |
OLD | NEW |