which is just a #define to g_assert for now, but can now easily be turned into something that does some nicer debugging using our new stack trace infrastructure. This commit also reverts all constructed() functions to use assert again.
700 lines
22 KiB
C
700 lines
22 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
|
*
|
|
* gimpitemtree.c
|
|
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
#include <gegl.h>
|
|
|
|
#include "core-types.h"
|
|
|
|
#include "gimpimage.h"
|
|
#include "gimpimage-undo-push.h"
|
|
#include "gimpitem.h"
|
|
#include "gimpitemstack.h"
|
|
#include "gimpitemtree.h"
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_IMAGE,
|
|
PROP_CONTAINER_TYPE,
|
|
PROP_ITEM_TYPE,
|
|
PROP_ACTIVE_ITEM
|
|
};
|
|
|
|
|
|
typedef struct _GimpItemTreePrivate GimpItemTreePrivate;
|
|
|
|
struct _GimpItemTreePrivate
|
|
{
|
|
GimpImage *image;
|
|
|
|
GType container_type;
|
|
GType item_type;
|
|
|
|
GimpItem *active_item;
|
|
|
|
GHashTable *name_hash;
|
|
};
|
|
|
|
#define GIMP_ITEM_TREE_GET_PRIVATE(object) \
|
|
G_TYPE_INSTANCE_GET_PRIVATE (object, \
|
|
GIMP_TYPE_ITEM_TREE, \
|
|
GimpItemTreePrivate)
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
static void gimp_item_tree_constructed (GObject *object);
|
|
static void gimp_item_tree_finalize (GObject *object);
|
|
static void gimp_item_tree_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_item_tree_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static gint64 gimp_item_tree_get_memsize (GimpObject *object,
|
|
gint64 *gui_size);
|
|
|
|
static void gimp_item_tree_uniquefy_name (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
const gchar *new_name);
|
|
|
|
|
|
G_DEFINE_TYPE (GimpItemTree, gimp_item_tree, GIMP_TYPE_OBJECT)
|
|
|
|
#define parent_class gimp_item_tree_parent_class
|
|
|
|
|
|
static void
|
|
gimp_item_tree_class_init (GimpItemTreeClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
object_class->constructed = gimp_item_tree_constructed;
|
|
object_class->finalize = gimp_item_tree_finalize;
|
|
object_class->set_property = gimp_item_tree_set_property;
|
|
object_class->get_property = gimp_item_tree_get_property;
|
|
|
|
gimp_object_class->get_memsize = gimp_item_tree_get_memsize;
|
|
|
|
g_object_class_install_property (object_class, PROP_IMAGE,
|
|
g_param_spec_object ("image",
|
|
NULL, NULL,
|
|
GIMP_TYPE_IMAGE,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
g_object_class_install_property (object_class, PROP_CONTAINER_TYPE,
|
|
g_param_spec_gtype ("container-type",
|
|
NULL, NULL,
|
|
GIMP_TYPE_ITEM_STACK,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
g_object_class_install_property (object_class, PROP_ITEM_TYPE,
|
|
g_param_spec_gtype ("item-type",
|
|
NULL, NULL,
|
|
GIMP_TYPE_ITEM,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
g_object_class_install_property (object_class, PROP_ACTIVE_ITEM,
|
|
g_param_spec_object ("active-item",
|
|
NULL, NULL,
|
|
GIMP_TYPE_ITEM,
|
|
GIMP_PARAM_READWRITE));
|
|
|
|
g_type_class_add_private (klass, sizeof (GimpItemTreePrivate));
|
|
}
|
|
|
|
static void
|
|
gimp_item_tree_init (GimpItemTree *tree)
|
|
{
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
private->name_hash = g_hash_table_new (g_str_hash, g_str_equal);
|
|
}
|
|
|
|
static void
|
|
gimp_item_tree_constructed (GObject *object)
|
|
{
|
|
GimpItemTree *tree = GIMP_ITEM_TREE (object);
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
|
|
gimp_assert (GIMP_IS_IMAGE (private->image));
|
|
gimp_assert (g_type_is_a (private->container_type, GIMP_TYPE_ITEM_STACK));
|
|
gimp_assert (g_type_is_a (private->item_type, GIMP_TYPE_ITEM));
|
|
gimp_assert (private->item_type != GIMP_TYPE_ITEM);
|
|
|
|
tree->container = g_object_new (private->container_type,
|
|
"name", g_type_name (private->item_type),
|
|
"children-type", private->item_type,
|
|
"policy", GIMP_CONTAINER_POLICY_STRONG,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
gimp_item_tree_finalize (GObject *object)
|
|
{
|
|
GimpItemTree *tree = GIMP_ITEM_TREE (object);
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_clear_pointer (&private->name_hash, g_hash_table_unref);
|
|
g_clear_object (&tree->container);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_item_tree_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_IMAGE:
|
|
private->image = g_value_get_object (value); /* don't ref */
|
|
break;
|
|
case PROP_CONTAINER_TYPE:
|
|
private->container_type = g_value_get_gtype (value);
|
|
break;
|
|
case PROP_ITEM_TYPE:
|
|
private->item_type = g_value_get_gtype (value);
|
|
break;
|
|
case PROP_ACTIVE_ITEM:
|
|
private->active_item = g_value_get_object (value); /* don't ref */
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_item_tree_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_IMAGE:
|
|
g_value_set_object (value, private->image);
|
|
break;
|
|
case PROP_CONTAINER_TYPE:
|
|
g_value_set_gtype (value, private->container_type);
|
|
break;
|
|
case PROP_ITEM_TYPE:
|
|
g_value_set_gtype (value, private->item_type);
|
|
break;
|
|
case PROP_ACTIVE_ITEM:
|
|
g_value_set_object (value, private->active_item);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gint64
|
|
gimp_item_tree_get_memsize (GimpObject *object,
|
|
gint64 *gui_size)
|
|
{
|
|
GimpItemTree *tree = GIMP_ITEM_TREE (object);
|
|
gint64 memsize = 0;
|
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (tree->container), gui_size);
|
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
gui_size);
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
GimpItemTree *
|
|
gimp_item_tree_new (GimpImage *image,
|
|
GType container_type,
|
|
GType item_type)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
|
g_return_val_if_fail (g_type_is_a (container_type, GIMP_TYPE_ITEM_STACK), NULL);
|
|
g_return_val_if_fail (g_type_is_a (item_type, GIMP_TYPE_ITEM), NULL);
|
|
|
|
return g_object_new (GIMP_TYPE_ITEM_TREE,
|
|
"image", image,
|
|
"container-type", container_type,
|
|
"item-type", item_type,
|
|
NULL);
|
|
}
|
|
|
|
GimpItem *
|
|
gimp_item_tree_get_active_item (GimpItemTree *tree)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
|
|
|
|
return GIMP_ITEM_TREE_GET_PRIVATE (tree)->active_item;
|
|
}
|
|
|
|
void
|
|
gimp_item_tree_set_active_item (GimpItemTree *tree,
|
|
GimpItem *item)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_if_fail (item == NULL ||
|
|
G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
|
|
g_return_if_fail (item == NULL || gimp_item_get_tree (item) == tree);
|
|
|
|
if (item != private->active_item)
|
|
{
|
|
private->active_item = item;
|
|
|
|
g_object_notify (G_OBJECT (tree), "active-item");
|
|
}
|
|
}
|
|
|
|
GimpItem *
|
|
gimp_item_tree_get_item_by_name (GimpItemTree *tree,
|
|
const gchar *name)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
return g_hash_table_lookup (GIMP_ITEM_TREE_GET_PRIVATE (tree)->name_hash,
|
|
name);
|
|
}
|
|
|
|
gboolean
|
|
gimp_item_tree_get_insert_pos (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
GimpItem **parent,
|
|
gint *position)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
GimpContainer *container;
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), FALSE);
|
|
g_return_val_if_fail (parent != NULL, FALSE);
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
|
|
FALSE);
|
|
g_return_val_if_fail (! gimp_item_is_attached (item), FALSE);
|
|
g_return_val_if_fail (gimp_item_get_image (item) == private->image, FALSE);
|
|
g_return_val_if_fail (*parent == NULL ||
|
|
*parent == GIMP_IMAGE_ACTIVE_PARENT ||
|
|
G_TYPE_CHECK_INSTANCE_TYPE (*parent, private->item_type),
|
|
FALSE);
|
|
g_return_val_if_fail (*parent == NULL ||
|
|
*parent == GIMP_IMAGE_ACTIVE_PARENT ||
|
|
gimp_item_get_tree (*parent) == tree, FALSE);
|
|
g_return_val_if_fail (*parent == NULL ||
|
|
*parent == GIMP_IMAGE_ACTIVE_PARENT ||
|
|
gimp_viewable_get_children (GIMP_VIEWABLE (*parent)),
|
|
FALSE);
|
|
g_return_val_if_fail (position != NULL, FALSE);
|
|
|
|
/* if we want to insert in the active item's parent container */
|
|
if (*parent == GIMP_IMAGE_ACTIVE_PARENT)
|
|
{
|
|
if (private->active_item)
|
|
{
|
|
/* if the active item is a branch, add to the top of that
|
|
* branch; add to the active item's parent container
|
|
* otherwise
|
|
*/
|
|
if (gimp_viewable_get_children (GIMP_VIEWABLE (private->active_item)))
|
|
{
|
|
*parent = private->active_item;
|
|
*position = 0;
|
|
}
|
|
else
|
|
{
|
|
*parent = gimp_item_get_parent (private->active_item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* use the toplevel container if there is no active item */
|
|
*parent = NULL;
|
|
}
|
|
}
|
|
|
|
if (*parent)
|
|
container = gimp_viewable_get_children (GIMP_VIEWABLE (*parent));
|
|
else
|
|
container = tree->container;
|
|
|
|
/* if we want to add on top of the active item */
|
|
if (*position == -1)
|
|
{
|
|
if (private->active_item)
|
|
*position =
|
|
gimp_container_get_child_index (container,
|
|
GIMP_OBJECT (private->active_item));
|
|
|
|
/* if the active item is not in the specified parent container,
|
|
* fall back to index 0
|
|
*/
|
|
if (*position == -1)
|
|
*position = 0;
|
|
}
|
|
|
|
/* don't add at a non-existing index */
|
|
*position = CLAMP (*position, 0, gimp_container_get_n_children (container));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gimp_item_tree_add_item (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
GimpItem *parent,
|
|
gint position)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
GimpContainer *container;
|
|
GimpContainer *children;
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
|
|
g_return_if_fail (! gimp_item_is_attached (item));
|
|
g_return_if_fail (gimp_item_get_image (item) == private->image);
|
|
g_return_if_fail (parent == NULL ||
|
|
G_TYPE_CHECK_INSTANCE_TYPE (parent, private->item_type));
|
|
g_return_if_fail (parent == NULL || gimp_item_get_tree (parent) == tree);
|
|
g_return_if_fail (parent == NULL ||
|
|
gimp_viewable_get_children (GIMP_VIEWABLE (parent)));
|
|
|
|
gimp_item_tree_uniquefy_name (tree, item, NULL);
|
|
|
|
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
|
|
|
|
if (children)
|
|
{
|
|
GList *list = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (children));
|
|
|
|
while (list)
|
|
{
|
|
gimp_item_tree_uniquefy_name (tree, list->data, NULL);
|
|
|
|
list = g_list_remove (list, list->data);
|
|
}
|
|
}
|
|
|
|
if (parent)
|
|
container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
|
|
else
|
|
container = tree->container;
|
|
|
|
if (parent)
|
|
gimp_viewable_set_parent (GIMP_VIEWABLE (item),
|
|
GIMP_VIEWABLE (parent));
|
|
|
|
gimp_container_insert (container, GIMP_OBJECT (item), position);
|
|
|
|
/* if the item came from the undo stack, reset its "removed" state */
|
|
if (gimp_item_is_removed (item))
|
|
gimp_item_unset_removed (item);
|
|
}
|
|
|
|
GimpItem *
|
|
gimp_item_tree_remove_item (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
GimpItem *new_active)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
GimpItem *parent;
|
|
GimpContainer *container;
|
|
GimpContainer *children;
|
|
gint index;
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), NULL);
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
|
|
NULL);
|
|
g_return_val_if_fail (gimp_item_get_tree (item) == tree, NULL);
|
|
|
|
parent = gimp_item_get_parent (item);
|
|
container = gimp_item_get_container (item);
|
|
index = gimp_item_get_index (item);
|
|
|
|
g_object_ref (item);
|
|
|
|
g_hash_table_remove (private->name_hash,
|
|
gimp_object_get_name (item));
|
|
|
|
children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
|
|
|
|
if (children)
|
|
{
|
|
GList *list = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (children));
|
|
|
|
while (list)
|
|
{
|
|
g_hash_table_remove (private->name_hash,
|
|
gimp_object_get_name (list->data));
|
|
|
|
list = g_list_remove (list, list->data);
|
|
}
|
|
}
|
|
|
|
gimp_container_remove (container, GIMP_OBJECT (item));
|
|
|
|
if (parent)
|
|
gimp_viewable_set_parent (GIMP_VIEWABLE (item), NULL);
|
|
|
|
gimp_item_removed (item);
|
|
|
|
if (! new_active)
|
|
{
|
|
gint n_children = gimp_container_get_n_children (container);
|
|
|
|
if (n_children > 0)
|
|
{
|
|
index = CLAMP (index, 0, n_children - 1);
|
|
|
|
new_active =
|
|
GIMP_ITEM (gimp_container_get_child_by_index (container, index));
|
|
}
|
|
else if (parent)
|
|
{
|
|
new_active = parent;
|
|
}
|
|
}
|
|
|
|
g_object_unref (item);
|
|
|
|
return new_active;
|
|
}
|
|
|
|
gboolean
|
|
gimp_item_tree_reorder_item (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
GimpItem *new_parent,
|
|
gint new_index,
|
|
gboolean push_undo,
|
|
const gchar *undo_desc)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
GimpContainer *container;
|
|
GimpContainer *new_container;
|
|
gint n_items;
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM_TREE (tree), FALSE);
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type),
|
|
FALSE);
|
|
g_return_val_if_fail (gimp_item_get_tree (item) == tree, FALSE);
|
|
g_return_val_if_fail (new_parent == NULL ||
|
|
G_TYPE_CHECK_INSTANCE_TYPE (new_parent,
|
|
private->item_type),
|
|
FALSE);
|
|
g_return_val_if_fail (new_parent == NULL ||
|
|
gimp_item_get_tree (new_parent) == tree, FALSE);
|
|
g_return_val_if_fail (new_parent == NULL ||
|
|
gimp_viewable_get_children (GIMP_VIEWABLE (new_parent)),
|
|
FALSE);
|
|
g_return_val_if_fail (item != new_parent, FALSE);
|
|
g_return_val_if_fail (new_parent == NULL ||
|
|
! gimp_viewable_is_ancestor (GIMP_VIEWABLE (item),
|
|
GIMP_VIEWABLE (new_parent)),
|
|
FALSE);
|
|
|
|
container = gimp_item_get_container (item);
|
|
|
|
if (new_parent)
|
|
new_container = gimp_viewable_get_children (GIMP_VIEWABLE (new_parent));
|
|
else
|
|
new_container = tree->container;
|
|
|
|
n_items = gimp_container_get_n_children (new_container);
|
|
|
|
if (new_container == container)
|
|
n_items--;
|
|
|
|
new_index = CLAMP (new_index, 0, n_items);
|
|
|
|
if (new_container != container ||
|
|
new_index != gimp_item_get_index (item))
|
|
{
|
|
if (push_undo)
|
|
gimp_image_undo_push_item_reorder (private->image, undo_desc, item);
|
|
|
|
if (new_container != container)
|
|
{
|
|
g_object_ref (item);
|
|
|
|
gimp_container_remove (container, GIMP_OBJECT (item));
|
|
|
|
gimp_viewable_set_parent (GIMP_VIEWABLE (item),
|
|
GIMP_VIEWABLE (new_parent));
|
|
|
|
gimp_container_insert (new_container, GIMP_OBJECT (item), new_index);
|
|
|
|
g_object_unref (item);
|
|
}
|
|
else
|
|
{
|
|
gimp_container_reorder (container, GIMP_OBJECT (item), new_index);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gimp_item_tree_rename_item (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
const gchar *new_name,
|
|
gboolean push_undo,
|
|
const gchar *undo_desc)
|
|
{
|
|
GimpItemTreePrivate *private;
|
|
|
|
g_return_if_fail (GIMP_IS_ITEM_TREE (tree));
|
|
|
|
private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (item, private->item_type));
|
|
g_return_if_fail (gimp_item_get_tree (item) == tree);
|
|
g_return_if_fail (new_name != NULL);
|
|
|
|
if (strcmp (new_name, gimp_object_get_name (item)))
|
|
{
|
|
if (push_undo)
|
|
gimp_image_undo_push_item_rename (gimp_item_get_image (item),
|
|
undo_desc, item);
|
|
|
|
gimp_item_tree_uniquefy_name (tree, item, new_name);
|
|
}
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
gimp_item_tree_uniquefy_name (GimpItemTree *tree,
|
|
GimpItem *item,
|
|
const gchar *new_name)
|
|
{
|
|
GimpItemTreePrivate *private = GIMP_ITEM_TREE_GET_PRIVATE (tree);
|
|
|
|
if (new_name)
|
|
{
|
|
g_hash_table_remove (private->name_hash,
|
|
gimp_object_get_name (item));
|
|
|
|
gimp_object_set_name (GIMP_OBJECT (item), new_name);
|
|
}
|
|
|
|
/* Remove any trailing whitespace. */
|
|
if (gimp_object_get_name (item))
|
|
{
|
|
gchar *name = g_strchomp (g_strdup (gimp_object_get_name (item)));
|
|
|
|
gimp_object_take_name (GIMP_OBJECT (item), name);
|
|
}
|
|
|
|
if (g_hash_table_lookup (private->name_hash,
|
|
gimp_object_get_name (item)))
|
|
{
|
|
gchar *name = g_strdup (gimp_object_get_name (item));
|
|
gchar *new_name = NULL;
|
|
gint number = 0;
|
|
gint precision = 1;
|
|
GRegex *end_numbers = g_regex_new (" ?#([0-9]+)\\s*$", 0, 0, NULL);
|
|
GMatchInfo *match_info = NULL;
|
|
|
|
if (g_regex_match (end_numbers, name, 0, &match_info))
|
|
{
|
|
gchar *match;
|
|
gint start_pos;
|
|
|
|
match = g_match_info_fetch (match_info, 1);
|
|
if (match && match[0] == '0')
|
|
{
|
|
precision = strlen (match);
|
|
}
|
|
number = atoi (match);
|
|
g_free (match);
|
|
|
|
g_match_info_fetch_pos (match_info, 0,
|
|
&start_pos, NULL);
|
|
name[start_pos] = '\0';
|
|
}
|
|
g_match_info_free (match_info);
|
|
g_regex_unref (end_numbers);
|
|
|
|
do
|
|
{
|
|
number++;
|
|
|
|
g_free (new_name);
|
|
|
|
new_name = g_strdup_printf ("%s #%.*d",
|
|
name,
|
|
precision,
|
|
number);
|
|
}
|
|
while (g_hash_table_lookup (private->name_hash, new_name));
|
|
|
|
g_free (name);
|
|
|
|
gimp_object_take_name (GIMP_OBJECT (item), new_name);
|
|
}
|
|
|
|
g_hash_table_insert (private->name_hash,
|
|
(gpointer) gimp_object_get_name (item),
|
|
item);
|
|
}
|