Home | History | Annotate | Download | only in extensions
      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