1 // Copyright (c) 2012 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/ui/gtk/extensions/media_galleries_dialog_gtk.h" 6 7 #include "base/auto_reset.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/media_galleries/media_galleries_preferences.h" 10 #include "chrome/browser/ui/gtk/gtk_util.h" 11 #include "components/web_modal/web_contents_modal_dialog_manager.h" 12 #include "grit/generated_resources.h" 13 #include "ui/base/gtk/gtk_hig_constants.h" 14 #include "ui/base/l10n/l10n_util.h" 15 16 using web_modal::WebContentsModalDialogManager; 17 18 namespace chrome { 19 20 namespace { 21 22 // Color used for additional attachment detail text for galleries. 23 const GdkColor kDeemphasizedTextColor = GDK_COLOR_RGB(0x96, 0x96, 0x96); 24 25 // Width and height of the scrollable area in which galleries are shown. 26 const int kGalleryControlScrollableWidth = 280; 27 const int kGalleryControlScrollableHeight = 192; 28 29 } // namespace 30 31 typedef MediaGalleriesDialogController::GalleryPermissionsVector 32 GalleryPermissionsVector; 33 34 MediaGalleriesDialogGtk::MediaGalleriesDialogGtk( 35 MediaGalleriesDialogController* controller) 36 : controller_(controller), 37 window_(NULL), 38 confirm_(NULL), 39 accepted_(false) { 40 contents_.reset(gtk_vbox_new(FALSE, ui::kContentAreaSpacing)); 41 g_object_ref_sink(contents_.get()); 42 g_signal_connect(contents_.get(), 43 "destroy", 44 G_CALLBACK(OnDestroyThunk), 45 this); 46 InitWidgets(); 47 48 // May be NULL during tests. 49 if (controller->web_contents()) { 50 window_ = CreateWebContentsModalDialogGtk(contents_.get(), confirm_); 51 52 WebContentsModalDialogManager* web_contents_modal_dialog_manager = 53 WebContentsModalDialogManager::FromWebContents( 54 controller->web_contents()); 55 web_contents_modal_dialog_manager->ShowDialog(window_); 56 } 57 } 58 59 MediaGalleriesDialogGtk::~MediaGalleriesDialogGtk() { 60 } 61 62 void MediaGalleriesDialogGtk::InitWidgets() { 63 gtk_util::RemoveAllChildren(contents_.get()); 64 checkbox_map_.clear(); 65 confirm_ = NULL; 66 67 GtkWidget* header = gtk_util::LeftAlignMisc(gtk_label_new( 68 UTF16ToUTF8(controller_->GetHeader()).c_str())); 69 gtk_box_pack_start(GTK_BOX(contents_.get()), header, FALSE, FALSE, 0); 70 71 GtkWidget* subtext = 72 gtk_label_new(UTF16ToUTF8(controller_->GetSubtext()).c_str()); 73 gtk_label_set_line_wrap(GTK_LABEL(subtext), TRUE); 74 gtk_widget_set_size_request(subtext, 500, -1); 75 gtk_box_pack_start(GTK_BOX(contents_.get()), subtext, FALSE, FALSE, 0); 76 77 // The checkboxes are added inside a scrollable area. 78 GtkWidget* scroll_window = 79 gtk_scrolled_window_new(NULL, NULL); 80 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), 81 GTK_POLICY_NEVER, 82 GTK_POLICY_AUTOMATIC); 83 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), 84 GTK_SHADOW_ETCHED_IN); 85 86 GtkWidget* checkbox_container = gtk_vbox_new(FALSE, ui::kControlSpacing); 87 gtk_widget_set_size_request(scroll_window, 88 kGalleryControlScrollableWidth, 89 kGalleryControlScrollableHeight); 90 gtk_container_set_border_width(GTK_CONTAINER(checkbox_container), 91 ui::kGroupIndent); 92 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_window), 93 checkbox_container); 94 gtk_widget_show(checkbox_container); 95 gtk_box_pack_start(GTK_BOX(contents_.get()), scroll_window, 96 FALSE, FALSE, 0); 97 gtk_widget_show(scroll_window); 98 99 // Attached galleries checkboxes 100 GalleryPermissionsVector permissions = controller_->AttachedPermissions(); 101 for (GalleryPermissionsVector::const_iterator iter = permissions.begin(); 102 iter != permissions.end(); ++iter) { 103 UpdateGalleryInContainer(iter->pref_info, iter->allowed, 104 checkbox_container); 105 } 106 107 // Separator line and unattached volumes header text. 108 GtkWidget* separator = gtk_hseparator_new(); 109 gtk_box_pack_start(GTK_BOX(checkbox_container), separator, FALSE, FALSE, 0); 110 111 GtkWidget* unattached_hbox = gtk_hbox_new(FALSE, ui::kLabelSpacing); 112 GtkWidget* unattached_text = gtk_label_new(UTF16ToUTF8( 113 controller_->GetUnattachedLocationsHeader()).c_str()); 114 gtk_label_set_line_wrap(GTK_LABEL(unattached_text), FALSE); 115 gtk_box_pack_start(GTK_BOX(unattached_hbox), unattached_text, 116 FALSE, FALSE, 0); 117 gtk_box_pack_start(GTK_BOX(checkbox_container), unattached_hbox, 118 FALSE, FALSE, 0); 119 120 // Unattached galleries checkboxes 121 const GalleryPermissionsVector unattached_permissions = 122 controller_->UnattachedPermissions(); 123 for (GalleryPermissionsVector::const_iterator iter = 124 unattached_permissions.begin(); 125 iter != unattached_permissions.end(); ++iter) { 126 UpdateGalleryInContainer(iter->pref_info, iter->allowed, 127 checkbox_container); 128 } 129 130 GtkWidget* bottom_area = gtk_hbox_new(FALSE, ui::kControlSpacing); 131 132 // Add gallery button. 133 GtkWidget* add_folder = gtk_button_new_with_label( 134 l10n_util::GetStringUTF8(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY).c_str()); 135 g_signal_connect(add_folder, "clicked", G_CALLBACK(OnAddFolderThunk), this); 136 gtk_box_pack_start(GTK_BOX(bottom_area), add_folder, FALSE, FALSE, 0); 137 138 // Confirm/cancel button. 139 confirm_ = gtk_button_new_with_label(l10n_util::GetStringUTF8( 140 IDS_MEDIA_GALLERIES_DIALOG_CONFIRM).c_str()); 141 gtk_button_set_image( 142 GTK_BUTTON(confirm_), 143 gtk_image_new_from_stock(GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON)); 144 g_signal_connect(confirm_, "clicked", G_CALLBACK(OnConfirmThunk), this); 145 gtk_box_pack_end(GTK_BOX(bottom_area), confirm_, FALSE, FALSE, 0); 146 147 GtkWidget* cancel = gtk_button_new_with_label(l10n_util::GetStringUTF8( 148 IDS_MEDIA_GALLERIES_DIALOG_CANCEL).c_str()); 149 gtk_button_set_image( 150 GTK_BUTTON(cancel), 151 gtk_image_new_from_stock(GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON)); 152 g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelThunk), this); 153 gtk_box_pack_end(GTK_BOX(bottom_area), cancel, FALSE, FALSE, 0); 154 gtk_box_pack_start(GTK_BOX(contents_.get()), bottom_area, FALSE, FALSE, 0); 155 156 // As a safeguard against the user skipping reading over the dialog and just 157 // confirming, the button will be unavailable for dialogs without any checks 158 // until the user toggles something. 159 gtk_widget_set_sensitive(confirm_, controller_->HasPermittedGalleries()); 160 161 gtk_widget_show_all(contents_.get()); 162 } 163 164 void MediaGalleriesDialogGtk::UpdateGallery( 165 const MediaGalleryPrefInfo& gallery, 166 bool permitted) { 167 InitWidgets(); 168 } 169 170 void MediaGalleriesDialogGtk::UpdateGalleryInContainer( 171 const MediaGalleryPrefInfo& gallery, 172 bool permitted, 173 GtkWidget* checkbox_container) { 174 GtkWidget* hbox = gtk_hbox_new(FALSE, ui::kLabelSpacing); 175 GtkWidget* widget = gtk_check_button_new(); 176 g_signal_connect(widget, "toggled", G_CALLBACK(OnToggledThunk), this); 177 gtk_box_pack_start(GTK_BOX(checkbox_container), hbox, FALSE, FALSE, 0); 178 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0); 179 std::string details = UTF16ToUTF8(gallery.GetGalleryAdditionalDetails()); 180 GtkWidget* details_label = gtk_label_new(details.c_str()); 181 gtk_label_set_line_wrap(GTK_LABEL(details_label), FALSE); 182 gtk_util::SetLabelColor(details_label, &kDeemphasizedTextColor); 183 gtk_box_pack_start(GTK_BOX(hbox), details_label, FALSE, FALSE, 0); 184 185 gtk_widget_show(hbox); 186 checkbox_map_[gallery.pref_id] = widget; 187 188 std::string tooltip_text = UTF16ToUTF8(gallery.GetGalleryTooltip()); 189 gtk_widget_set_tooltip_text(widget, tooltip_text.c_str()); 190 191 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), permitted); 192 std::string label = UTF16ToUTF8(gallery.GetGalleryDisplayName()); 193 gtk_button_set_label(GTK_BUTTON(widget), label.c_str()); 194 } 195 196 void MediaGalleriesDialogGtk::ForgetGallery(MediaGalleryPrefId gallery) { 197 for (CheckboxMap::iterator iter = checkbox_map_.begin(); 198 iter != checkbox_map_.end(); ++iter) { 199 if (iter->first == gallery) { 200 GtkWidget* checkbox = iter->second; 201 checkbox_map_.erase(iter); 202 gtk_widget_destroy(gtk_widget_get_parent(checkbox)); 203 return; 204 } 205 } 206 } 207 208 void MediaGalleriesDialogGtk::OnToggled(GtkWidget* widget) { 209 if (confirm_) 210 gtk_widget_set_sensitive(confirm_, TRUE); 211 212 for (CheckboxMap::const_iterator iter = checkbox_map_.begin(); 213 iter != checkbox_map_.end(); ++iter) { 214 if (iter->second == widget) { 215 controller_->DidToggleGalleryId( 216 iter->first, 217 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); 218 } 219 } 220 } 221 222 void MediaGalleriesDialogGtk::OnAddFolder(GtkWidget* widget) { 223 controller_->OnAddFolderClicked(); 224 } 225 226 void MediaGalleriesDialogGtk::OnConfirm(GtkWidget* widget) { 227 accepted_ = true; 228 229 if (window_) 230 gtk_widget_destroy(window_); 231 } 232 233 void MediaGalleriesDialogGtk::OnCancel(GtkWidget* widget) { 234 if (window_) 235 gtk_widget_destroy(window_); 236 } 237 238 void MediaGalleriesDialogGtk::OnDestroy(GtkWidget* widget) { 239 controller_->DialogFinished(accepted_); 240 } 241 242 // MediaGalleriesDialogController ---------------------------------------------- 243 244 // static 245 MediaGalleriesDialog* MediaGalleriesDialog::Create( 246 MediaGalleriesDialogController* controller) { 247 return new MediaGalleriesDialogGtk(controller); 248 } 249 250 } // namespace chrome 251