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