1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpsettingseditor.c
5  * Copyright (C) 2008-2017 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27 
28 #include "libgimpbase/gimpbase.h"
29 #include "libgimpconfig/gimpconfig.h"
30 #include "libgimpwidgets/gimpwidgets.h"
31 
32 #include "widgets-types.h"
33 
34 #include "operations/gimp-operation-config.h"
35 
36 #include "core/gimp.h"
37 #include "core/gimpcontainer.h"
38 #include "core/gimpviewable.h"
39 
40 #include "gimpcontainertreestore.h"
41 #include "gimpcontainertreeview.h"
42 #include "gimpcontainerview.h"
43 #include "gimpsettingseditor.h"
44 #include "gimpviewrenderer.h"
45 #include "gimpwidgets-utils.h"
46 
47 #include "gimp-intl.h"
48 
49 
50 enum
51 {
52   PROP_0,
53   PROP_GIMP,
54   PROP_CONFIG,
55   PROP_CONTAINER
56 };
57 
58 
59 typedef struct _GimpSettingsEditorPrivate GimpSettingsEditorPrivate;
60 
61 struct _GimpSettingsEditorPrivate
62 {
63   Gimp          *gimp;
64   GObject       *config;
65   GimpContainer *container;
66   GObject       *selected_setting;
67 
68   GtkWidget     *view;
69   GtkWidget     *import_button;
70   GtkWidget     *export_button;
71   GtkWidget     *delete_button;
72 };
73 
74 #define GET_PRIVATE(item) ((GimpSettingsEditorPrivate *) gimp_settings_editor_get_instance_private ((GimpSettingsEditor *) (item)))
75 
76 
77 static void   gimp_settings_editor_constructed    (GObject             *object);
78 static void   gimp_settings_editor_finalize       (GObject             *object);
79 static void   gimp_settings_editor_set_property   (GObject             *object,
80                                                    guint                property_id,
81                                                    const GValue        *value,
82                                                    GParamSpec          *pspec);
83 static void   gimp_settings_editor_get_property   (GObject             *object,
84                                                    guint                property_id,
85                                                    GValue              *value,
86                                                    GParamSpec          *pspec);
87 
88 static gboolean
89           gimp_settings_editor_row_separator_func (GtkTreeModel        *model,
90                                                    GtkTreeIter         *iter,
91                                                    gpointer             data);
92 static void   gimp_settings_editor_select_item    (GimpContainerView   *view,
93                                                    GimpViewable        *viewable,
94                                                    gpointer             insert_data,
95                                                    GimpSettingsEditor  *editor);
96 static void   gimp_settings_editor_import_clicked (GtkWidget           *widget,
97                                                    GimpSettingsEditor  *editor);
98 static void   gimp_settings_editor_export_clicked (GtkWidget           *widget,
99                                                    GimpSettingsEditor  *editor);
100 static void   gimp_settings_editor_delete_clicked (GtkWidget           *widget,
101                                                    GimpSettingsEditor  *editor);
102 static void   gimp_settings_editor_name_edited    (GtkCellRendererText *cell,
103                                                    const gchar         *path_str,
104                                                    const gchar         *new_name,
105                                                    GimpSettingsEditor  *editor);
106 
107 
G_DEFINE_TYPE_WITH_PRIVATE(GimpSettingsEditor,gimp_settings_editor,GTK_TYPE_BOX)108 G_DEFINE_TYPE_WITH_PRIVATE (GimpSettingsEditor, gimp_settings_editor,
109                             GTK_TYPE_BOX)
110 
111 #define parent_class gimp_settings_editor_parent_class
112 
113 
114 static void
115 gimp_settings_editor_class_init (GimpSettingsEditorClass *klass)
116 {
117   GObjectClass *object_class = G_OBJECT_CLASS (klass);
118 
119   object_class->constructed  = gimp_settings_editor_constructed;
120   object_class->finalize     = gimp_settings_editor_finalize;
121   object_class->set_property = gimp_settings_editor_set_property;
122   object_class->get_property = gimp_settings_editor_get_property;
123 
124   g_object_class_install_property (object_class, PROP_GIMP,
125                                    g_param_spec_object ("gimp",
126                                                         NULL, NULL,
127                                                         GIMP_TYPE_GIMP,
128                                                         GIMP_PARAM_READWRITE |
129                                                         G_PARAM_CONSTRUCT_ONLY));
130 
131   g_object_class_install_property (object_class, PROP_CONFIG,
132                                    g_param_spec_object ("config",
133                                                         NULL, NULL,
134                                                         GIMP_TYPE_CONFIG,
135                                                         GIMP_PARAM_READWRITE |
136                                                         G_PARAM_CONSTRUCT_ONLY));
137 
138   g_object_class_install_property (object_class, PROP_CONTAINER,
139                                    g_param_spec_object ("container",
140                                                         NULL, NULL,
141                                                         GIMP_TYPE_CONTAINER,
142                                                         GIMP_PARAM_READWRITE |
143                                                         G_PARAM_CONSTRUCT_ONLY));
144 }
145 
146 static void
gimp_settings_editor_init(GimpSettingsEditor * editor)147 gimp_settings_editor_init (GimpSettingsEditor *editor)
148 {
149   gtk_orientable_set_orientation (GTK_ORIENTABLE (editor),
150                                   GTK_ORIENTATION_VERTICAL);
151 
152   gtk_box_set_spacing (GTK_BOX (editor), 6);
153 }
154 
155 static void
gimp_settings_editor_constructed(GObject * object)156 gimp_settings_editor_constructed (GObject *object)
157 {
158   GimpSettingsEditor        *editor  = GIMP_SETTINGS_EDITOR (object);
159   GimpSettingsEditorPrivate *private = GET_PRIVATE (object);
160   GimpContainerTreeView     *tree_view;
161 
162   G_OBJECT_CLASS (parent_class)->constructed (object);
163 
164   gimp_assert (GIMP_IS_GIMP (private->gimp));
165   gimp_assert (GIMP_IS_CONFIG (private->config));
166   gimp_assert (GIMP_IS_CONTAINER (private->container));
167 
168   private->view = gimp_container_tree_view_new (private->container,
169                                                 gimp_get_user_context (private->gimp),
170                                                16, 0);
171   gtk_widget_set_size_request (private->view, 200, 200);
172   gtk_box_pack_start (GTK_BOX (editor), private->view, TRUE, TRUE, 0);
173   gtk_widget_show (private->view);
174 
175   tree_view = GIMP_CONTAINER_TREE_VIEW (private->view);
176 
177   gtk_tree_view_set_row_separator_func (tree_view->view,
178                                         gimp_settings_editor_row_separator_func,
179                                         private->view, NULL);
180 
181   g_signal_connect (tree_view, "select-item",
182                     G_CALLBACK (gimp_settings_editor_select_item),
183                     editor);
184 
185   gimp_container_tree_view_connect_name_edited (tree_view,
186                                                 G_CALLBACK (gimp_settings_editor_name_edited),
187                                                 editor);
188 
189   private->import_button =
190     gimp_editor_add_button (GIMP_EDITOR (tree_view),
191                             GIMP_ICON_DOCUMENT_OPEN,
192                             _("Import presets from a file"),
193                             NULL,
194                             G_CALLBACK (gimp_settings_editor_import_clicked),
195                             NULL,
196                             editor);
197 
198   private->export_button =
199     gimp_editor_add_button (GIMP_EDITOR (tree_view),
200                             GIMP_ICON_DOCUMENT_SAVE,
201                             _("Export the selected presets to a file"),
202                             NULL,
203                             G_CALLBACK (gimp_settings_editor_export_clicked),
204                             NULL,
205                             editor);
206 
207   private->delete_button =
208     gimp_editor_add_button (GIMP_EDITOR (tree_view),
209                             GIMP_ICON_EDIT_DELETE,
210                             _("Delete the selected preset"),
211                             NULL,
212                             G_CALLBACK (gimp_settings_editor_delete_clicked),
213                             NULL,
214                             editor);
215 
216   gtk_widget_set_sensitive (private->delete_button, FALSE);
217 }
218 
219 static void
gimp_settings_editor_finalize(GObject * object)220 gimp_settings_editor_finalize (GObject *object)
221 {
222   GimpSettingsEditorPrivate *private = GET_PRIVATE (object);
223 
224   g_clear_object (&private->config);
225   g_clear_object (&private->container);
226 
227   G_OBJECT_CLASS (parent_class)->finalize (object);
228 }
229 
230 static void
gimp_settings_editor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)231 gimp_settings_editor_set_property (GObject      *object,
232                                    guint         property_id,
233                                    const GValue *value,
234                                    GParamSpec   *pspec)
235 {
236   GimpSettingsEditorPrivate *private = GET_PRIVATE (object);
237 
238   switch (property_id)
239     {
240     case PROP_GIMP:
241       private->gimp = g_value_get_object (value); /* don't dup */
242       break;
243 
244     case PROP_CONFIG:
245       private->config = g_value_dup_object (value);
246       break;
247 
248     case PROP_CONTAINER:
249       private->container = g_value_dup_object (value);
250       break;
251 
252    default:
253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
254       break;
255     }
256 }
257 
258 static void
gimp_settings_editor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)259 gimp_settings_editor_get_property (GObject    *object,
260                                    guint       property_id,
261                                    GValue     *value,
262                                    GParamSpec *pspec)
263 {
264   GimpSettingsEditorPrivate *private = GET_PRIVATE (object);
265 
266   switch (property_id)
267     {
268     case PROP_GIMP:
269       g_value_set_object (value, private->gimp);
270       break;
271 
272     case PROP_CONFIG:
273       g_value_set_object (value, private->config);
274       break;
275 
276     case PROP_CONTAINER:
277       g_value_set_object (value, private->container);
278       break;
279 
280    default:
281       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
282       break;
283     }
284 }
285 
286 static gboolean
gimp_settings_editor_row_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)287 gimp_settings_editor_row_separator_func (GtkTreeModel *model,
288                                          GtkTreeIter  *iter,
289                                          gpointer      data)
290 {
291   gchar *name = NULL;
292 
293   gtk_tree_model_get (model, iter,
294                       GIMP_CONTAINER_TREE_STORE_COLUMN_NAME, &name,
295                       -1);
296   g_free (name);
297 
298   return name == NULL;
299 }
300 
301 static void
gimp_settings_editor_select_item(GimpContainerView * view,GimpViewable * viewable,gpointer insert_data,GimpSettingsEditor * editor)302 gimp_settings_editor_select_item (GimpContainerView  *view,
303                                   GimpViewable       *viewable,
304                                   gpointer            insert_data,
305                                   GimpSettingsEditor *editor)
306 {
307   GimpSettingsEditorPrivate *private = GET_PRIVATE (editor);
308   gboolean                   sensitive;
309 
310   private->selected_setting = G_OBJECT (viewable);
311 
312   sensitive = (private->selected_setting != NULL &&
313                gimp_object_get_name (private->selected_setting));
314 
315   gtk_widget_set_sensitive (private->export_button, sensitive);
316   gtk_widget_set_sensitive (private->delete_button, sensitive);
317 }
318 
319 static void
gimp_settings_editor_import_clicked(GtkWidget * widget,GimpSettingsEditor * editor)320 gimp_settings_editor_import_clicked (GtkWidget          *widget,
321                                      GimpSettingsEditor *editor)
322 {
323 }
324 
325 static void
gimp_settings_editor_export_clicked(GtkWidget * widget,GimpSettingsEditor * editor)326 gimp_settings_editor_export_clicked (GtkWidget          *widget,
327                                      GimpSettingsEditor *editor)
328 {
329 }
330 
331 static void
gimp_settings_editor_delete_clicked(GtkWidget * widget,GimpSettingsEditor * editor)332 gimp_settings_editor_delete_clicked (GtkWidget          *widget,
333                                      GimpSettingsEditor *editor)
334 {
335   GimpSettingsEditorPrivate *private = GET_PRIVATE (editor);
336 
337   if (private->selected_setting)
338     {
339       GimpObject *new;
340 
341       new = gimp_container_get_neighbor_of (private->container,
342                                             GIMP_OBJECT (private->selected_setting));
343 
344       /*  don't select the separator  */
345       if (new && ! gimp_object_get_name (new))
346         new = NULL;
347 
348       gimp_container_remove (private->container,
349                              GIMP_OBJECT (private->selected_setting));
350 
351       gimp_container_view_select_item (GIMP_CONTAINER_VIEW (private->view),
352                                        GIMP_VIEWABLE (new));
353 
354       gimp_operation_config_serialize (private->gimp, private->container, NULL);
355     }
356 }
357 
358 static void
gimp_settings_editor_name_edited(GtkCellRendererText * cell,const gchar * path_str,const gchar * new_name,GimpSettingsEditor * editor)359 gimp_settings_editor_name_edited (GtkCellRendererText *cell,
360                                   const gchar         *path_str,
361                                   const gchar         *new_name,
362                                   GimpSettingsEditor  *editor)
363 {
364   GimpSettingsEditorPrivate *private = GET_PRIVATE (editor);
365   GimpContainerTreeView     *tree_view;
366   GtkTreePath               *path;
367   GtkTreeIter                iter;
368 
369   tree_view = GIMP_CONTAINER_TREE_VIEW (private->view);
370 
371   path = gtk_tree_path_new_from_string (path_str);
372 
373   if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
374     {
375       GimpViewRenderer *renderer;
376       GimpObject       *object;
377       const gchar      *old_name;
378       gchar            *name;
379 
380       gtk_tree_model_get (tree_view->model, &iter,
381                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
382                           -1);
383 
384       object = GIMP_OBJECT (renderer->viewable);
385 
386       old_name = gimp_object_get_name (object);
387 
388       if (! old_name) old_name = "";
389       if (! new_name) new_name = "";
390 
391       name = g_strstrip (g_strdup (new_name));
392 
393       if (strlen (name) && strcmp (old_name, name))
394         {
395           gint64 t;
396 
397           g_object_get (object,
398                         "time", &t,
399                         NULL);
400 
401           if (t > 0)
402             g_object_set (object,
403                           "time", (gint64) 0,
404                           NULL);
405 
406           /*  set name after time so the object is reordered correctly  */
407           gimp_object_take_name (object, name);
408 
409           gimp_operation_config_serialize (private->gimp, private->container,
410                                            NULL);
411         }
412       else
413         {
414           g_free (name);
415 
416           name = gimp_viewable_get_description (renderer->viewable, NULL);
417           gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), &iter,
418                               GIMP_CONTAINER_TREE_STORE_COLUMN_NAME, name,
419                               -1);
420           g_free (name);
421         }
422 
423       g_object_unref (renderer);
424     }
425 
426   gtk_tree_path_free (path);
427 }
428 
429 
430 /*  public functions  */
431 
432 GtkWidget *
gimp_settings_editor_new(Gimp * gimp,GObject * config,GimpContainer * container)433 gimp_settings_editor_new (Gimp          *gimp,
434                           GObject       *config,
435                           GimpContainer *container)
436 {
437   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
438   g_return_val_if_fail (GIMP_IS_CONFIG (config), NULL);
439   g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
440 
441   return g_object_new (GIMP_TYPE_SETTINGS_EDITOR,
442                        "gimp",      gimp,
443                        "config",    config,
444                        "container", container,
445                        NULL);
446 }
447