1 /*
2 * frogr-create-new-set-dialog.c -- 'Create new set' dialog
3 *
4 * Copyright (C) 2010-2018 Mario Sanchez Prada
5 * Authors: Mario Sanchez Prada <msanchez@gnome.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 3 of the GNU General Public
9 * License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>
18 *
19 */
20
21 #include "frogr-create-new-set-dialog.h"
22
23 #include "frogr-photoset.h"
24 #include "frogr-controller.h"
25 #include "frogr-model.h"
26 #include "frogr-picture.h"
27 #include "frogr-util.h"
28
29 #include <config.h>
30 #include <glib/gi18n.h>
31
32
33 struct _FrogrCreateNewSetDialog {
34 GtkDialog parent;
35
36 GtkWidget *title_entry;
37 GtkWidget *description_tv;
38 GtkWidget *copy_to_pictures_cb;
39 GtkTextBuffer *description_buffer;
40
41 GSList *pictures;
42 GSList *photosets;
43 gboolean copy_to_pictures;
44 };
45
46 G_DEFINE_TYPE (FrogrCreateNewSetDialog, frogr_create_new_set_dialog, GTK_TYPE_DIALOG)
47
48
49 /* Properties */
50 enum {
51 PROP_0,
52 PROP_PICTURES,
53 PROP_PHOTOSETS
54 };
55
56
57 /* Prototypes */
58
59 static void _set_pictures (FrogrCreateNewSetDialog *self, const GSList *pictures);
60
61 static void _set_photosets (FrogrCreateNewSetDialog *self, const GSList *photosets);
62
63 static void _on_button_toggled (GtkToggleButton *button, gpointer data);
64
65 static gboolean _validate_dialog_data (FrogrCreateNewSetDialog *self);
66
67 static gboolean _save_data (FrogrCreateNewSetDialog *self);
68
69 static void _update_model (FrogrCreateNewSetDialog *self,
70 const gchar *title,
71 const gchar *description);
72
73 static void _dialog_response_cb (GtkDialog *dialog, gint response, gpointer data);
74
75 /* Private API */
76
77 static void
_set_pictures(FrogrCreateNewSetDialog * self,const GSList * pictures)78 _set_pictures (FrogrCreateNewSetDialog *self, const GSList *pictures)
79 {
80 self->pictures = g_slist_copy ((GSList*) pictures);
81 g_slist_foreach (self->pictures, (GFunc)g_object_ref, NULL);
82 }
83
84 static void
_set_photosets(FrogrCreateNewSetDialog * self,const GSList * photosets)85 _set_photosets (FrogrCreateNewSetDialog *self, const GSList *photosets)
86 {
87 self->photosets = g_slist_copy ((GSList*)photosets);
88 g_slist_foreach (self->photosets, (GFunc)g_object_ref, NULL);
89 }
90
91 static void
_on_button_toggled(GtkToggleButton * button,gpointer data)92 _on_button_toggled (GtkToggleButton *button, gpointer data)
93 {
94 FrogrCreateNewSetDialog *self = NULL;
95 gboolean active = FALSE;
96
97 self = FROGR_CREATE_NEW_SET_DIALOG (data);
98 active = gtk_toggle_button_get_active (button);
99
100 if (GTK_WIDGET (button) == self->copy_to_pictures_cb)
101 self->copy_to_pictures = active;
102 }
103
104 static gboolean
_validate_dialog_data(FrogrCreateNewSetDialog * self)105 _validate_dialog_data (FrogrCreateNewSetDialog *self)
106 {
107 g_autofree gchar *title = NULL;
108 gboolean result = TRUE;
109
110 /* Validate set's title */
111 title = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->title_entry)));
112 if ((title == NULL) || g_str_equal (g_strstrip (title), ""))
113 result = FALSE;
114
115 return result;
116 }
117
118 static gboolean
_save_data(FrogrCreateNewSetDialog * self)119 _save_data (FrogrCreateNewSetDialog *self)
120 {
121 GtkTextIter start;
122 GtkTextIter end;
123 g_autofree gchar *title = NULL;
124 g_autofree gchar *description = NULL;
125 gboolean result = FALSE;
126
127 /* Save data */
128 title = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->title_entry)));
129 title = g_strstrip (title);
130
131 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (self->description_buffer),
132 &start, &end);
133 description = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (self->description_buffer),
134 &start, &end, FALSE);
135 description = g_strstrip (description);
136
137 /* validate and update */
138 result = _validate_dialog_data (self);
139 if (result)
140 _update_model (self, title, description);
141 else
142 frogr_util_show_error_dialog (GTK_WINDOW (self), _("Missing data required"));
143
144 /* Return result */
145 return result;
146 }
147
148 static void
_update_model(FrogrCreateNewSetDialog * self,const gchar * title,const gchar * description)149 _update_model (FrogrCreateNewSetDialog *self,
150 const gchar *title,
151 const gchar *description)
152 {
153 FrogrController *controller = NULL;
154 FrogrModel *model = NULL;
155 g_autoptr(FrogrPhotoSet) new_set = NULL;
156 FrogrPicture *picture = NULL;
157 GSList *item = NULL;
158
159 controller = frogr_controller_get_instance ();
160 model = frogr_controller_get_model (controller);
161
162 /* Add the set to the model */
163 new_set = frogr_photoset_new_local (title, description);
164 frogr_model_add_local_photoset (model, new_set);
165
166 /* Add the set to the list of sets for each picture */
167 for (item = self->pictures; item; item = g_slist_next (item))
168 {
169 picture = FROGR_PICTURE (item->data);
170 frogr_picture_add_photoset (picture, new_set);
171
172 /* Copy album's details over pictures if requested */
173 if (self->copy_to_pictures)
174 {
175 frogr_picture_set_title (picture, title);
176 frogr_picture_set_description (picture, description);
177 }
178 }
179
180 frogr_model_notify_changes_in_pictures (model);
181 }
182
183 static void
_dialog_response_cb(GtkDialog * dialog,gint response,gpointer data)184 _dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
185 {
186 FrogrCreateNewSetDialog *self = NULL;
187
188 /* Try to save data if response is OK */
189 self = FROGR_CREATE_NEW_SET_DIALOG (dialog);
190 if (response == GTK_RESPONSE_ACCEPT && _save_data (self) == FALSE)
191 return;
192
193 /* Destroy the dialog */
194 gtk_widget_destroy (GTK_WIDGET (dialog));
195 }
196
197 static void
_frogr_create_new_set_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)198 _frogr_create_new_set_dialog_set_property (GObject *object,
199 guint prop_id,
200 const GValue *value,
201 GParamSpec *pspec)
202 {
203 switch (prop_id)
204 {
205 case PROP_PICTURES:
206 _set_pictures (FROGR_CREATE_NEW_SET_DIALOG (object), g_value_get_pointer (value));
207 break;
208 case PROP_PHOTOSETS:
209 _set_photosets (FROGR_CREATE_NEW_SET_DIALOG (object), g_value_get_pointer (value));
210 break;
211 default:
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213 break;
214 }
215 }
216
217 static void
_frogr_create_new_set_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)218 _frogr_create_new_set_dialog_get_property (GObject *object,
219 guint prop_id,
220 GValue *value,
221 GParamSpec *pspec)
222 {
223 FrogrCreateNewSetDialog *dialog = FROGR_CREATE_NEW_SET_DIALOG (object);
224
225 switch (prop_id)
226 {
227 case PROP_PICTURES:
228 g_value_set_pointer (value, dialog->pictures);
229 break;
230 case PROP_PHOTOSETS:
231 g_value_set_pointer (value, dialog->photosets);
232 break;
233 default:
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
235 break;
236 }
237 }
238
239 static void
_frogr_create_new_set_dialog_dispose(GObject * object)240 _frogr_create_new_set_dialog_dispose (GObject *object)
241 {
242 FrogrCreateNewSetDialog *dialog = FROGR_CREATE_NEW_SET_DIALOG (object);
243
244 if (dialog->pictures)
245 {
246 g_slist_free_full (dialog->pictures, g_object_unref);
247 dialog->pictures = NULL;
248 }
249
250 if (dialog->photosets)
251 {
252 g_slist_free_full (dialog->photosets, g_object_unref);
253 dialog->photosets = NULL;
254 }
255
256 G_OBJECT_CLASS(frogr_create_new_set_dialog_parent_class)->dispose (object);
257 }
258
259 static void
frogr_create_new_set_dialog_class_init(FrogrCreateNewSetDialogClass * klass)260 frogr_create_new_set_dialog_class_init (FrogrCreateNewSetDialogClass *klass)
261 {
262 GObjectClass *obj_class = (GObjectClass *)klass;
263 GParamSpec *pspec;
264
265 /* GObject signals */
266 obj_class->set_property = _frogr_create_new_set_dialog_set_property;
267 obj_class->get_property = _frogr_create_new_set_dialog_get_property;
268 obj_class->dispose = _frogr_create_new_set_dialog_dispose;
269
270 /* Install properties */
271 pspec = g_param_spec_pointer ("pictures",
272 "pictures",
273 "List of pictures for "
274 "the 'add to set' dialog",
275 G_PARAM_READWRITE
276 | G_PARAM_CONSTRUCT_ONLY);
277 g_object_class_install_property (obj_class, PROP_PICTURES, pspec);
278
279 pspec = g_param_spec_pointer ("photosets",
280 "photosets",
281 "List of sets currently available "
282 "for the 'add to set' dialog",
283 G_PARAM_READWRITE
284 | G_PARAM_CONSTRUCT_ONLY);
285 g_object_class_install_property (obj_class, PROP_PHOTOSETS, pspec);
286 }
287
288 static void
frogr_create_new_set_dialog_init(FrogrCreateNewSetDialog * self)289 frogr_create_new_set_dialog_init (FrogrCreateNewSetDialog *self)
290 {
291 GtkWidget *content_area = NULL;
292 GtkWidget *vbox = NULL;
293 GtkWidget *grid = NULL;
294 GtkWidget *scroller = NULL;
295 GtkWidget *widget = NULL;
296
297 self->pictures = NULL;
298 self->photosets = NULL;
299
300 /* Create widgets */
301 gtk_dialog_add_buttons (GTK_DIALOG (self),
302 _("_Cancel"),
303 GTK_RESPONSE_CANCEL,
304 _("_Add"),
305 GTK_RESPONSE_ACCEPT,
306 NULL);
307 gtk_container_set_border_width (GTK_CONTAINER (self), 6);
308
309 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
310 gtk_widget_set_margin_bottom (vbox, 12);
311 gtk_widget_show (vbox);
312
313 grid = gtk_grid_new ();
314 gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
315 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
316 gtk_box_pack_start (GTK_BOX (vbox), grid, TRUE, TRUE, 0);
317 gtk_widget_show (grid);
318
319 widget = gtk_label_new (_("Title:"));
320 gtk_widget_set_halign (GTK_WIDGET (widget), GTK_ALIGN_END);
321 gtk_grid_attach (GTK_GRID (grid), widget, 0, 0, 1, 1);
322 gtk_widget_show (widget);
323
324 widget = gtk_entry_new ();
325 gtk_widget_set_hexpand (GTK_WIDGET (widget), TRUE);
326 gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1);
327 self->title_entry = widget;
328 gtk_widget_show (widget);
329
330 widget = gtk_label_new (_("Description:"));
331 gtk_widget_set_halign (GTK_WIDGET (widget), GTK_ALIGN_END);
332 gtk_widget_set_valign (GTK_WIDGET (widget), GTK_ALIGN_START);
333 gtk_grid_attach (GTK_GRID (grid), widget, 0, 1, 1, 1);
334 gtk_widget_show (widget);
335
336 widget = gtk_text_view_new ();
337 scroller = gtk_scrolled_window_new (NULL, NULL);
338 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
339 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
340 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
341 GTK_SHADOW_ETCHED_IN);
342 gtk_container_add (GTK_CONTAINER (scroller), widget);
343 gtk_widget_show (widget);
344
345 gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (widget), FALSE);
346 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD);
347 gtk_widget_set_hexpand (GTK_WIDGET (scroller), TRUE);
348 gtk_widget_set_vexpand (GTK_WIDGET (scroller), TRUE);
349 gtk_grid_attach (GTK_GRID (grid), scroller, 1, 1, 1, 1);
350 gtk_widget_show (scroller);
351
352 self->description_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
353 self->description_tv = widget;
354
355 widget = gtk_check_button_new_with_mnemonic (_("Fill Pictures Details with Title and Description"));
356 gtk_widget_set_hexpand (GTK_WIDGET (widget), TRUE);
357 gtk_grid_attach (GTK_GRID (grid), widget, 1, 2, 1, 1);
358 gtk_widget_show (widget);
359 self->copy_to_pictures_cb = widget;
360
361 content_area = gtk_dialog_get_content_area (GTK_DIALOG (self));
362 gtk_container_add (GTK_CONTAINER (content_area), vbox);
363 gtk_widget_show (content_area);
364
365 g_signal_connect (G_OBJECT (self->copy_to_pictures_cb), "toggled",
366 G_CALLBACK (_on_button_toggled),
367 self);
368
369 gtk_dialog_set_default_response (GTK_DIALOG (self), GTK_RESPONSE_ACCEPT);
370
371 self->copy_to_pictures = FALSE;
372 }
373
374 /* Public API */
375
376 void
frogr_create_new_set_dialog_show(GtkWindow * parent,const GSList * pictures,const GSList * photosets)377 frogr_create_new_set_dialog_show (GtkWindow *parent,
378 const GSList *pictures,
379 const GSList *photosets)
380 {
381 GtkWidget *dialog = NULL;
382 dialog = GTK_WIDGET (g_object_new (FROGR_TYPE_CREATE_NEW_SET_DIALOG,
383 "title", _("Create New Set"),
384 "modal", TRUE,
385 "pictures", pictures,
386 "photosets", photosets,
387 "transient-for", parent,
388 "width-request", -1,
389 "height-request", 300,
390 "resizable", TRUE,
391 #if GTK_CHECK_VERSION (3, 12, 0)
392 "use-header-bar", USE_HEADER_BAR,
393 #endif
394 NULL));
395
396 g_signal_connect (G_OBJECT (dialog), "response",
397 G_CALLBACK (_dialog_response_cb), NULL);
398
399 gtk_widget_show (dialog);
400 }
401