• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/i18n/rtl.h"
10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/google/google_util.h"
12 #include "chrome/browser/page_info_model.h"
13 #include "chrome/browser/page_info_window.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h"
16 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
17 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
18 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
19 #include "chrome/browser/ui/gtk/gtk_util.h"
20 #include "chrome/browser/ui/gtk/info_bubble_gtk.h"
21 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/browser/certificate_viewer.h"
24 #include "content/common/notification_observer.h"
25 #include "content/common/notification_registrar.h"
26 #include "content/common/notification_service.h"
27 #include "googleurl/src/gurl.h"
28 #include "grit/generated_resources.h"
29 #include "grit/locale_settings.h"
30 #include "ui/base/l10n/l10n_util.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   GtkThemeService* theme_service_;
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 
PageInfoBubbleGtk(gfx::NativeWindow parent,Profile * profile,const GURL & url,const NavigationEntry::SSLStatus & ssl,bool show_history)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_service_(GtkThemeService::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_service_,
135                                 this);  // |delegate|
136   if (!bubble_) {
137     NOTREACHED();
138     return;
139   }
140 }
141 
~PageInfoBubbleGtk()142 PageInfoBubbleGtk::~PageInfoBubbleGtk() {
143 }
144 
ModelChanged()145 void PageInfoBubbleGtk::ModelChanged() {
146   InitContents();
147 }
148 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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_service_->UseGtkTheme());
159   }
160 
161   if (theme_service_->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, &gtk_util::kGdkBlack);
170     }
171   }
172 }
173 
InfoBubbleClosing(InfoBubbleGtk * info_bubble,bool closed_by_escape)174 void PageInfoBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
175                                           bool closed_by_escape) {
176   delete this;
177 }
178 
InitContents()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_service_->InitThemesFor(this);
210   gtk_widget_show_all(contents_);
211 }
212 
CreateSection(const PageInfoModel::SectionInfo & section)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     gtk_label_set_selectable(GTK_LABEL(label), TRUE);
230     labels_.push_back(label);
231     PangoAttrList* attributes = pango_attr_list_new();
232     pango_attr_list_insert(attributes,
233                            pango_attr_weight_new(PANGO_WEIGHT_BOLD));
234     gtk_label_set_attributes(GTK_LABEL(label), attributes);
235     pango_attr_list_unref(attributes);
236     gtk_util::SetLabelWidth(label, 400);
237     // Allow linebreaking in the middle of words if necessary, so that extremely
238     // long hostnames (longer than one line) will still be completely shown.
239     gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
240     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
241   }
242   GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.description).c_str());
243   gtk_label_set_selectable(GTK_LABEL(label), TRUE);
244   labels_.push_back(label);
245   gtk_util::SetLabelWidth(label, 400);
246   // Allow linebreaking in the middle of words if necessary, so that extremely
247   // long hostnames (longer than one line) will still be completely shown.
248   gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
249   gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
250 
251   if (section.type == PageInfoModel::SECTION_INFO_IDENTITY && cert_id_ > 0) {
252     GtkWidget* view_cert_link = gtk_chrome_link_button_new(
253         l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str());
254     links_.push_back(view_cert_link);
255     GtkWidget* cert_link_hbox = gtk_hbox_new(FALSE, 0);
256     // Stick it in an hbox so it doesn't expand to the whole width.
257     gtk_box_pack_start(GTK_BOX(cert_link_hbox), view_cert_link,
258                        FALSE, FALSE, 0);
259     gtk_box_pack_start(GTK_BOX(vbox), cert_link_hbox, FALSE, FALSE, 0);
260     g_signal_connect(view_cert_link, "clicked",
261                      G_CALLBACK(OnViewCertLinkClickedThunk), this);
262   }
263 
264   return section_box;
265 }
266 
OnViewCertLinkClicked(GtkWidget * widget)267 void PageInfoBubbleGtk::OnViewCertLinkClicked(GtkWidget* widget) {
268   ShowCertificateViewerByID(GTK_WINDOW(parent_), cert_id_);
269   bubble_->Close();
270 }
271 
OnHelpLinkClicked(GtkWidget * widget)272 void PageInfoBubbleGtk::OnHelpLinkClicked(GtkWidget* widget) {
273   GURL url = google_util::AppendGoogleLocaleParam(
274       GURL(chrome::kPageInfoHelpCenterURL));
275   Browser* browser = BrowserList::GetLastActive();
276   browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
277   bubble_->Close();
278 }
279 
280 }  // namespace
281 
282 namespace browser {
283 
ShowPageInfoBubble(gfx::NativeWindow parent,Profile * profile,const GURL & url,const NavigationEntry::SSLStatus & ssl,bool show_history)284 void ShowPageInfoBubble(gfx::NativeWindow parent,
285                         Profile* profile,
286                         const GURL& url,
287                         const NavigationEntry::SSLStatus& ssl,
288                         bool show_history) {
289   new PageInfoBubbleGtk(parent, profile, url, ssl, show_history);
290 }
291 
292 }  // namespace browser
293