Files
gimp/app/core/gimplist.c
Michael Natterer 28e1a379e6 app: remove const qualifiers from all object parameters
They are unreliable because every type checking cast discards them,
they are useless anyway, visual clutter, added inconsistently, and
generally suck. Wanted to do this a long time ago, it was a bad idea
in the first place.
2016-05-19 23:54:14 +02:00

655 lines
19 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* gimplist.c
* Copyright (C) 2001-2016 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> /* strcmp */
#include <glib-object.h>
#include "core-types.h"
#include "gimp-memsize.h"
#include "gimplist.h"
enum
{
PROP_0,
PROP_UNIQUE_NAMES,
PROP_SORT_FUNC,
PROP_APPEND
};
static void gimp_list_finalize (GObject *object);
static void gimp_list_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_list_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gint64 gimp_list_get_memsize (GimpObject *object,
gint64 *gui_size);
static void gimp_list_add (GimpContainer *container,
GimpObject *object);
static void gimp_list_remove (GimpContainer *container,
GimpObject *object);
static void gimp_list_reorder (GimpContainer *container,
GimpObject *object,
gint new_index);
static void gimp_list_clear (GimpContainer *container);
static gboolean gimp_list_have (GimpContainer *container,
GimpObject *object);
static void gimp_list_foreach (GimpContainer *container,
GFunc func,
gpointer user_data);
static GimpObject * gimp_list_get_child_by_name (GimpContainer *container,
const gchar *name);
static GimpObject * gimp_list_get_child_by_index (GimpContainer *container,
gint index);
static gint gimp_list_get_child_index (GimpContainer *container,
GimpObject *object);
static void gimp_list_uniquefy_name (GimpList *gimp_list,
GimpObject *object);
static void gimp_list_object_renamed (GimpObject *object,
GimpList *list);
G_DEFINE_TYPE (GimpList, gimp_list, GIMP_TYPE_CONTAINER)
#define parent_class gimp_list_parent_class
static void
gimp_list_class_init (GimpListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
GimpContainerClass *container_class = GIMP_CONTAINER_CLASS (klass);
object_class->finalize = gimp_list_finalize;
object_class->set_property = gimp_list_set_property;
object_class->get_property = gimp_list_get_property;
gimp_object_class->get_memsize = gimp_list_get_memsize;
container_class->add = gimp_list_add;
container_class->remove = gimp_list_remove;
container_class->reorder = gimp_list_reorder;
container_class->clear = gimp_list_clear;
container_class->have = gimp_list_have;
container_class->foreach = gimp_list_foreach;
container_class->get_child_by_name = gimp_list_get_child_by_name;
container_class->get_child_by_index = gimp_list_get_child_by_index;
container_class->get_child_index = gimp_list_get_child_index;
g_object_class_install_property (object_class, PROP_UNIQUE_NAMES,
g_param_spec_boolean ("unique-names",
NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_SORT_FUNC,
g_param_spec_pointer ("sort-func",
NULL, NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_APPEND,
g_param_spec_boolean ("append",
NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
gimp_list_init (GimpList *list)
{
list->queue = g_queue_new ();
list->unique_names = FALSE;
list->sort_func = NULL;
list->append = FALSE;
}
static void
gimp_list_finalize (GObject *object)
{
GimpList *list = GIMP_LIST (object);
if (list->queue)
{
g_queue_free (list->queue);
list->queue = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_list_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpList *list = GIMP_LIST (object);
switch (property_id)
{
case PROP_UNIQUE_NAMES:
list->unique_names = g_value_get_boolean (value);
break;
case PROP_SORT_FUNC:
gimp_list_set_sort_func (list, g_value_get_pointer (value));
break;
case PROP_APPEND:
list->append = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_list_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpList *list = GIMP_LIST (object);
switch (property_id)
{
case PROP_UNIQUE_NAMES:
g_value_set_boolean (value, list->unique_names);
break;
case PROP_SORT_FUNC:
g_value_set_pointer (value, list->sort_func);
break;
case PROP_APPEND:
g_value_set_boolean (value, list->append);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gint64
gimp_list_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpList *list = GIMP_LIST (object);
gint64 memsize = 0;
if (gimp_container_get_policy (GIMP_CONTAINER (list)) ==
GIMP_CONTAINER_POLICY_STRONG)
{
memsize += gimp_g_queue_get_memsize_foreach (list->queue,
(GimpMemsizeFunc) gimp_object_get_memsize,
gui_size);
}
else
{
memsize += gimp_g_queue_get_memsize (list->queue, 0);
}
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static gint
gimp_list_sort_func (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
GCompareFunc func = user_data;
return func (a, b);
}
static void
gimp_list_add (GimpContainer *container,
GimpObject *object)
{
GimpList *list = GIMP_LIST (container);
if (list->unique_names)
gimp_list_uniquefy_name (list, object);
if (list->unique_names || list->sort_func)
g_signal_connect (object, "name-changed",
G_CALLBACK (gimp_list_object_renamed),
list);
if (list->sort_func)
{
g_queue_insert_sorted (list->queue, object, gimp_list_sort_func,
list->sort_func);
}
else if (list->append)
{
g_queue_push_tail (list->queue, object);
}
else
{
g_queue_push_head (list->queue, object);
}
GIMP_CONTAINER_CLASS (parent_class)->add (container, object);
}
static void
gimp_list_remove (GimpContainer *container,
GimpObject *object)
{
GimpList *list = GIMP_LIST (container);
if (list->unique_names || list->sort_func)
g_signal_handlers_disconnect_by_func (object,
gimp_list_object_renamed,
list);
g_queue_remove (list->queue, object);
GIMP_CONTAINER_CLASS (parent_class)->remove (container, object);
}
static void
gimp_list_reorder (GimpContainer *container,
GimpObject *object,
gint new_index)
{
GimpList *list = GIMP_LIST (container);
g_queue_remove (list->queue, object);
if (new_index == gimp_container_get_n_children (container) - 1)
g_queue_push_tail (list->queue, object);
else
g_queue_push_nth (list->queue, object, new_index);
}
static void
gimp_list_clear (GimpContainer *container)
{
GimpList *list = GIMP_LIST (container);
while (g_queue_peek_head (list->queue))
gimp_container_remove (container, g_queue_peek_head (list->queue));
}
static gboolean
gimp_list_have (GimpContainer *container,
GimpObject *object)
{
GimpList *list = GIMP_LIST (container);
return g_queue_find (list->queue, object) ? TRUE : FALSE;
}
static void
gimp_list_foreach (GimpContainer *container,
GFunc func,
gpointer user_data)
{
GimpList *list = GIMP_LIST (container);
g_queue_foreach (list->queue, func, user_data);
}
static GimpObject *
gimp_list_get_child_by_name (GimpContainer *container,
const gchar *name)
{
GimpList *list = GIMP_LIST (container);
GList *glist;
for (glist = list->queue->head; glist; glist = g_list_next (glist))
{
GimpObject *object = glist->data;
if (! strcmp (gimp_object_get_name (object), name))
return object;
}
return NULL;
}
static GimpObject *
gimp_list_get_child_by_index (GimpContainer *container,
gint index)
{
GimpList *list = GIMP_LIST (container);
return g_queue_peek_nth (list->queue, index);
}
static gint
gimp_list_get_child_index (GimpContainer *container,
GimpObject *object)
{
GimpList *list = GIMP_LIST (container);
return g_queue_index (list->queue, (gpointer) object);
}
/**
* gimp_list_new:
* @children_type: the #GType of objects the list is going to hold
* @unique_names: if the list should ensure that all its children
* have unique names.
*
* Creates a new #GimpList object. Since #GimpList is a #GimpContainer
* implementation, it holds GimpObjects. Thus @children_type must be
* GIMP_TYPE_OBJECT or a type derived from it.
*
* The returned list has the #GIMP_CONTAINER_POLICY_STRONG.
*
* Return value: a new #GimpList object
**/
GimpContainer *
gimp_list_new (GType children_type,
gboolean unique_names)
{
GimpList *list;
g_return_val_if_fail (g_type_is_a (children_type, GIMP_TYPE_OBJECT), NULL);
list = g_object_new (GIMP_TYPE_LIST,
"children-type", children_type,
"policy", GIMP_CONTAINER_POLICY_STRONG,
"unique-names", unique_names ? TRUE : FALSE,
NULL);
/* for debugging purposes only */
gimp_object_set_static_name (GIMP_OBJECT (list), g_type_name (children_type));
return GIMP_CONTAINER (list);
}
/**
* gimp_list_new_weak:
* @children_type: the #GType of objects the list is going to hold
* @unique_names: if the list should ensure that all its children
* have unique names.
*
* Creates a new #GimpList object. Since #GimpList is a #GimpContainer
* implementation, it holds GimpObjects. Thus @children_type must be
* GIMP_TYPE_OBJECT or a type derived from it.
*
* The returned list has the #GIMP_CONTAINER_POLICY_WEAK.
*
* Return value: a new #GimpList object
**/
GimpContainer *
gimp_list_new_weak (GType children_type,
gboolean unique_names)
{
GimpList *list;
g_return_val_if_fail (g_type_is_a (children_type, GIMP_TYPE_OBJECT), NULL);
list = g_object_new (GIMP_TYPE_LIST,
"children-type", children_type,
"policy", GIMP_CONTAINER_POLICY_WEAK,
"unique-names", unique_names ? TRUE : FALSE,
NULL);
/* for debugging purposes only */
gimp_object_set_static_name (GIMP_OBJECT (list), g_type_name (children_type));
return GIMP_CONTAINER (list);
}
/**
* gimp_list_reverse:
* @list: a #GimpList
*
* Reverses the order of elements in a #GimpList.
**/
void
gimp_list_reverse (GimpList *list)
{
g_return_if_fail (GIMP_IS_LIST (list));
if (gimp_container_get_n_children (GIMP_CONTAINER (list)) > 1)
{
gimp_container_freeze (GIMP_CONTAINER (list));
g_queue_reverse (list->queue);
gimp_container_thaw (GIMP_CONTAINER (list));
}
}
/**
* gimp_list_set_sort_func:
* @list: a #GimpList
* @sort_func: a #GCompareFunc
*
* Sorts the elements of @list using gimp_list_sort() and remembers the
* passed @sort_func in order to keep the list ordered across inserting
* or renaming children.
**/
void
gimp_list_set_sort_func (GimpList *list,
GCompareFunc sort_func)
{
g_return_if_fail (GIMP_IS_LIST (list));
if (sort_func != list->sort_func)
{
if (sort_func)
gimp_list_sort (list, sort_func);
list->sort_func = sort_func;
g_object_notify (G_OBJECT (list), "sort-func");
}
}
/**
* gimp_list_get_sort_func:
* @list: a #GimpList
*
* Returns the @list's sort function, see gimp_list_set_sort_func().
*
* Return Value: The @list's sort function.
**/
GCompareFunc
gimp_list_get_sort_func (GimpList*list)
{
g_return_val_if_fail (GIMP_IS_LIST (list), NULL);
return list->sort_func;
}
/**
* gimp_list_sort:
* @list: a #GimpList
* @sort_func: a #GCompareFunc
*
* Sorts the elements of a #GimpList according to the given @sort_func.
* See g_list_sort() for a detailed description of this function.
**/
void
gimp_list_sort (GimpList *list,
GCompareFunc sort_func)
{
g_return_if_fail (GIMP_IS_LIST (list));
g_return_if_fail (sort_func != NULL);
if (gimp_container_get_n_children (GIMP_CONTAINER (list)) > 1)
{
gimp_container_freeze (GIMP_CONTAINER (list));
g_queue_sort (list->queue, gimp_list_sort_func, sort_func);
gimp_container_thaw (GIMP_CONTAINER (list));
}
}
/**
* gimp_list_sort_by_name:
* @list: a #GimpList
*
* Sorts the #GimpObject elements of a #GimpList by their names.
**/
void
gimp_list_sort_by_name (GimpList *list)
{
g_return_if_fail (GIMP_IS_LIST (list));
gimp_list_sort (list, (GCompareFunc) gimp_object_name_collate);
}
/* private functions */
static void
gimp_list_uniquefy_name (GimpList *gimp_list,
GimpObject *object)
{
gchar *name = (gchar *) gimp_object_get_name (object);
GList *list;
if (! name)
return;
for (list = gimp_list->queue->head; list; list = g_list_next (list))
{
GimpObject *object2 = list->data;
const gchar *name2 = gimp_object_get_name (object2);
if (object != object2 &&
name2 &&
! strcmp (name, name2))
break;
}
if (list)
{
gchar *ext;
gchar *new_name = NULL;
gint unique_ext = 0;
name = g_strdup (name);
ext = strrchr (name, '#');
if (ext)
{
gchar ext_str[8];
unique_ext = atoi (ext + 1);
g_snprintf (ext_str, sizeof (ext_str), "%d", unique_ext);
/* check if the extension really is of the form "#<n>" */
if (! strcmp (ext_str, ext + 1))
{
if (ext > name && *(ext - 1) == ' ')
ext--;
*ext = '\0';
}
else
{
unique_ext = 0;
}
}
do
{
unique_ext++;
g_free (new_name);
new_name = g_strdup_printf ("%s #%d", name, unique_ext);
for (list = gimp_list->queue->head; list; list = g_list_next (list))
{
GimpObject *object2 = list->data;
const gchar *name2 = gimp_object_get_name (object2);
if (object != object2 &&
name2 &&
! strcmp (new_name, name2))
break;
}
}
while (list);
g_free (name);
gimp_object_take_name (object, new_name);
}
}
static void
gimp_list_object_renamed (GimpObject *object,
GimpList *list)
{
if (list->unique_names)
{
g_signal_handlers_block_by_func (object,
gimp_list_object_renamed,
list);
gimp_list_uniquefy_name (list, object);
g_signal_handlers_unblock_by_func (object,
gimp_list_object_renamed,
list);
}
if (list->sort_func)
{
GList *glist;
gint old_index;
gint new_index = 0;
old_index = g_queue_index (list->queue, object);
for (glist = list->queue->head; glist; glist = g_list_next (glist))
{
GimpObject *object2 = GIMP_OBJECT (glist->data);
if (object == object2)
continue;
if (list->sort_func (object, object2) > 0)
new_index++;
else
break;
}
if (new_index != old_index)
gimp_container_reorder (GIMP_CONTAINER (list), object, new_index);
}
}