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.
5 #include "chrome/browser/ui/gtk/extensions/media_galleries_dialog_gtk.h"
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"
16 using web_modal::WebContentsModalDialogManager
;
20 // Color used for additional attachment detail text for galleries.
21 const GdkColor kDeemphasizedTextColor
= GDK_COLOR_RGB(0x96, 0x96, 0x96);
23 // Width and height of the scrollable area in which galleries are shown.
24 const int kGalleryControlScrollableWidth
= 280;
25 const int kGalleryControlScrollableHeight
= 192;
29 typedef MediaGalleriesDialogController::GalleryPermissionsVector
30 GalleryPermissionsVector
;
32 MediaGalleriesDialogGtk::MediaGalleriesDialogGtk(
33 MediaGalleriesDialogController
* controller
)
34 : controller_(controller
),
38 contents_
.reset(gtk_vbox_new(FALSE
, ui::kContentAreaSpacing
));
39 g_object_ref_sink(contents_
.get());
40 g_signal_connect(contents_
.get(),
42 G_CALLBACK(OnDestroyThunk
),
46 // May be NULL during tests.
47 if (controller
->web_contents()) {
48 window_
= CreateWebContentsModalDialogGtk(contents_
.get(), confirm_
);
50 WebContentsModalDialogManager
* web_contents_modal_dialog_manager
=
51 WebContentsModalDialogManager::FromWebContents(
52 controller
->web_contents());
53 web_contents_modal_dialog_manager
->ShowDialog(window_
);
57 MediaGalleriesDialogGtk::~MediaGalleriesDialogGtk() {
60 void MediaGalleriesDialogGtk::InitWidgets() {
61 gtk_util::RemoveAllChildren(contents_
.get());
62 checkbox_map_
.clear();
63 new_checkbox_map_
.clear();
66 GtkWidget
* header
= gtk_util::LeftAlignMisc(gtk_label_new(
67 base::UTF16ToUTF8(controller_
->GetHeader()).c_str()));
68 gtk_box_pack_start(GTK_BOX(contents_
.get()), header
, FALSE
, FALSE
, 0);
71 gtk_label_new(base::UTF16ToUTF8(controller_
->GetSubtext()).c_str());
72 gtk_label_set_line_wrap(GTK_LABEL(subtext
), TRUE
);
73 gtk_widget_set_size_request(subtext
, 500, -1);
74 gtk_box_pack_start(GTK_BOX(contents_
.get()), subtext
, FALSE
, FALSE
, 0);
76 // The checkboxes are added inside a scrollable area.
77 GtkWidget
* scroll_window
=
78 gtk_scrolled_window_new(NULL
, NULL
);
79 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window
),
81 GTK_POLICY_AUTOMATIC
);
82 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window
),
83 GTK_SHADOW_ETCHED_IN
);
85 GtkWidget
* checkbox_container
= gtk_vbox_new(FALSE
, ui::kControlSpacing
);
86 gtk_widget_set_size_request(scroll_window
,
87 kGalleryControlScrollableWidth
,
88 kGalleryControlScrollableHeight
);
89 gtk_container_set_border_width(GTK_CONTAINER(checkbox_container
),
91 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_window
),
93 gtk_widget_show(checkbox_container
);
94 gtk_box_pack_start(GTK_BOX(contents_
.get()), scroll_window
,
96 gtk_widget_show(scroll_window
);
98 // Attached galleries checkboxes
99 GalleryPermissionsVector permissions
= controller_
->AttachedPermissions();
100 for (GalleryPermissionsVector::const_iterator iter
= permissions
.begin();
101 iter
!= permissions
.end(); ++iter
) {
102 UpdateGalleryInContainer(iter
->pref_info
, iter
->allowed
,
106 const GalleryPermissionsVector unattached_permissions
=
107 controller_
->UnattachedPermissions();
108 if (!unattached_permissions
.empty()) {
109 // Separator line and unattached volumes header text.
110 GtkWidget
* separator
= gtk_hseparator_new();
111 gtk_box_pack_start(GTK_BOX(checkbox_container
), separator
, FALSE
, FALSE
, 0);
113 GtkWidget
* unattached_hbox
= gtk_hbox_new(FALSE
, ui::kLabelSpacing
);
114 GtkWidget
* unattached_text
= gtk_label_new(base::UTF16ToUTF8(
115 controller_
->GetUnattachedLocationsHeader()).c_str());
116 gtk_label_set_line_wrap(GTK_LABEL(unattached_text
), FALSE
);
117 gtk_box_pack_start(GTK_BOX(unattached_hbox
), unattached_text
,
119 gtk_box_pack_start(GTK_BOX(checkbox_container
), unattached_hbox
,
122 // Unattached galleries checkboxes
123 for (GalleryPermissionsVector::const_iterator iter
=
124 unattached_permissions
.begin();
125 iter
!= unattached_permissions
.end(); ++iter
) {
126 UpdateGalleryInContainer(iter
->pref_info
, iter
->allowed
,
131 GtkWidget
* bottom_area
= gtk_hbox_new(FALSE
, ui::kControlSpacing
);
133 // Add gallery button.
134 GtkWidget
* add_folder
= gtk_button_new_with_label(
135 l10n_util::GetStringUTF8(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY
).c_str());
136 g_signal_connect(add_folder
, "clicked", G_CALLBACK(OnAddFolderThunk
), this);
137 gtk_box_pack_start(GTK_BOX(bottom_area
), add_folder
, FALSE
, FALSE
, 0);
139 // Confirm/cancel button.
140 confirm_
= gtk_button_new_with_label(l10n_util::GetStringUTF8(
141 IDS_MEDIA_GALLERIES_DIALOG_CONFIRM
).c_str());
142 gtk_button_set_image(
143 GTK_BUTTON(confirm_
),
144 gtk_image_new_from_stock(GTK_STOCK_APPLY
, GTK_ICON_SIZE_BUTTON
));
145 g_signal_connect(confirm_
, "clicked", G_CALLBACK(OnConfirmThunk
), this);
146 gtk_box_pack_end(GTK_BOX(bottom_area
), confirm_
, FALSE
, FALSE
, 0);
148 GtkWidget
* cancel
= gtk_button_new_with_label(l10n_util::GetStringUTF8(
149 IDS_MEDIA_GALLERIES_DIALOG_CANCEL
).c_str());
150 gtk_button_set_image(
152 gtk_image_new_from_stock(GTK_STOCK_CANCEL
, GTK_ICON_SIZE_BUTTON
));
153 g_signal_connect(cancel
, "clicked", G_CALLBACK(OnCancelThunk
), this);
154 gtk_box_pack_end(GTK_BOX(bottom_area
), cancel
, FALSE
, FALSE
, 0);
155 gtk_box_pack_start(GTK_BOX(contents_
.get()), bottom_area
, FALSE
, FALSE
, 0);
157 // As a safeguard against the user skipping reading over the dialog and just
158 // confirming, the button will be unavailable for dialogs without any checks
159 // until the user toggles something.
160 gtk_widget_set_sensitive(confirm_
, controller_
->HasPermittedGalleries());
162 gtk_widget_show_all(contents_
.get());
165 void MediaGalleriesDialogGtk::UpdateGalleries() {
169 void MediaGalleriesDialogGtk::UpdateGalleryInContainer(
170 const MediaGalleryPrefInfo
& gallery
,
172 GtkWidget
* checkbox_container
) {
173 GtkWidget
* hbox
= gtk_hbox_new(FALSE
, ui::kLabelSpacing
);
174 GtkWidget
* widget
= gtk_check_button_new();
175 g_signal_connect(widget
, "toggled", G_CALLBACK(OnToggledThunk
), this);
176 gtk_box_pack_start(GTK_BOX(checkbox_container
), hbox
, FALSE
, FALSE
, 0);
177 gtk_box_pack_start(GTK_BOX(hbox
), widget
, FALSE
, FALSE
, 0);
178 std::string details
=
179 base::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);
185 gtk_widget_show(hbox
);
186 if (gallery
.pref_id
!= kInvalidMediaGalleryPrefId
)
187 checkbox_map_
[gallery
.pref_id
] = widget
;
189 new_checkbox_map_
[widget
] = gallery
;
191 std::string tooltip_text
= base::UTF16ToUTF8(gallery
.GetGalleryTooltip());
192 gtk_widget_set_tooltip_text(widget
, tooltip_text
.c_str());
194 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
), permitted
);
195 std::string label
= base::UTF16ToUTF8(gallery
.GetGalleryDisplayName());
196 // TODO(gbillock): Would be nice to add middle elide behavior here.
197 gtk_button_set_label(GTK_BUTTON(widget
), label
.c_str());
200 void MediaGalleriesDialogGtk::OnToggled(GtkWidget
* widget
) {
202 gtk_widget_set_sensitive(confirm_
, TRUE
);
204 for (CheckboxMap::const_iterator iter
= checkbox_map_
.begin();
205 iter
!= checkbox_map_
.end(); ++iter
) {
206 if (iter
->second
== widget
) {
207 controller_
->DidToggleGalleryId(
209 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)));
213 for (NewCheckboxMap::const_iterator iter
= new_checkbox_map_
.begin();
214 iter
!= new_checkbox_map_
.end(); ++iter
) {
215 if (iter
->first
== widget
) {
216 controller_
->DidToggleNewGallery(
218 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
)));
224 void MediaGalleriesDialogGtk::OnAddFolder(GtkWidget
* widget
) {
225 controller_
->OnAddFolderClicked();
228 void MediaGalleriesDialogGtk::OnConfirm(GtkWidget
* widget
) {
232 gtk_widget_destroy(window_
);
235 void MediaGalleriesDialogGtk::OnCancel(GtkWidget
* widget
) {
237 gtk_widget_destroy(window_
);
240 void MediaGalleriesDialogGtk::OnDestroy(GtkWidget
* widget
) {
241 controller_
->DialogFinished(accepted_
);
244 // MediaGalleriesDialogController ----------------------------------------------
247 MediaGalleriesDialog
* MediaGalleriesDialog::Create(
248 MediaGalleriesDialogController
* controller
) {
249 return new MediaGalleriesDialogGtk(controller
);