Gimp/app/core/gimpdatafactory.c
Jehan 9f9c0b4ea6 app: GimpFontFactory doesn't force anymore unique font names.
Note that there is a `container_obsolete` too in GimpDataFactory and I don't
apply the "unique-name" property to it because I'm unsure what it is.

Furthermore, eventually we'll want all types of data to allow duplicate names
(brushes, patterns or whatnot may come from all sources and may be named the
same by different people). But for now, let's focus on fonts before breaking
other parts of the codebase which we might not look into right now.
2023-07-25 23:10:26 +02:00

1003 lines
31 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpdatafactory.c
* Copyright (C) 2001-2018 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <stdlib.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpconfig/gimpconfig.h"
#include "core-types.h"
#include "gimp.h"
#include "gimp-utils.h"
#include "gimpasyncset.h"
#include "gimpcancelable.h"
#include "gimpcontext.h"
#include "gimpdata.h"
#include "gimpdatafactory.h"
#include "gimplist.h"
#include "gimpuncancelablewaitable.h"
#include "gimpwaitable.h"
#include "gimp-intl.h"
enum
{
PROP_0,
PROP_GIMP,
PROP_DATA_TYPE,
PROP_PATH_PROPERTY_NAME,
PROP_WRITABLE_PROPERTY_NAME,
PROP_EXT_PROPERTY_NAME,
PROP_NEW_FUNC,
PROP_GET_STANDARD_FUNC,
PROP_UNIQUE_NAMES
};
struct _GimpDataFactoryPrivate
{
Gimp *gimp;
GType data_type;
GimpContainer *container;
GimpContainer *container_obsolete;
gboolean unique_names;
gchar *path_property_name;
gchar *writable_property_name;
gchar *ext_property_name;
GimpDataNewFunc data_new_func;
GimpDataGetStandardFunc data_get_standard_func;
GimpAsyncSet *async_set;
};
#define GET_PRIVATE(obj) (((GimpDataFactory *) (obj))->priv)
static void gimp_data_factory_constructed (GObject *object);
static void gimp_data_factory_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_data_factory_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_data_factory_finalize (GObject *object);
static gint64 gimp_data_factory_get_memsize (GimpObject *object,
gint64 *gui_size);
static void gimp_data_factory_real_data_save (GimpDataFactory *factory);
static void gimp_data_factory_real_data_cancel (GimpDataFactory *factory);
static GimpData * gimp_data_factory_real_data_duplicate (GimpDataFactory *factory,
GimpData *data);
static gboolean gimp_data_factory_real_data_delete (GimpDataFactory *factory,
GimpData *data,
gboolean delete_from_disk,
GError **error);
static void gimp_data_factory_path_notify (GObject *object,
const GParamSpec *pspec,
GimpDataFactory *factory);
static GFile * gimp_data_factory_get_save_dir (GimpDataFactory *factory,
GError **error);
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GimpDataFactory, gimp_data_factory,
GIMP_TYPE_OBJECT)
#define parent_class gimp_data_factory_parent_class
static void
gimp_data_factory_class_init (GimpDataFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
object_class->constructed = gimp_data_factory_constructed;
object_class->set_property = gimp_data_factory_set_property;
object_class->get_property = gimp_data_factory_get_property;
object_class->finalize = gimp_data_factory_finalize;
gimp_object_class->get_memsize = gimp_data_factory_get_memsize;
klass->data_init = NULL;
klass->data_refresh = NULL;
klass->data_save = gimp_data_factory_real_data_save;
klass->data_cancel = gimp_data_factory_real_data_cancel;
klass->data_duplicate = gimp_data_factory_real_data_duplicate;
klass->data_delete = gimp_data_factory_real_data_delete;
g_object_class_install_property (object_class, PROP_GIMP,
g_param_spec_object ("gimp", NULL, NULL,
GIMP_TYPE_GIMP,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_DATA_TYPE,
g_param_spec_gtype ("data-type", NULL, NULL,
GIMP_TYPE_DATA,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_PATH_PROPERTY_NAME,
g_param_spec_string ("path-property-name",
NULL, NULL,
NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_WRITABLE_PROPERTY_NAME,
g_param_spec_string ("writable-property-name",
NULL, NULL,
NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_EXT_PROPERTY_NAME,
g_param_spec_string ("ext-property-name",
NULL, NULL,
NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_NEW_FUNC,
g_param_spec_pointer ("new-func",
NULL, NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_GET_STANDARD_FUNC,
g_param_spec_pointer ("get-standard-func",
NULL, NULL,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_UNIQUE_NAMES,
g_param_spec_boolean ("unique-names",
NULL, NULL,
TRUE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
gimp_data_factory_init (GimpDataFactory *factory)
{
factory->priv = gimp_data_factory_get_instance_private (factory);
factory->priv->async_set = gimp_async_set_new ();
}
static void
gimp_data_factory_constructed (GObject *object)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_GIMP (priv->gimp));
gimp_assert (g_type_is_a (priv->data_type, GIMP_TYPE_DATA));
gimp_assert (GIMP_DATA_FACTORY_GET_CLASS (object)->data_init != NULL);
gimp_assert (GIMP_DATA_FACTORY_GET_CLASS (object)->data_refresh != NULL);
/* Passing along the "unique names" property to the data container. */
priv->container = gimp_list_new (priv->data_type, priv->unique_names);
gimp_list_set_sort_func (GIMP_LIST (priv->container),
(GCompareFunc) gimp_data_compare);
priv->container_obsolete = gimp_list_new (priv->data_type, TRUE);
gimp_list_set_sort_func (GIMP_LIST (priv->container_obsolete),
(GCompareFunc) gimp_data_compare);
}
static void
gimp_data_factory_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_GIMP:
priv->gimp = g_value_get_object (value); /* don't ref */
break;
case PROP_DATA_TYPE:
priv->data_type = g_value_get_gtype (value);
break;
case PROP_PATH_PROPERTY_NAME:
priv->path_property_name = g_value_dup_string (value);
break;
case PROP_WRITABLE_PROPERTY_NAME:
priv->writable_property_name = g_value_dup_string (value);
break;
case PROP_EXT_PROPERTY_NAME:
priv->ext_property_name = g_value_dup_string (value);
break;
case PROP_NEW_FUNC:
priv->data_new_func = g_value_get_pointer (value);
break;
case PROP_GET_STANDARD_FUNC:
priv->data_get_standard_func = g_value_get_pointer (value);
break;
case PROP_UNIQUE_NAMES:
priv->unique_names = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_data_factory_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_GIMP:
g_value_set_object (value, priv->gimp);
break;
case PROP_DATA_TYPE:
g_value_set_gtype (value, priv->data_type);
break;
case PROP_PATH_PROPERTY_NAME:
g_value_set_string (value, priv->path_property_name);
break;
case PROP_WRITABLE_PROPERTY_NAME:
g_value_set_string (value, priv->writable_property_name);
break;
case PROP_EXT_PROPERTY_NAME:
g_value_set_string (value, priv->ext_property_name);
break;
case PROP_NEW_FUNC:
g_value_set_pointer (value, priv->data_new_func);
break;
case PROP_GET_STANDARD_FUNC:
g_value_set_pointer (value, priv->data_get_standard_func);
break;
case PROP_UNIQUE_NAMES:
g_value_set_boolean (value, priv->unique_names);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_data_factory_finalize (GObject *object)
{
GimpDataFactory *factory = GIMP_DATA_FACTORY (object);
GimpDataFactoryPrivate *priv = GET_PRIVATE (object);
if (priv->async_set)
{
gimp_data_factory_data_cancel (factory);
g_clear_object (&priv->async_set);
}
g_clear_object (&priv->container);
g_clear_object (&priv->container_obsolete);
g_clear_pointer (&priv->path_property_name, g_free);
g_clear_pointer (&priv->writable_property_name, g_free);
g_clear_pointer (&priv->ext_property_name, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
gimp_data_factory_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (object);
gint64 memsize = 0;
memsize += gimp_object_get_memsize (GIMP_OBJECT (priv->container),
gui_size);
memsize += gimp_object_get_memsize (GIMP_OBJECT (priv->container_obsolete),
gui_size);
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static void
gimp_data_factory_real_data_save (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
GList *dirty = NULL;
GList *list;
GFile *writable_dir;
GError *error = NULL;
for (list = GIMP_LIST (priv->container)->queue->head;
list;
list = g_list_next (list))
{
GimpData *data = list->data;
if (gimp_data_is_dirty (data) &&
gimp_data_is_writable (data))
{
dirty = g_list_prepend (dirty, data);
}
}
if (! dirty)
return;
writable_dir = gimp_data_factory_get_save_dir (factory, &error);
if (! writable_dir)
{
gimp_message (priv->gimp, NULL, GIMP_MESSAGE_ERROR,
_("Failed to save data:\n\n%s"),
error->message);
g_clear_error (&error);
g_list_free (dirty);
return;
}
for (list = dirty; list; list = g_list_next (list))
{
GimpData *data = list->data;
GError *error = NULL;
if (! gimp_data_get_file (data))
gimp_data_create_filename (data, writable_dir);
if (factory->priv->gimp->be_verbose)
{
GFile *file = gimp_data_get_file (data);
if (file)
g_print ("Writing dirty data '%s'\n",
gimp_file_get_utf8_name (file));
}
if (! gimp_data_save (data, &error))
{
/* check if there actually was an error (no error
* means the data class does not implement save)
*/
if (error)
{
gimp_message (priv->gimp, NULL, GIMP_MESSAGE_ERROR,
_("Failed to save data:\n\n%s"),
error->message);
g_clear_error (&error);
}
}
}
g_object_unref (writable_dir);
g_list_free (dirty);
}
static void
gimp_data_factory_real_data_cancel (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
gimp_cancelable_cancel (GIMP_CANCELABLE (priv->async_set));
gimp_waitable_wait (GIMP_WAITABLE (priv->async_set));
}
static GimpData *
gimp_data_factory_real_data_duplicate (GimpDataFactory *factory,
GimpData *data)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
GimpData *new_data;
new_data = gimp_data_duplicate (data);
if (new_data)
{
const gchar *name = gimp_object_get_name (data);
gchar *ext;
gint copy_len;
gint number;
gchar *new_name;
ext = strrchr (name, '#');
copy_len = strlen (_("copy"));
if ((strlen (name) >= copy_len &&
strcmp (&name[strlen (name) - copy_len], _("copy")) == 0) ||
(ext && (number = atoi (ext + 1)) > 0 &&
((gint) (log10 (number) + 1)) == strlen (ext + 1)))
{
/* don't have redundant "copy"s */
new_name = g_strdup (name);
}
else
{
new_name = g_strdup_printf (_("%s copy"), name);
}
gimp_object_take_name (GIMP_OBJECT (new_data), new_name);
gimp_container_add (priv->container, GIMP_OBJECT (new_data));
g_object_unref (new_data);
}
return new_data;
}
static gboolean
gimp_data_factory_real_data_delete (GimpDataFactory *factory,
GimpData *data,
gboolean delete_from_disk,
GError **error)
{
if (delete_from_disk && gimp_data_get_file (data))
return gimp_data_delete_from_disk (data, error);
return TRUE;
}
/* public functions */
void
gimp_data_factory_data_init (GimpDataFactory *factory,
GimpContext *context,
gboolean no_data)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
gchar *signal_name;
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
g_return_if_fail (GIMP_IS_CONTEXT (context));
/* Always freeze() and thaw() the container around initialization,
* even if no_data, the thaw() will implicitly make GimpContext
* create the standard data that serves as fallback.
*/
gimp_container_freeze (priv->container);
if (! no_data)
{
if (priv->gimp->be_verbose)
{
const gchar *name = gimp_object_get_name (factory);
g_print ("Loading '%s' data\n", name ? name : "???");
}
GIMP_DATA_FACTORY_GET_CLASS (factory)->data_init (factory, context);
}
gimp_container_thaw (priv->container);
signal_name = g_strdup_printf ("notify::%s", priv->path_property_name);
g_signal_connect_object (priv->gimp->config, signal_name,
G_CALLBACK (gimp_data_factory_path_notify),
factory, 0);
g_free (signal_name);
signal_name = g_strdup_printf ("notify::%s", priv->ext_property_name);
g_signal_connect_object (priv->gimp->extension_manager, signal_name,
G_CALLBACK (gimp_data_factory_path_notify),
factory, 0);
g_free (signal_name);
}
static void
gimp_data_factory_clean_cb (GimpDataFactory *factory,
GimpData *data,
gpointer user_data)
{
if (gimp_data_is_dirty (data))
gimp_data_clean (data);
}
void
gimp_data_factory_data_clean (GimpDataFactory *factory)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
gimp_data_factory_data_foreach (factory, TRUE,
gimp_data_factory_clean_cb, NULL);
}
void
gimp_data_factory_data_refresh (GimpDataFactory *factory,
GimpContext *context)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
g_return_if_fail (GIMP_IS_CONTEXT (context));
GIMP_DATA_FACTORY_GET_CLASS (factory)->data_refresh (factory, context);
}
void
gimp_data_factory_data_save (GimpDataFactory *factory)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
if (! gimp_container_is_empty (factory->priv->container))
GIMP_DATA_FACTORY_GET_CLASS (factory)->data_save (factory);
}
static void
gimp_data_factory_data_free_foreach (GimpDataFactory *factory,
GimpData *data,
gpointer user_data)
{
gimp_container_remove (factory->priv->container, GIMP_OBJECT (data));
}
void
gimp_data_factory_data_free (GimpDataFactory *factory)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
gimp_data_factory_data_cancel (factory);
if (! gimp_container_is_empty (factory->priv->container))
{
gimp_container_freeze (factory->priv->container);
gimp_data_factory_data_foreach (factory, TRUE,
gimp_data_factory_data_free_foreach,
NULL);
gimp_container_thaw (factory->priv->container);
}
}
GimpAsyncSet *
gimp_data_factory_get_async_set (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
return factory->priv->async_set;
}
gboolean
gimp_data_factory_data_wait (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv;
GimpWaitable *waitable;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), FALSE);
priv = GET_PRIVATE (factory);
/* don't allow cancellation for now */
waitable = gimp_uncancelable_waitable_new (GIMP_WAITABLE (priv->async_set));
gimp_wait (priv->gimp, waitable,
_("Loading fonts (this may take a while...)"));
g_object_unref (waitable);
return TRUE;
}
void
gimp_data_factory_data_cancel (GimpDataFactory *factory)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
GIMP_DATA_FACTORY_GET_CLASS (factory)->data_cancel (factory);
}
gboolean
gimp_data_factory_has_data_new_func (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), FALSE);
return factory->priv->data_new_func != NULL;
}
GimpData *
gimp_data_factory_data_new (GimpDataFactory *factory,
GimpContext *context,
const gchar *name)
{
GimpDataFactoryPrivate *priv;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (*name != '\0', NULL);
priv = GET_PRIVATE (factory);
if (priv->data_new_func)
{
GimpData *data = priv->data_new_func (context, name);
if (data)
{
gimp_container_add (priv->container, GIMP_OBJECT (data));
g_object_unref (data);
return data;
}
g_warning ("%s: GimpDataFactory::data_new_func() returned NULL",
G_STRFUNC);
}
return NULL;
}
GimpData *
gimp_data_factory_data_get_standard (GimpDataFactory *factory,
GimpContext *context)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
if (factory->priv->data_get_standard_func)
return factory->priv->data_get_standard_func (context);
return NULL;
}
GimpData *
gimp_data_factory_data_duplicate (GimpDataFactory *factory,
GimpData *data)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_return_val_if_fail (GIMP_IS_DATA (data), NULL);
return GIMP_DATA_FACTORY_GET_CLASS (factory)->data_duplicate (factory, data);
}
gboolean
gimp_data_factory_data_delete (GimpDataFactory *factory,
GimpData *data,
gboolean delete_from_disk,
GError **error)
{
GimpDataFactoryPrivate *priv;
gboolean retval = TRUE;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), FALSE);
g_return_val_if_fail (GIMP_IS_DATA (data), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = GET_PRIVATE (factory);
if (gimp_container_have (priv->container, GIMP_OBJECT (data)))
{
g_object_ref (data);
gimp_container_remove (priv->container, GIMP_OBJECT (data));
retval = GIMP_DATA_FACTORY_GET_CLASS (factory)->data_delete (factory, data,
delete_from_disk,
error);
g_object_unref (data);
}
return retval;
}
gboolean
gimp_data_factory_data_save_single (GimpDataFactory *factory,
GimpData *data,
GError **error)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), FALSE);
g_return_val_if_fail (GIMP_IS_DATA (data), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (! gimp_data_is_dirty (data))
return TRUE;
if (! gimp_data_get_file (data))
{
GFile *writable_dir;
GError *my_error = NULL;
writable_dir = gimp_data_factory_get_save_dir (factory, &my_error);
if (! writable_dir)
{
g_set_error (error, GIMP_DATA_ERROR, 0,
_("Failed to save data:\n\n%s"),
my_error->message);
g_clear_error (&my_error);
return FALSE;
}
gimp_data_create_filename (data, writable_dir);
g_object_unref (writable_dir);
}
if (! gimp_data_is_writable (data))
return FALSE;
if (factory->priv->gimp->be_verbose)
{
GFile *file = gimp_data_get_file (data);
if (file)
g_print ("Writing dirty data '%s'\n",
gimp_file_get_utf8_name (file));
}
if (! gimp_data_save (data, error))
{
/* check if there actually was an error (no error
* means the data class does not implement save)
*/
if (! error)
g_set_error (error, GIMP_DATA_ERROR, 0,
_("Failed to save data:\n\n%s"),
"Data class does not implement saving");
return FALSE;
}
return TRUE;
}
void
gimp_data_factory_data_foreach (GimpDataFactory *factory,
gboolean skip_internal,
GimpDataForeachFunc callback,
gpointer user_data)
{
GList *list;
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
g_return_if_fail (callback != NULL);
list = GIMP_LIST (factory->priv->container)->queue->head;
while (list)
{
GList *next = g_list_next (list);
if (! (skip_internal && gimp_data_is_internal (list->data)))
callback (factory, list->data, user_data);
list = next;
}
}
Gimp *
gimp_data_factory_get_gimp (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
return factory->priv->gimp;
}
GType
gimp_data_factory_get_data_type (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), G_TYPE_NONE);
return gimp_container_get_children_type (factory->priv->container);
}
GimpContainer *
gimp_data_factory_get_container (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
return factory->priv->container;
}
GimpContainer *
gimp_data_factory_get_container_obsolete (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
return factory->priv->container_obsolete;
}
GList *
gimp_data_factory_get_data_path (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
gchar *path = NULL;
GList *list = NULL;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_object_get (priv->gimp->config,
priv->path_property_name, &path,
NULL);
if (path)
{
list = gimp_config_path_expand_to_files (path, NULL);
g_free (path);
}
return list;
}
GList *
gimp_data_factory_get_data_path_writable (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
gchar *path = NULL;
GList *list = NULL;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_object_get (priv->gimp->config,
priv->writable_property_name, &path,
NULL);
if (path)
{
list = gimp_config_path_expand_to_files (path, NULL);
g_free (path);
}
return list;
}
const GList *
gimp_data_factory_get_data_path_ext (GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
GList *list = NULL;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_object_get (priv->gimp->extension_manager,
priv->ext_property_name, &list,
NULL);
return list;
}
/* private functions */
static void
gimp_data_factory_path_notify (GObject *object,
const GParamSpec *pspec,
GimpDataFactory *factory)
{
GimpDataFactoryPrivate *priv = GET_PRIVATE (factory);
gimp_set_busy (priv->gimp);
gimp_data_factory_data_refresh (factory, gimp_get_user_context (priv->gimp));
gimp_unset_busy (priv->gimp);
}
static GFile *
gimp_data_factory_get_save_dir (GimpDataFactory *factory,
GError **error)
{
GList *path;
GList *writable_path;
GFile *writable_dir = NULL;
path = gimp_data_factory_get_data_path (factory);
writable_path = gimp_data_factory_get_data_path_writable (factory);
if (writable_path)
{
GList *list;
gboolean found_any = FALSE;
for (list = writable_path; list; list = g_list_next (list))
{
GList *found = g_list_find_custom (path, list->data,
(GCompareFunc) gimp_file_compare);
if (found)
{
GFile *dir = found->data;
found_any = TRUE;
if (g_file_query_file_type (dir, G_FILE_QUERY_INFO_NONE,
NULL) != G_FILE_TYPE_DIRECTORY)
{
/* error out only if this is the last chance */
if (! list->next)
{
g_set_error (error, GIMP_DATA_ERROR, 0,
_("You have a writable data folder "
"configured (%s), but this folder does "
"not exist. Please create the folder or "
"fix your configuration in the "
"Preferences dialog's 'Folders' section."),
gimp_file_get_utf8_name (dir));
}
}
else
{
writable_dir = g_object_ref (dir);
break;
}
}
}
if (! writable_dir && ! found_any)
{
g_set_error (error, GIMP_DATA_ERROR, 0,
_("You have a writable data folder configured, but this "
"folder is not part of your data search path. You "
"probably edited the gimprc file manually, "
"please fix it in the Preferences dialog's 'Folders' "
"section."));
}
}
else
{
g_set_error (error, GIMP_DATA_ERROR, 0,
_("You don't have any writable data folder configured."));
}
g_list_free_full (path, (GDestroyNotify) g_object_unref);
g_list_free_full (writable_path, (GDestroyNotify) g_object_unref);
return writable_dir;
}