| 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 "chrome/browser/gtk/content_setting_bubble_gtk.h" |  | 
| 6 |  | 
| 7 #include <set> |  | 
| 8 #include <string> |  | 
| 9 #include <vector> |  | 
| 10 |  | 
| 11 #include "app/l10n_util.h" |  | 
| 12 #include "app/text_elider.h" |  | 
| 13 #include "base/i18n/rtl.h" |  | 
| 14 #include "base/utf_string_conversions.h" |  | 
| 15 #include "chrome/browser/blocked_content_container.h" |  | 
| 16 #include "chrome/browser/content_settings/host_content_settings_map.h" |  | 
| 17 #include "chrome/browser/content_setting_bubble_model.h" |  | 
| 18 #include "chrome/browser/gtk/gtk_chrome_link_button.h" |  | 
| 19 #include "chrome/browser/gtk/gtk_theme_provider.h" |  | 
| 20 #include "chrome/browser/gtk/gtk_util.h" |  | 
| 21 #include "chrome/browser/gtk/options/content_settings_window_gtk.h" |  | 
| 22 #include "chrome/browser/profiles/profile.h" |  | 
| 23 #include "chrome/browser/tab_contents/tab_contents.h" |  | 
| 24 #include "chrome/common/content_settings.h" |  | 
| 25 #include "chrome/common/notification_source.h" |  | 
| 26 #include "chrome/common/notification_type.h" |  | 
| 27 #include "gfx/gtk_util.h" |  | 
| 28 #include "grit/app_resources.h" |  | 
| 29 #include "grit/generated_resources.h" |  | 
| 30 #include "webkit/plugins/npapi/plugin_list.h" |  | 
| 31 |  | 
| 32 namespace { |  | 
| 33 |  | 
| 34 // Padding between content and edge of info bubble. |  | 
| 35 const int kContentBorder = 7; |  | 
| 36 |  | 
| 37 // The maximum width of a title entry in the content box. We elide anything |  | 
| 38 // longer than this. |  | 
| 39 const int kMaxLinkPixelSize = 500; |  | 
| 40 |  | 
| 41 std::string BuildElidedText(const std::string& input) { |  | 
| 42   return UTF16ToUTF8(gfx::ElideText( |  | 
| 43       UTF8ToUTF16(input), |  | 
| 44       gfx::Font(), |  | 
| 45       kMaxLinkPixelSize, |  | 
| 46       false)); |  | 
| 47 } |  | 
| 48 |  | 
| 49 }  // namespace |  | 
| 50 |  | 
| 51 ContentSettingBubbleGtk::ContentSettingBubbleGtk( |  | 
| 52     GtkWidget* anchor, |  | 
| 53     InfoBubbleGtkDelegate* delegate, |  | 
| 54     ContentSettingBubbleModel* content_setting_bubble_model, |  | 
| 55     Profile* profile, |  | 
| 56     TabContents* tab_contents) |  | 
| 57     : anchor_(anchor), |  | 
| 58       profile_(profile), |  | 
| 59       tab_contents_(tab_contents), |  | 
| 60       delegate_(delegate), |  | 
| 61       content_setting_bubble_model_(content_setting_bubble_model), |  | 
| 62       info_bubble_(NULL) { |  | 
| 63   registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, |  | 
| 64                  Source<TabContents>(tab_contents)); |  | 
| 65   BuildBubble(); |  | 
| 66 } |  | 
| 67 |  | 
| 68 ContentSettingBubbleGtk::~ContentSettingBubbleGtk() { |  | 
| 69 } |  | 
| 70 |  | 
| 71 void ContentSettingBubbleGtk::Close() { |  | 
| 72   if (info_bubble_) |  | 
| 73     info_bubble_->Close(); |  | 
| 74 } |  | 
| 75 |  | 
| 76 void ContentSettingBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, |  | 
| 77                                                 bool closed_by_escape) { |  | 
| 78   delegate_->InfoBubbleClosing(info_bubble, closed_by_escape); |  | 
| 79   delete this; |  | 
| 80 } |  | 
| 81 |  | 
| 82 void ContentSettingBubbleGtk::Observe(NotificationType type, |  | 
| 83                                       const NotificationSource& source, |  | 
| 84                                       const NotificationDetails& details) { |  | 
| 85   DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED); |  | 
| 86   DCHECK(source == Source<TabContents>(tab_contents_)); |  | 
| 87   tab_contents_ = NULL; |  | 
| 88 } |  | 
| 89 |  | 
| 90 void ContentSettingBubbleGtk::BuildBubble() { |  | 
| 91   GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(profile_); |  | 
| 92 |  | 
| 93   GtkWidget* bubble_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |  | 
| 94   gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder); |  | 
| 95 |  | 
| 96   const ContentSettingBubbleModel::BubbleContent& content = |  | 
| 97       content_setting_bubble_model_->bubble_content(); |  | 
| 98   if (!content.title.empty()) { |  | 
| 99     // Add the content label. |  | 
| 100     GtkWidget* label = gtk_label_new(content.title.c_str()); |  | 
| 101     gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |  | 
| 102     gtk_box_pack_start(GTK_BOX(bubble_content), label, FALSE, FALSE, 0); |  | 
| 103   } |  | 
| 104 |  | 
| 105   const std::set<std::string>& plugins = content.resource_identifiers; |  | 
| 106   if (!plugins.empty()) { |  | 
| 107     GtkWidget* list_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |  | 
| 108 |  | 
| 109     for (std::set<std::string>::const_iterator it = plugins.begin(); |  | 
| 110         it != plugins.end(); ++it) { |  | 
| 111       std::string name = UTF16ToUTF8( |  | 
| 112           webkit::npapi::PluginList::Singleton()->GetPluginGroupName(*it)); |  | 
| 113       if (name.empty()) |  | 
| 114         name = *it; |  | 
| 115 |  | 
| 116       GtkWidget* label = gtk_label_new(BuildElidedText(name).c_str()); |  | 
| 117       GtkWidget* label_box = gtk_hbox_new(FALSE, 0); |  | 
| 118       gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 0); |  | 
| 119 |  | 
| 120       gtk_box_pack_start(GTK_BOX(list_content), |  | 
| 121                          label_box, |  | 
| 122                          FALSE, FALSE, 0); |  | 
| 123     } |  | 
| 124     gtk_box_pack_start(GTK_BOX(bubble_content), list_content, FALSE, FALSE, |  | 
| 125                        gtk_util::kControlSpacing); |  | 
| 126   } |  | 
| 127 |  | 
| 128   if (content_setting_bubble_model_->content_type() == |  | 
| 129       CONTENT_SETTINGS_TYPE_POPUPS) { |  | 
| 130     const std::vector<ContentSettingBubbleModel::PopupItem>& popup_items = |  | 
| 131         content.popup_items; |  | 
| 132     GtkWidget* table = gtk_table_new(popup_items.size(), 2, FALSE); |  | 
| 133     int row = 0; |  | 
| 134     for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator |  | 
| 135          i(popup_items.begin()); i != popup_items.end(); ++i, ++row) { |  | 
| 136       GtkWidget* image = gtk_image_new(); |  | 
| 137       if (!i->bitmap.empty()) { |  | 
| 138         GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&i->bitmap); |  | 
| 139         gtk_image_set_from_pixbuf(GTK_IMAGE(image), icon_pixbuf); |  | 
| 140         g_object_unref(icon_pixbuf); |  | 
| 141 |  | 
| 142         // We stuff the image in an event box so we can trap mouse clicks on the |  | 
| 143         // image (and launch the popup). |  | 
| 144         GtkWidget* event_box = gtk_event_box_new(); |  | 
| 145         gtk_container_add(GTK_CONTAINER(event_box), image); |  | 
| 146 |  | 
| 147         popup_icons_[event_box] = i -popup_items.begin(); |  | 
| 148         g_signal_connect(event_box, "button_press_event", |  | 
| 149                          G_CALLBACK(OnPopupIconButtonPressThunk), this); |  | 
| 150         gtk_table_attach(GTK_TABLE(table), event_box, 0, 1, row, row + 1, |  | 
| 151                          GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2, |  | 
| 152                          gtk_util::kControlSpacing / 2); |  | 
| 153       } |  | 
| 154 |  | 
| 155       GtkWidget* button = gtk_chrome_link_button_new( |  | 
| 156           BuildElidedText(i->title).c_str()); |  | 
| 157       popup_links_[button] = i -popup_items.begin(); |  | 
| 158       g_signal_connect(button, "clicked", G_CALLBACK(OnPopupLinkClickedThunk), |  | 
| 159                        this); |  | 
| 160       gtk_table_attach(GTK_TABLE(table), button, 1, 2, row, row + 1, |  | 
| 161                        GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2, |  | 
| 162                        gtk_util::kControlSpacing / 2); |  | 
| 163     } |  | 
| 164 |  | 
| 165     gtk_box_pack_start(GTK_BOX(bubble_content), table, FALSE, FALSE, 0); |  | 
| 166   } |  | 
| 167 |  | 
| 168   if (content_setting_bubble_model_->content_type() != |  | 
| 169       CONTENT_SETTINGS_TYPE_COOKIES) { |  | 
| 170     const ContentSettingBubbleModel::RadioGroup& radio_group = |  | 
| 171         content.radio_group; |  | 
| 172     for (ContentSettingBubbleModel::RadioItems::const_iterator i = |  | 
| 173          radio_group.radio_items.begin(); |  | 
| 174          i != radio_group.radio_items.end(); ++i) { |  | 
| 175       std::string elided = BuildElidedText(*i); |  | 
| 176       GtkWidget* radio = |  | 
| 177           radio_group_gtk_.empty() ? |  | 
| 178               gtk_radio_button_new_with_label(NULL, elided.c_str()) : |  | 
| 179               gtk_radio_button_new_with_label_from_widget( |  | 
| 180                   GTK_RADIO_BUTTON(radio_group_gtk_[0]), |  | 
| 181                   elided.c_str()); |  | 
| 182       gtk_box_pack_start(GTK_BOX(bubble_content), radio, FALSE, FALSE, 0); |  | 
| 183       if (i - radio_group.radio_items.begin() == radio_group.default_item) { |  | 
| 184         // We must set the default value before we attach the signal handlers |  | 
| 185         // or pain occurs. |  | 
| 186         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); |  | 
| 187       } |  | 
| 188       radio_group_gtk_.push_back(radio); |  | 
| 189     } |  | 
| 190     for (std::vector<GtkWidget*>::const_iterator i = radio_group_gtk_.begin(); |  | 
| 191          i != radio_group_gtk_.end(); ++i) { |  | 
| 192       // We can attach signal handlers now that all defaults are set. |  | 
| 193       g_signal_connect(*i, "toggled", G_CALLBACK(OnRadioToggledThunk), this); |  | 
| 194     } |  | 
| 195   } |  | 
| 196 |  | 
| 197   for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i = |  | 
| 198        content.domain_lists.begin(); |  | 
| 199        i != content.domain_lists.end(); ++i) { |  | 
| 200     // Put each list into its own vbox to allow spacing between lists. |  | 
| 201     GtkWidget* list_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |  | 
| 202 |  | 
| 203     GtkWidget* label = gtk_label_new(BuildElidedText(i->title).c_str()); |  | 
| 204     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); |  | 
| 205     GtkWidget* label_box = gtk_hbox_new(FALSE, 0); |  | 
| 206     gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 0); |  | 
| 207     gtk_box_pack_start(GTK_BOX(list_content), label_box, FALSE, FALSE, 0); |  | 
| 208     for (std::set<std::string>::const_iterator j = i->hosts.begin(); |  | 
| 209          j != i->hosts.end(); ++j) { |  | 
| 210       gtk_box_pack_start(GTK_BOX(list_content), |  | 
| 211                          gtk_util::IndentWidget(gtk_util::CreateBoldLabel(*j)), |  | 
| 212                          FALSE, FALSE, 0); |  | 
| 213     } |  | 
| 214     gtk_box_pack_start(GTK_BOX(bubble_content), list_content, FALSE, FALSE, |  | 
| 215                        gtk_util::kControlSpacing); |  | 
| 216   } |  | 
| 217 |  | 
| 218   if (!content.custom_link.empty()) { |  | 
| 219     GtkWidget* custom_link_box = gtk_hbox_new(FALSE, 0); |  | 
| 220     GtkWidget* custom_link = NULL; |  | 
| 221     if (content.custom_link_enabled) { |  | 
| 222       custom_link = gtk_chrome_link_button_new(content.custom_link.c_str()); |  | 
| 223       g_signal_connect(custom_link, "clicked", |  | 
| 224                        G_CALLBACK(OnCustomLinkClickedThunk), this); |  | 
| 225     } else { |  | 
| 226       custom_link = gtk_label_new(content.custom_link.c_str()); |  | 
| 227       gtk_misc_set_alignment(GTK_MISC(custom_link), 0, 0.5); |  | 
| 228     } |  | 
| 229     DCHECK(custom_link); |  | 
| 230     gtk_box_pack_start(GTK_BOX(custom_link_box), custom_link, FALSE, FALSE, 0); |  | 
| 231     gtk_box_pack_start(GTK_BOX(bubble_content), custom_link_box, |  | 
| 232                        FALSE, FALSE, 0); |  | 
| 233   } |  | 
| 234 |  | 
| 235   gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(), |  | 
| 236                      FALSE, FALSE, 0); |  | 
| 237 |  | 
| 238   GtkWidget* bottom_box = gtk_hbox_new(FALSE, 0); |  | 
| 239 |  | 
| 240   GtkWidget* manage_link = |  | 
| 241       gtk_chrome_link_button_new(content.manage_link.c_str()); |  | 
| 242   g_signal_connect(manage_link, "clicked", G_CALLBACK(OnManageLinkClickedThunk), |  | 
| 243                    this); |  | 
| 244   gtk_box_pack_start(GTK_BOX(bottom_box), manage_link, FALSE, FALSE, 0); |  | 
| 245 |  | 
| 246   GtkWidget* button = gtk_button_new_with_label( |  | 
| 247       l10n_util::GetStringUTF8(IDS_DONE).c_str()); |  | 
| 248   g_signal_connect(button, "clicked", G_CALLBACK(OnCloseButtonClickedThunk), |  | 
| 249                    this); |  | 
| 250   gtk_box_pack_end(GTK_BOX(bottom_box), button, FALSE, FALSE, 0); |  | 
| 251 |  | 
| 252   gtk_box_pack_start(GTK_BOX(bubble_content), bottom_box, FALSE, FALSE, 0); |  | 
| 253   gtk_widget_grab_focus(bottom_box); |  | 
| 254   gtk_widget_grab_focus(button); |  | 
| 255 |  | 
| 256   InfoBubbleGtk::ArrowLocationGtk arrow_location = |  | 
| 257       !base::i18n::IsRTL() ? |  | 
| 258       InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : |  | 
| 259       InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; |  | 
| 260   info_bubble_ = InfoBubbleGtk::Show( |  | 
| 261       anchor_, |  | 
| 262       NULL, |  | 
| 263       bubble_content, |  | 
| 264       arrow_location, |  | 
| 265       true,  // match_system_theme |  | 
| 266       true,  // grab_input |  | 
| 267       theme_provider, |  | 
| 268       this); |  | 
| 269 } |  | 
| 270 |  | 
| 271 void ContentSettingBubbleGtk::OnPopupIconButtonPress( |  | 
| 272     GtkWidget* icon_event_box, |  | 
| 273     GdkEventButton* event) { |  | 
| 274   PopupMap::iterator i(popup_icons_.find(icon_event_box)); |  | 
| 275   DCHECK(i != popup_icons_.end()); |  | 
| 276   content_setting_bubble_model_->OnPopupClicked(i->second); |  | 
| 277   // The views interface implicitly closes because of the launching of a new |  | 
| 278   // window; we need to do that explicitly. |  | 
| 279   Close(); |  | 
| 280 } |  | 
| 281 |  | 
| 282 void ContentSettingBubbleGtk::OnPopupLinkClicked(GtkWidget* button) { |  | 
| 283   PopupMap::iterator i(popup_links_.find(button)); |  | 
| 284   DCHECK(i != popup_links_.end()); |  | 
| 285   content_setting_bubble_model_->OnPopupClicked(i->second); |  | 
| 286   // The views interface implicitly closes because of the launching of a new |  | 
| 287   // window; we need to do that explicitly. |  | 
| 288   Close(); |  | 
| 289 } |  | 
| 290 |  | 
| 291 void ContentSettingBubbleGtk::OnRadioToggled(GtkWidget* widget) { |  | 
| 292   for (ContentSettingBubbleGtk::RadioGroupGtk::const_iterator i = |  | 
| 293        radio_group_gtk_.begin(); |  | 
| 294        i != radio_group_gtk_.end(); ++i) { |  | 
| 295     if (widget == *i) { |  | 
| 296       content_setting_bubble_model_->OnRadioClicked( |  | 
| 297           i - radio_group_gtk_.begin()); |  | 
| 298       return; |  | 
| 299     } |  | 
| 300   } |  | 
| 301   NOTREACHED() << "unknown radio toggled"; |  | 
| 302 } |  | 
| 303 |  | 
| 304 void ContentSettingBubbleGtk::OnCloseButtonClicked(GtkWidget *button) { |  | 
| 305   Close(); |  | 
| 306 } |  | 
| 307 |  | 
| 308 void ContentSettingBubbleGtk::OnCustomLinkClicked(GtkWidget* button) { |  | 
| 309   content_setting_bubble_model_->OnCustomLinkClicked(); |  | 
| 310   Close(); |  | 
| 311 } |  | 
| 312 |  | 
| 313 void ContentSettingBubbleGtk::OnManageLinkClicked(GtkWidget* button) { |  | 
| 314   content_setting_bubble_model_->OnManageLinkClicked(); |  | 
| 315   Close(); |  | 
| 316 } |  | 
| OLD | NEW | 
|---|