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