1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpcontainereditor.c
5 * Copyright (C) 2001-2011 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 <gegl.h>
24 #include <gtk/gtk.h>
25
26 #include "libgimpwidgets/gimpwidgets.h"
27
28 #include "widgets-types.h"
29
30 #include "core/gimpasyncset.h"
31 #include "core/gimpcontext.h"
32 #include "core/gimplist.h"
33 #include "core/gimpviewable.h"
34
35 #include "gimpcontainereditor.h"
36 #include "gimpcontainergridview.h"
37 #include "gimpcontainericonview.h"
38 #include "gimpcontainertreeview.h"
39 #include "gimpcontainerview.h"
40 #include "gimpdocked.h"
41 #include "gimpmenufactory.h"
42 #include "gimpviewrenderer.h"
43 #include "gimpuimanager.h"
44
45
46 enum
47 {
48 PROP_0,
49 PROP_VIEW_TYPE,
50 PROP_CONTAINER,
51 PROP_CONTEXT,
52 PROP_VIEW_SIZE,
53 PROP_VIEW_BORDER_WIDTH,
54 PROP_MENU_FACTORY,
55 PROP_MENU_IDENTIFIER,
56 PROP_UI_PATH
57 };
58
59
60 struct _GimpContainerEditorPrivate
61 {
62 GimpViewType view_type;
63 GimpContainer *container;
64 GimpContext *context;
65 gint view_size;
66 gint view_border_width;
67 GimpMenuFactory *menu_factory;
68 gchar *menu_identifier;
69 gchar *ui_path;
70 GtkWidget *busy_box;
71 GBinding *async_set_binding;
72 };
73
74
75 static void gimp_container_editor_docked_iface_init (GimpDockedInterface *iface);
76
77 static void gimp_container_editor_constructed (GObject *object);
78 static void gimp_container_editor_dispose (GObject *object);
79 static void gimp_container_editor_set_property (GObject *object,
80 guint property_id,
81 const GValue *value,
82 GParamSpec *pspec);
83 static void gimp_container_editor_get_property (GObject *object,
84 guint property_id,
85 GValue *value,
86 GParamSpec *pspec);
87
88 static gboolean gimp_container_editor_select_item (GtkWidget *widget,
89 GimpViewable *viewable,
90 gpointer insert_data,
91 GimpContainerEditor *editor);
92 static void gimp_container_editor_activate_item (GtkWidget *widget,
93 GimpViewable *viewable,
94 gpointer insert_data,
95 GimpContainerEditor *editor);
96 static void gimp_container_editor_context_item (GtkWidget *widget,
97 GimpViewable *viewable,
98 gpointer insert_data,
99 GimpContainerEditor *editor);
100 static void gimp_container_editor_real_context_item(GimpContainerEditor *editor,
101 GimpViewable *viewable);
102
103 static GtkWidget * gimp_container_editor_get_preview (GimpDocked *docked,
104 GimpContext *context,
105 GtkIconSize size);
106 static void gimp_container_editor_set_context (GimpDocked *docked,
107 GimpContext *context);
108 static GimpUIManager * gimp_container_editor_get_menu(GimpDocked *docked,
109 const gchar **ui_path,
110 gpointer *popup_data);
111
112 static gboolean gimp_container_editor_has_button_bar (GimpDocked *docked);
113 static void gimp_container_editor_set_show_button_bar (GimpDocked *docked,
114 gboolean show);
115 static gboolean gimp_container_editor_get_show_button_bar (GimpDocked *docked);
116
117
G_DEFINE_TYPE_WITH_CODE(GimpContainerEditor,gimp_container_editor,GTK_TYPE_BOX,G_ADD_PRIVATE (GimpContainerEditor)G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,gimp_container_editor_docked_iface_init))118 G_DEFINE_TYPE_WITH_CODE (GimpContainerEditor, gimp_container_editor,
119 GTK_TYPE_BOX,
120 G_ADD_PRIVATE (GimpContainerEditor)
121 G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
122 gimp_container_editor_docked_iface_init))
123
124 #define parent_class gimp_container_editor_parent_class
125
126
127 static void
128 gimp_container_editor_class_init (GimpContainerEditorClass *klass)
129 {
130 GObjectClass *object_class = G_OBJECT_CLASS (klass);
131
132 object_class->constructed = gimp_container_editor_constructed;
133 object_class->dispose = gimp_container_editor_dispose;
134 object_class->set_property = gimp_container_editor_set_property;
135 object_class->get_property = gimp_container_editor_get_property;
136
137 klass->select_item = NULL;
138 klass->activate_item = NULL;
139 klass->context_item = gimp_container_editor_real_context_item;
140
141 g_object_class_install_property (object_class, PROP_VIEW_TYPE,
142 g_param_spec_enum ("view-type",
143 NULL, NULL,
144 GIMP_TYPE_VIEW_TYPE,
145 GIMP_VIEW_TYPE_LIST,
146 GIMP_PARAM_READWRITE |
147 G_PARAM_CONSTRUCT_ONLY));
148
149 g_object_class_install_property (object_class, PROP_CONTAINER,
150 g_param_spec_object ("container",
151 NULL, NULL,
152 GIMP_TYPE_CONTAINER,
153 GIMP_PARAM_READWRITE |
154 G_PARAM_CONSTRUCT_ONLY));
155
156 g_object_class_install_property (object_class, PROP_CONTEXT,
157 g_param_spec_object ("context",
158 NULL, NULL,
159 GIMP_TYPE_CONTEXT,
160 GIMP_PARAM_READWRITE |
161 G_PARAM_CONSTRUCT_ONLY));
162
163 g_object_class_install_property (object_class, PROP_VIEW_SIZE,
164 g_param_spec_int ("view-size",
165 NULL, NULL,
166 1, GIMP_VIEWABLE_MAX_PREVIEW_SIZE,
167 GIMP_VIEW_SIZE_MEDIUM,
168 GIMP_PARAM_READWRITE |
169 G_PARAM_CONSTRUCT));
170
171 g_object_class_install_property (object_class, PROP_VIEW_BORDER_WIDTH,
172 g_param_spec_int ("view-border-width",
173 NULL, NULL,
174 0,
175 GIMP_VIEW_MAX_BORDER_WIDTH,
176 1,
177 GIMP_PARAM_READWRITE |
178 G_PARAM_CONSTRUCT));
179
180 g_object_class_install_property (object_class, PROP_MENU_FACTORY,
181 g_param_spec_object ("menu-factory",
182 NULL, NULL,
183 GIMP_TYPE_MENU_FACTORY,
184 GIMP_PARAM_READWRITE |
185 G_PARAM_CONSTRUCT_ONLY));
186
187 g_object_class_install_property (object_class, PROP_MENU_IDENTIFIER,
188 g_param_spec_string ("menu-identifier",
189 NULL, NULL,
190 NULL,
191 GIMP_PARAM_READWRITE |
192 G_PARAM_CONSTRUCT_ONLY));
193
194 g_object_class_install_property (object_class, PROP_UI_PATH,
195 g_param_spec_string ("ui-path",
196 NULL, NULL,
197 NULL,
198 GIMP_PARAM_READWRITE |
199 G_PARAM_CONSTRUCT_ONLY));
200 }
201
202 static void
gimp_container_editor_docked_iface_init(GimpDockedInterface * iface)203 gimp_container_editor_docked_iface_init (GimpDockedInterface *iface)
204 {
205 iface->get_preview = gimp_container_editor_get_preview;
206 iface->set_context = gimp_container_editor_set_context;
207 iface->get_menu = gimp_container_editor_get_menu;
208 iface->has_button_bar = gimp_container_editor_has_button_bar;
209 iface->set_show_button_bar = gimp_container_editor_set_show_button_bar;
210 iface->get_show_button_bar = gimp_container_editor_get_show_button_bar;
211 }
212
213 static void
gimp_container_editor_init(GimpContainerEditor * editor)214 gimp_container_editor_init (GimpContainerEditor *editor)
215 {
216 gtk_orientable_set_orientation (GTK_ORIENTABLE (editor),
217 GTK_ORIENTATION_VERTICAL);
218
219 editor->priv = gimp_container_editor_get_instance_private (editor);
220 }
221
222 static void
gimp_container_editor_constructed(GObject * object)223 gimp_container_editor_constructed (GObject *object)
224 {
225 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (object);
226
227 G_OBJECT_CLASS (parent_class)->constructed (object);
228
229 gimp_assert (GIMP_IS_CONTAINER (editor->priv->container));
230 gimp_assert (GIMP_IS_CONTEXT (editor->priv->context));
231
232 switch (editor->priv->view_type)
233 {
234 case GIMP_VIEW_TYPE_GRID:
235 #if 0
236 editor->view =
237 GIMP_CONTAINER_VIEW (gimp_container_icon_view_new (editor->priv->container,
238 editor->priv->context,
239 editor->priv->view_size,
240 editor->priv->view_border_width));
241 #else
242 editor->view =
243 GIMP_CONTAINER_VIEW (gimp_container_grid_view_new (editor->priv->container,
244 editor->priv->context,
245 editor->priv->view_size,
246 editor->priv->view_border_width));
247 #endif
248 break;
249
250 case GIMP_VIEW_TYPE_LIST:
251 editor->view =
252 GIMP_CONTAINER_VIEW (gimp_container_tree_view_new (editor->priv->container,
253 editor->priv->context,
254 editor->priv->view_size,
255 editor->priv->view_border_width));
256 break;
257
258 default:
259 gimp_assert_not_reached ();
260 }
261
262 if (GIMP_IS_LIST (editor->priv->container))
263 gimp_container_view_set_reorderable (GIMP_CONTAINER_VIEW (editor->view),
264 ! GIMP_LIST (editor->priv->container)->sort_func);
265
266 if (editor->priv->menu_factory &&
267 editor->priv->menu_identifier &&
268 editor->priv->ui_path)
269 {
270 gimp_editor_create_menu (GIMP_EDITOR (editor->view),
271 editor->priv->menu_factory,
272 editor->priv->menu_identifier,
273 editor->priv->ui_path,
274 editor);
275 }
276
277 gtk_box_pack_start (GTK_BOX (editor), GTK_WIDGET (editor->view),
278 TRUE, TRUE, 0);
279 gtk_widget_show (GTK_WIDGET (editor->view));
280
281 editor->priv->busy_box = gimp_busy_box_new (NULL);
282 gtk_box_pack_start (GTK_BOX (editor), editor->priv->busy_box, TRUE, TRUE, 0);
283
284 g_object_bind_property (editor->priv->busy_box, "visible",
285 editor->view, "visible",
286 G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
287
288 /* Connect "select-item" with G_CONNECT_AFTER because it's a
289 * RUN_LAST signal and the default handler selecting the row must
290 * run before signal connections. See bug #784176.
291 */
292 g_signal_connect_object (editor->view, "select-item",
293 G_CALLBACK (gimp_container_editor_select_item),
294 editor, G_CONNECT_AFTER);
295
296 g_signal_connect_object (editor->view, "activate-item",
297 G_CALLBACK (gimp_container_editor_activate_item),
298 editor, 0);
299 g_signal_connect_object (editor->view, "context-item",
300 G_CALLBACK (gimp_container_editor_context_item),
301 editor, 0);
302
303 {
304 GimpObject *object = gimp_context_get_by_type (editor->priv->context,
305 gimp_container_get_children_type (editor->priv->container));
306
307 gimp_container_editor_select_item (GTK_WIDGET (editor->view),
308 (GimpViewable *) object, NULL,
309 editor);
310 }
311 }
312
313 static void
gimp_container_editor_dispose(GObject * object)314 gimp_container_editor_dispose (GObject *object)
315 {
316 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (object);
317
318 gimp_container_editor_bind_to_async_set (editor, NULL, NULL);
319
320 g_clear_object (&editor->priv->container);
321 g_clear_object (&editor->priv->context);
322 g_clear_object (&editor->priv->menu_factory);
323
324 g_clear_pointer (&editor->priv->menu_identifier, g_free);
325 g_clear_pointer (&editor->priv->ui_path, g_free);
326
327 G_OBJECT_CLASS (parent_class)->dispose (object);
328 }
329
330 static void
gimp_container_editor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)331 gimp_container_editor_set_property (GObject *object,
332 guint property_id,
333 const GValue *value,
334 GParamSpec *pspec)
335 {
336 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (object);
337
338 switch (property_id)
339 {
340 case PROP_VIEW_TYPE:
341 editor->priv->view_type = g_value_get_enum (value);
342 break;
343
344 case PROP_CONTAINER:
345 editor->priv->container = g_value_dup_object (value);
346 break;
347
348 case PROP_CONTEXT:
349 editor->priv->context = g_value_dup_object (value);
350 break;
351
352 case PROP_VIEW_SIZE:
353 editor->priv->view_size = g_value_get_int (value);
354 break;
355
356 case PROP_VIEW_BORDER_WIDTH:
357 editor->priv->view_border_width = g_value_get_int (value);
358 break;
359
360 case PROP_MENU_FACTORY:
361 editor->priv->menu_factory = g_value_dup_object (value);
362 break;
363
364 case PROP_MENU_IDENTIFIER:
365 editor->priv->menu_identifier = g_value_dup_string (value);
366 break;
367
368 case PROP_UI_PATH:
369 editor->priv->ui_path = g_value_dup_string (value);
370 break;
371
372 default:
373 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
374 break;
375 }
376 }
377
378 static void
gimp_container_editor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)379 gimp_container_editor_get_property (GObject *object,
380 guint property_id,
381 GValue *value,
382 GParamSpec *pspec)
383 {
384 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (object);
385
386 switch (property_id)
387 {
388 case PROP_VIEW_TYPE:
389 g_value_set_enum (value, editor->priv->view_type);
390 break;
391
392 case PROP_CONTAINER:
393 g_value_set_object (value, editor->priv->container);
394 break;
395
396 case PROP_CONTEXT:
397 g_value_set_object (value, editor->priv->context);
398 break;
399
400 case PROP_VIEW_SIZE:
401 g_value_set_int (value, editor->priv->view_size);
402 break;
403
404 case PROP_VIEW_BORDER_WIDTH:
405 g_value_set_int (value, editor->priv->view_border_width);
406 break;
407
408 case PROP_MENU_FACTORY:
409 g_value_set_object (value, editor->priv->menu_factory);
410 break;
411
412 case PROP_MENU_IDENTIFIER:
413 g_value_set_string (value, editor->priv->menu_identifier);
414 break;
415
416 case PROP_UI_PATH:
417 g_value_set_string (value, editor->priv->ui_path);
418 break;
419
420 default:
421 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
422 break;
423 }
424 }
425
426 GtkSelectionMode
gimp_container_editor_get_selection_mode(GimpContainerEditor * editor)427 gimp_container_editor_get_selection_mode (GimpContainerEditor *editor)
428 {
429 return gimp_container_view_get_selection_mode (GIMP_CONTAINER_VIEW (editor->view));
430 }
431
432 void
gimp_container_editor_set_selection_mode(GimpContainerEditor * editor,GtkSelectionMode mode)433 gimp_container_editor_set_selection_mode (GimpContainerEditor *editor,
434 GtkSelectionMode mode)
435 {
436 gimp_container_view_set_selection_mode (GIMP_CONTAINER_VIEW (editor->view),
437 mode);
438 }
439
440 /* private functions */
441
442 static gboolean
gimp_container_editor_select_item(GtkWidget * widget,GimpViewable * viewable,gpointer insert_data,GimpContainerEditor * editor)443 gimp_container_editor_select_item (GtkWidget *widget,
444 GimpViewable *viewable,
445 gpointer insert_data,
446 GimpContainerEditor *editor)
447 {
448 GimpContainerEditorClass *klass = GIMP_CONTAINER_EDITOR_GET_CLASS (editor);
449
450 if (klass->select_item)
451 klass->select_item (editor, viewable);
452
453 if (gimp_editor_get_ui_manager (GIMP_EDITOR (editor->view)))
454 gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (editor->view)),
455 gimp_editor_get_popup_data (GIMP_EDITOR (editor->view)));
456
457 return TRUE;
458 }
459
460 static void
gimp_container_editor_activate_item(GtkWidget * widget,GimpViewable * viewable,gpointer insert_data,GimpContainerEditor * editor)461 gimp_container_editor_activate_item (GtkWidget *widget,
462 GimpViewable *viewable,
463 gpointer insert_data,
464 GimpContainerEditor *editor)
465 {
466 GimpContainerEditorClass *klass = GIMP_CONTAINER_EDITOR_GET_CLASS (editor);
467
468 if (klass->activate_item)
469 klass->activate_item (editor, viewable);
470 }
471
472 static void
gimp_container_editor_context_item(GtkWidget * widget,GimpViewable * viewable,gpointer insert_data,GimpContainerEditor * editor)473 gimp_container_editor_context_item (GtkWidget *widget,
474 GimpViewable *viewable,
475 gpointer insert_data,
476 GimpContainerEditor *editor)
477 {
478 GimpContainerEditorClass *klass = GIMP_CONTAINER_EDITOR_GET_CLASS (editor);
479
480 if (klass->context_item)
481 klass->context_item (editor, viewable);
482 }
483
484 static void
gimp_container_editor_real_context_item(GimpContainerEditor * editor,GimpViewable * viewable)485 gimp_container_editor_real_context_item (GimpContainerEditor *editor,
486 GimpViewable *viewable)
487 {
488 GimpContainer *container = gimp_container_view_get_container (editor->view);
489
490 if (viewable && gimp_container_have (container, GIMP_OBJECT (viewable)))
491 {
492 gimp_editor_popup_menu (GIMP_EDITOR (editor->view), NULL, NULL);
493 }
494 }
495
496 static GtkWidget *
gimp_container_editor_get_preview(GimpDocked * docked,GimpContext * context,GtkIconSize size)497 gimp_container_editor_get_preview (GimpDocked *docked,
498 GimpContext *context,
499 GtkIconSize size)
500 {
501 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
502
503 return gimp_docked_get_preview (GIMP_DOCKED (editor->view),
504 context, size);
505 }
506
507 static void
gimp_container_editor_set_context(GimpDocked * docked,GimpContext * context)508 gimp_container_editor_set_context (GimpDocked *docked,
509 GimpContext *context)
510 {
511 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
512
513 gimp_docked_set_context (GIMP_DOCKED (editor->view), context);
514 }
515
516 static GimpUIManager *
gimp_container_editor_get_menu(GimpDocked * docked,const gchar ** ui_path,gpointer * popup_data)517 gimp_container_editor_get_menu (GimpDocked *docked,
518 const gchar **ui_path,
519 gpointer *popup_data)
520 {
521 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
522
523 return gimp_docked_get_menu (GIMP_DOCKED (editor->view), ui_path, popup_data);
524 }
525
526 static gboolean
gimp_container_editor_has_button_bar(GimpDocked * docked)527 gimp_container_editor_has_button_bar (GimpDocked *docked)
528 {
529 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
530
531 return gimp_docked_has_button_bar (GIMP_DOCKED (editor->view));
532 }
533
534 static void
gimp_container_editor_set_show_button_bar(GimpDocked * docked,gboolean show)535 gimp_container_editor_set_show_button_bar (GimpDocked *docked,
536 gboolean show)
537 {
538 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
539
540 gimp_docked_set_show_button_bar (GIMP_DOCKED (editor->view), show);
541 }
542
543 static gboolean
gimp_container_editor_get_show_button_bar(GimpDocked * docked)544 gimp_container_editor_get_show_button_bar (GimpDocked *docked)
545 {
546 GimpContainerEditor *editor = GIMP_CONTAINER_EDITOR (docked);
547
548 return gimp_docked_get_show_button_bar (GIMP_DOCKED (editor->view));
549 }
550
551 void
gimp_container_editor_bind_to_async_set(GimpContainerEditor * editor,GimpAsyncSet * async_set,const gchar * message)552 gimp_container_editor_bind_to_async_set (GimpContainerEditor *editor,
553 GimpAsyncSet *async_set,
554 const gchar *message)
555 {
556 g_return_if_fail (GIMP_IS_CONTAINER_EDITOR (editor));
557 g_return_if_fail (async_set == NULL || GIMP_IS_ASYNC_SET (async_set));
558 g_return_if_fail (async_set == NULL || message != NULL);
559
560 if (! async_set && ! editor->priv->async_set_binding)
561 return;
562
563 g_clear_object (&editor->priv->async_set_binding);
564
565 if (async_set)
566 {
567 gimp_busy_box_set_message (GIMP_BUSY_BOX (editor->priv->busy_box),
568 message);
569
570 editor->priv->async_set_binding = g_object_bind_property (
571 async_set, "empty",
572 editor->priv->busy_box, "visible",
573 G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
574 }
575 else
576 {
577 gtk_widget_hide (editor->priv->busy_box);
578 }
579 }
580