1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * gimpitemtree.c
5  * Copyright (C) 2010 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 <stdlib.h>
24 #include <string.h>
25 
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27 #include <gegl.h>
28 
29 #include "core-types.h"
30 
31 #include "gimpimage.h"
32 #include "gimpimage-undo-push.h"
33 #include "gimpitem.h"
34 #include "gimpitemstack.h"
35 #include "gimpitemtree.h"
36 
37 
38 enum
39 {
40   PROP_0,
41   PROP_IMAGE,
42   PROP_CONTAINER_TYPE,
43   PROP_ITEM_TYPE,
44   PROP_ACTIVE_ITEM
45 };
46 
47 
48 typedef struct _GimpItemTreePrivate GimpItemTreePrivate;
49 
50 struct _GimpItemTreePrivate
51 {
52   GimpImage  *image;
53 
54   GType       container_type;
55   GType       item_type;
56 
57   GimpItem   *active_item;
58 
59   GHashTable *name_hash;
60 };
61 
62 #define GIMP_ITEM_TREE_GET_PRIVATE(object) \
63         ((GimpItemTreePrivate *) gimp_item_tree_get_instance_private ((GimpItemTree *) (object)))
64 
65 
66 /*  local function prototypes  */
67 
68 static void     gimp_item_tree_constructed   (GObject      *object);
69 static void     gimp_item_tree_dispose       (GObject      *object);
70 static void     gimp_item_tree_finalize      (GObject      *object);
71 static void     gimp_item_tree_set_property  (GObject      *object,
72                                               guint         property_id,
73                                               const GValue *value,
74                                               GParamSpec   *pspec);
75 static void     gimp_item_tree_get_property  (GObject      *object,
76                                               guint         property_id,
77                                               GValue       *value,
78                                               GParamSpec   *pspec);
79 
80 static gint64   gimp_item_tree_get_memsize   (GimpObject   *object,
81                                               gint64       *gui_size);
82 
83 static void     gimp_item_tree_uniquefy_name (GimpItemTree *tree,
84                                               GimpItem     *item,
85                                               const gchar  *new_name);
86 
87 
G_DEFINE_TYPE_WITH_PRIVATE(GimpItemTree,gimp_item_tree,GIMP_TYPE_OBJECT)88 G_DEFINE_TYPE_WITH_PRIVATE (GimpItemTree, gimp_item_tree, GIMP_TYPE_OBJECT)
89 
90 #define parent_class gimp_item_tree_parent_class
91 
92 
93 static void
94 gimp_item_tree_class_init (GimpItemTreeClass *klass)
95 {
96   GObjectClass    *object_class      = G_OBJECT_CLASS (klass);
97   GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
98 
99   object_class->constructed      = gimp_item_tree_constructed;
100   object_class->dispose          = gimp_item_tree_dispose;
101   object_class->finalize         = gimp_item_tree_finalize;
102   object_class->set_property     = gimp_item_tree_set_property;
103   object_class->get_property     = gimp_item_tree_get_property;
104 
105   gimp_object_class->get_memsize = gimp_item_tree_get_memsize;
106 
107   g_object_class_install_property (object_class, PROP_IMAGE,
108                                    g_param_spec_object ("image",
109                                                         NULL, NULL,
110                                                         GIMP_TYPE_IMAGE,
111                                                         GIMP_PARAM_READWRITE |
112                                                         G_PARAM_CONSTRUCT_ONLY));
113 
114   g_object_class_install_property (object_class, PROP_CONTAINER_TYPE,
115                                    g_param_spec_gtype ("container-type",
116                                                        NULL, NULL,
117                                                        GIMP_TYPE_ITEM_STACK,
118                                                        GIMP_PARAM_READWRITE |
119                                                        G_PARAM_CONSTRUCT_ONLY));
120 
121   g_object_class_install_property (object_class, PROP_ITEM_TYPE,
122                                    g_param_spec_gtype ("item-type",
123                                                        NULL, NULL,
124                                                        GIMP_TYPE_ITEM,
125                                                        GIMP_PARAM_READWRITE |
126                                                        G_PARAM_CONSTRUCT_ONLY));
127 
128   g_object_class_install_property (object_class, PROP_ACTIVE_ITEM,
129                                    g_param_spec_object ("active-item",
130                                                         NULL, NULL,
131                                                         GIMP_TYPE_ITEM,
132                                                         GIMP_PARAM_READWRITE));
133 }
134 
135 static void
gimp_item_tree_init(GimpItemTree * tree)136 gimp_item_tree_init (GimpItemTree *tree)
137 {
138   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
139 
140   private->name_hash = g_hash_table_new (g_str_hash, g_str_equal);
141 }
142 
143 static void
gimp_item_tree_constructed(GObject * object)144 gimp_item_tree_constructed (GObject *object)
145 {
146   GimpItemTree        *tree    = GIMP_ITEM_TREE (object);
147   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
148 
149   G_OBJECT_CLASS (parent_class)->constructed (object);
150 
151   gimp_assert (GIMP_IS_IMAGE (private->image));
152   gimp_assert (g_type_is_a (private->container_type, GIMP_TYPE_ITEM_STACK));
153   gimp_assert (g_type_is_a (private->item_type,      GIMP_TYPE_ITEM));
154   gimp_assert (private->item_type != GIMP_TYPE_ITEM);
155 
156   tree->container = g_object_new (private->container_type,
157                                   "name",          g_type_name (private->item_type),
158                                   "children-type", private->item_type,
159                                   "policy",        GIMP_CONTAINER_POLICY_STRONG,
160                                   NULL);
161 }
162 
163 static void
gimp_item_tree_dispose(GObject * object)164 gimp_item_tree_dispose (GObject *object)
165 {
166   GimpItemTree        *tree    = GIMP_ITEM_TREE (object);
167   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
168 
169   gimp_item_tree_set_active_item (tree, NULL);
170 
171   gimp_container_foreach (tree->container,
172                           (GFunc) gimp_item_removed, NULL);
173 
174   gimp_container_clear (tree->container);
175   g_hash_table_remove_all (private->name_hash);
176 
177   G_OBJECT_CLASS (parent_class)->dispose (object);
178 }
179 
180 static void
gimp_item_tree_finalize(GObject * object)181 gimp_item_tree_finalize (GObject *object)
182 {
183   GimpItemTree        *tree    = GIMP_ITEM_TREE (object);
184   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
185 
186   g_clear_pointer (&private->name_hash, g_hash_table_unref);
187   g_clear_object (&tree->container);
188 
189   G_OBJECT_CLASS (parent_class)->finalize (object);
190 }
191 
192 static void
gimp_item_tree_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)193 gimp_item_tree_set_property (GObject      *object,
194                              guint         property_id,
195                              const GValue *value,
196                              GParamSpec   *pspec)
197 {
198   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (object);
199 
200   switch (property_id)
201     {
202     case PROP_IMAGE:
203       private->image = g_value_get_object (value); /* don't ref */
204       break;
205     case PROP_CONTAINER_TYPE:
206       private->container_type = g_value_get_gtype (value);
207       break;
208     case PROP_ITEM_TYPE:
209       private->item_type = g_value_get_gtype (value);
210       break;
211     case PROP_ACTIVE_ITEM:
212       private->active_item = g_value_get_object (value); /* don't ref */
213       break;
214 
215     default:
216       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
217       break;
218     }
219 }
220 
221 static void
gimp_item_tree_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)222 gimp_item_tree_get_property (GObject    *object,
223                              guint       property_id,
224                              GValue     *value,
225                              GParamSpec *pspec)
226 {
227   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (object);
228 
229   switch (property_id)
230     {
231     case PROP_IMAGE:
232       g_value_set_object (value, private->image);
233       break;
234     case PROP_CONTAINER_TYPE:
235       g_value_set_gtype (value, private->container_type);
236       break;
237     case PROP_ITEM_TYPE:
238       g_value_set_gtype (value, private->item_type);
239       break;
240     case PROP_ACTIVE_ITEM:
241       g_value_set_object (value, private->active_item);
242       break;
243 
244     default:
245       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
246       break;
247     }
248 }
249 
250 static gint64
gimp_item_tree_get_memsize(GimpObject * object,gint64 * gui_size)251 gimp_item_tree_get_memsize (GimpObject *object,
252                             gint64     *gui_size)
253 {
254   GimpItemTree *tree    = GIMP_ITEM_TREE (object);
255   gint64        memsize = 0;
256 
257   memsize += gimp_object_get_memsize (GIMP_OBJECT (tree->container), gui_size);
258 
259   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
260                                                                   gui_size);
261 }
262 
263 
264 /*  public functions  */
265 
266 GimpItemTree *
gimp_item_tree_new(GimpImage * image,GType container_type,GType item_type)267 gimp_item_tree_new (GimpImage *image,
268                     GType      container_type,
269                     GType      item_type)
270 {
271   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
272   g_return_val_if_fail (g_type_is_a (container_type, GIMP_TYPE_ITEM_STACK), NULL);
273   g_return_val_if_fail (g_type_is_a (item_type, GIMP_TYPE_ITEM), NULL);
274 
275   return g_object_new (GIMP_TYPE_ITEM_TREE,
276                        "image",          image,
277                        "container-type", container_type,
278                        "item-type",      item_type,
279                        NULL);
280 }
281 
282 GimpItem *
gimp_item_tree_get_active_item(GimpItemTree * tree)283 gimp_item_tree_get_active_item (GimpItemTree *tree)
284 {
285   g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
286 
287   return GIMP_ITEM_TREE_GET_PRIVATE (tree)->active_item;
288 }
289 
290 void
gimp_item_tree_set_active_item(GimpItemTree * tree,GimpItem * item)291 gimp_item_tree_set_active_item (GimpItemTree *tree,
292                                 GimpItem     *item)
293 {
294   GimpItemTreePrivate *private;
295 
296   g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
297 
298   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
299 
300   g_return_if_fail (item == NULL ||
301                     G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
302   g_return_if_fail (item == NULL || gimp_item_get_tree (item) == tree);
303 
304   if (item != private->active_item)
305     {
306       private->active_item = item;
307 
308       g_object_notify (G_OBJECT (tree), "active-item");
309     }
310 }
311 
312 GimpItem *
gimp_item_tree_get_item_by_name(GimpItemTree * tree,const gchar * name)313 gimp_item_tree_get_item_by_name (GimpItemTree *tree,
314                                  const gchar  *name)
315 {
316   g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
317   g_return_val_if_fail (name != NULL, NULL);
318 
319   return g_hash_table_lookup (GIMP_ITEM_TREE_GET_PRIVATE (tree)->name_hash,
320                               name);
321 }
322 
323 gboolean
gimp_item_tree_get_insert_pos(GimpItemTree * tree,GimpItem * item,GimpItem ** parent,gint * position)324 gimp_item_tree_get_insert_pos (GimpItemTree  *tree,
325                                GimpItem      *item,
326                                GimpItem     **parent,
327                                gint          *position)
328 {
329   GimpItemTreePrivate *private;
330   GimpContainer       *container;
331 
332   g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), FALSE);
333   g_return_val_if_fail (parent != NULL, FALSE);
334 
335   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
336 
337   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
338                         FALSE);
339   g_return_val_if_fail (! gimp_item_is_attached (item), FALSE);
340   g_return_val_if_fail (gimp_item_get_image (item) == private->image, FALSE);
341   g_return_val_if_fail (*parent == NULL ||
342                         *parent == GIMP_IMAGE_ACTIVE_PARENT ||
343                         G_TYPE_CHECK_INSTANCE_TYPE (*parent, private->item_type),
344                         FALSE);
345   g_return_val_if_fail (*parent == NULL ||
346                         *parent == GIMP_IMAGE_ACTIVE_PARENT ||
347                         gimp_item_get_tree (*parent) == tree, FALSE);
348   g_return_val_if_fail (*parent == NULL ||
349                         *parent == GIMP_IMAGE_ACTIVE_PARENT ||
350                         gimp_viewable_get_children (GIMP_VIEWABLE (*parent)),
351                         FALSE);
352   g_return_val_if_fail (position != NULL, FALSE);
353 
354   /*  if we want to insert in the active item's parent container  */
355   if (*parent == GIMP_IMAGE_ACTIVE_PARENT)
356     {
357       if (private->active_item)
358         {
359           /*  if the active item is a branch, add to the top of that
360            *  branch; add to the active item's parent container
361            *  otherwise
362            */
363           if (gimp_viewable_get_children (GIMP_VIEWABLE (private->active_item)))
364             {
365               *parent   = private->active_item;
366               *position = 0;
367             }
368           else
369             {
370               *parent = gimp_item_get_parent (private->active_item);
371             }
372         }
373       else
374         {
375           /*  use the toplevel container if there is no active item  */
376           *parent = NULL;
377         }
378     }
379 
380   if (*parent)
381     container = gimp_viewable_get_children (GIMP_VIEWABLE (*parent));
382   else
383     container = tree->container;
384 
385   /*  if we want to add on top of the active item  */
386   if (*position == -1)
387     {
388       if (private->active_item)
389         *position =
390           gimp_container_get_child_index (container,
391                                           GIMP_OBJECT (private->active_item));
392 
393       /*  if the active item is not in the specified parent container,
394        *  fall back to index 0
395        */
396       if (*position == -1)
397         *position = 0;
398     }
399 
400   /*  don't add at a non-existing index  */
401   *position = CLAMP (*position, 0, gimp_container_get_n_children (container));
402 
403   return TRUE;
404 }
405 
406 void
gimp_item_tree_add_item(GimpItemTree * tree,GimpItem * item,GimpItem * parent,gint position)407 gimp_item_tree_add_item (GimpItemTree *tree,
408                          GimpItem     *item,
409                          GimpItem     *parent,
410                          gint          position)
411 {
412   GimpItemTreePrivate *private;
413   GimpContainer       *container;
414   GimpContainer       *children;
415 
416   g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
417 
418   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
419 
420   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
421   g_return_if_fail (! gimp_item_is_attached (item));
422   g_return_if_fail (gimp_item_get_image (item) == private->image);
423   g_return_if_fail (parent == NULL ||
424                     G_TYPE_CHECK_INSTANCE_TYPE (parent, private->item_type));
425   g_return_if_fail (parent == NULL || gimp_item_get_tree (parent) == tree);
426   g_return_if_fail (parent == NULL ||
427                     gimp_viewable_get_children (GIMP_VIEWABLE (parent)));
428 
429   gimp_item_tree_uniquefy_name (tree, item, NULL);
430 
431   children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
432 
433   if (children)
434     {
435       GList *list = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (children));
436 
437       while (list)
438         {
439           gimp_item_tree_uniquefy_name (tree, list->data, NULL);
440 
441           list = g_list_remove (list, list->data);
442         }
443     }
444 
445   if (parent)
446     container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
447   else
448     container = tree->container;
449 
450   if (parent)
451     gimp_viewable_set_parent (GIMP_VIEWABLE (item),
452                               GIMP_VIEWABLE (parent));
453 
454   gimp_container_insert (container, GIMP_OBJECT (item), position);
455 
456   /*  if the item came from the undo stack, reset its "removed" state  */
457   if (gimp_item_is_removed (item))
458     gimp_item_unset_removed (item);
459 }
460 
461 GimpItem *
gimp_item_tree_remove_item(GimpItemTree * tree,GimpItem * item,GimpItem * new_active)462 gimp_item_tree_remove_item (GimpItemTree *tree,
463                             GimpItem     *item,
464                             GimpItem     *new_active)
465 {
466   GimpItemTreePrivate *private;
467   GimpItem            *parent;
468   GimpContainer       *container;
469   GimpContainer       *children;
470   gint                 index;
471 
472   g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
473 
474   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
475 
476   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
477                         NULL);
478   g_return_val_if_fail (gimp_item_get_tree (item) == tree, NULL);
479 
480   parent    = gimp_item_get_parent (item);
481   container = gimp_item_get_container (item);
482   index     = gimp_item_get_index (item);
483 
484   g_object_ref (item);
485 
486   g_hash_table_remove (private->name_hash,
487                        gimp_object_get_name (item));
488 
489   children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
490 
491   if (children)
492     {
493       GList *list = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (children));
494 
495       while (list)
496         {
497           g_hash_table_remove (private->name_hash,
498                                gimp_object_get_name (list->data));
499 
500           list = g_list_remove (list, list->data);
501         }
502     }
503 
504   gimp_container_remove (container, GIMP_OBJECT (item));
505 
506   if (parent)
507     gimp_viewable_set_parent (GIMP_VIEWABLE (item), NULL);
508 
509   gimp_item_removed (item);
510 
511   if (! new_active)
512     {
513       gint n_children = gimp_container_get_n_children (container);
514 
515       if (n_children > 0)
516         {
517           index = CLAMP (index, 0, n_children - 1);
518 
519           new_active =
520             GIMP_ITEM (gimp_container_get_child_by_index (container, index));
521         }
522       else if (parent)
523         {
524           new_active = parent;
525         }
526     }
527 
528   g_object_unref (item);
529 
530   return new_active;
531 }
532 
533 gboolean
gimp_item_tree_reorder_item(GimpItemTree * tree,GimpItem * item,GimpItem * new_parent,gint new_index,gboolean push_undo,const gchar * undo_desc)534 gimp_item_tree_reorder_item (GimpItemTree *tree,
535                              GimpItem     *item,
536                              GimpItem     *new_parent,
537                              gint          new_index,
538                              gboolean      push_undo,
539                              const gchar  *undo_desc)
540 {
541   GimpItemTreePrivate *private;
542   GimpContainer       *container;
543   GimpContainer       *new_container;
544   gint                 n_items;
545 
546   g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), FALSE);
547 
548   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
549 
550   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
551                         FALSE);
552   g_return_val_if_fail (gimp_item_get_tree (item) == tree, FALSE);
553   g_return_val_if_fail (new_parent == NULL ||
554                         G_TYPE_CHECK_INSTANCE_TYPE (new_parent,
555                                                     private->item_type),
556                         FALSE);
557   g_return_val_if_fail (new_parent == NULL ||
558                         gimp_item_get_tree (new_parent) == tree, FALSE);
559   g_return_val_if_fail (new_parent == NULL ||
560                         gimp_viewable_get_children (GIMP_VIEWABLE (new_parent)),
561                         FALSE);
562   g_return_val_if_fail (item != new_parent, FALSE);
563   g_return_val_if_fail (new_parent == NULL ||
564                         ! gimp_viewable_is_ancestor (GIMP_VIEWABLE (item),
565                                                      GIMP_VIEWABLE (new_parent)),
566                         FALSE);
567 
568   container = gimp_item_get_container (item);
569 
570   if (new_parent)
571     new_container = gimp_viewable_get_children (GIMP_VIEWABLE (new_parent));
572   else
573     new_container = tree->container;
574 
575   n_items = gimp_container_get_n_children (new_container);
576 
577   if (new_container == container)
578     n_items--;
579 
580   new_index = CLAMP (new_index, 0, n_items);
581 
582   if (new_container != container ||
583       new_index     != gimp_item_get_index (item))
584     {
585       if (push_undo)
586         gimp_image_undo_push_item_reorder (private->image, undo_desc, item);
587 
588       if (new_container != container)
589         {
590           g_object_ref (item);
591 
592           gimp_container_remove (container, GIMP_OBJECT (item));
593 
594           gimp_viewable_set_parent (GIMP_VIEWABLE (item),
595                                     GIMP_VIEWABLE (new_parent));
596 
597           gimp_container_insert (new_container, GIMP_OBJECT (item), new_index);
598 
599           g_object_unref (item);
600         }
601       else
602         {
603           gimp_container_reorder (container, GIMP_OBJECT (item), new_index);
604         }
605     }
606 
607   return TRUE;
608 }
609 
610 void
gimp_item_tree_rename_item(GimpItemTree * tree,GimpItem * item,const gchar * new_name,gboolean push_undo,const gchar * undo_desc)611 gimp_item_tree_rename_item (GimpItemTree *tree,
612                             GimpItem     *item,
613                             const gchar  *new_name,
614                             gboolean      push_undo,
615                             const gchar  *undo_desc)
616 {
617   GimpItemTreePrivate *private;
618 
619   g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
620 
621   private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
622 
623   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
624   g_return_if_fail (gimp_item_get_tree (item) == tree);
625   g_return_if_fail (new_name != NULL);
626 
627   if (strcmp (new_name, gimp_object_get_name (item)))
628     {
629       if (push_undo)
630         gimp_image_undo_push_item_rename (gimp_item_get_image (item),
631                                           undo_desc, item);
632 
633       gimp_item_tree_uniquefy_name (tree, item, new_name);
634     }
635 }
636 
637 
638 /*  private functions  */
639 
640 static void
gimp_item_tree_uniquefy_name(GimpItemTree * tree,GimpItem * item,const gchar * new_name)641 gimp_item_tree_uniquefy_name (GimpItemTree *tree,
642                               GimpItem     *item,
643                               const gchar  *new_name)
644 {
645   GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
646 
647   if (new_name)
648     {
649       g_hash_table_remove (private->name_hash,
650                            gimp_object_get_name (item));
651 
652       gimp_object_set_name (GIMP_OBJECT (item), new_name);
653     }
654 
655   /* Remove any trailing whitespace. */
656   if (gimp_object_get_name (item))
657     {
658       gchar *name = g_strchomp (g_strdup (gimp_object_get_name (item)));
659 
660       gimp_object_take_name (GIMP_OBJECT (item), name);
661     }
662 
663   if (g_hash_table_lookup (private->name_hash,
664                            gimp_object_get_name (item)))
665     {
666       gchar      *name        = g_strdup (gimp_object_get_name (item));
667       gchar      *new_name    = NULL;
668       gint        number      = 0;
669       gint        precision   = 1;
670       GRegex     *end_numbers = g_regex_new (" ?#([0-9]+)\\s*$", 0, 0, NULL);
671       GMatchInfo *match_info  = NULL;
672 
673       if (g_regex_match (end_numbers, name, 0, &match_info))
674         {
675           gchar *match;
676           gint   start_pos;
677 
678           match  = g_match_info_fetch (match_info, 1);
679           if (match && match[0] == '0')
680             {
681               precision = strlen (match);
682             }
683           number = atoi (match);
684           g_free (match);
685 
686           g_match_info_fetch_pos (match_info, 0,
687                                   &start_pos, NULL);
688           name[start_pos] = '\0';
689         }
690       g_match_info_free (match_info);
691       g_regex_unref (end_numbers);
692 
693       do
694         {
695           number++;
696 
697           g_free (new_name);
698 
699           new_name = g_strdup_printf ("%s #%.*d",
700                                       name,
701                                       precision,
702                                       number);
703         }
704       while (g_hash_table_lookup (private->name_hash, new_name));
705 
706       g_free (name);
707 
708       gimp_object_take_name (GIMP_OBJECT (item), new_name);
709     }
710 
711   g_hash_table_insert (private->name_hash,
712                        (gpointer) gimp_object_get_name (item),
713                        item);
714 }
715