Files
gimp/app/core/gimpdatafactory.c
Michael Natterer 9be16e00bc app: make sure name references to GimpData objects are serialized correctly
They were also serialized correctly before, but only because many
GimpData objects were (bogusly) always dirty after loading, which
caused them to always be written do disk on exit. This commit fixes
this problem and updates by-name references explicitly as things are
renamed, instead of relying on bugs.

Add gimp_data_factory_data_clean() which clears the dirty flags from
all a factory's objects. Call the new function on all factories at the
end of gimp_restore(), when all data has been loaded. This might be
total overkill, but ensures that everything is clean in the beginning.

Add new signal GimpContext::prop_name_changed() which is emitted when
any of the context's object properties (brush, gradient etc) is
renamed.

In GimpToolPreset, connect to the new signal and dirty the preset if a
relevant object propery was renamed, making sure the preset is saved
to disk later. Also optmize updates quite a bit by ignoring
notifications on tool option properties that are irrelevant to the
preset.

This might or might not address the issues discussed in bug #739487.
2015-02-26 22:31:58 +01:00

985 lines
30 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpdatafactory.c
* Copyright (C) 2001 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 "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpconfig/gimpconfig.h"
#include "core-types.h"
#include "gimp.h"
#include "gimp-utils.h"
#include "gimpcontext.h"
#include "gimpdata.h"
#include "gimpdatafactory.h"
#include "gimplist.h"
#include "gimp-intl.h"
/* Data files that have this string in their path are considered
* obsolete and are only kept around for backwards compatibility
*/
#define GIMP_OBSOLETE_DATA_DIR_NAME "gimp-obsolete-files"
typedef void (* GimpDataForeachFunc) (GimpDataFactory *factory,
GimpData *data,
gpointer user_data);
struct _GimpDataFactoryPriv
{
Gimp *gimp;
GimpContainer *container;
GimpContainer *container_obsolete;
gchar *path_property_name;
gchar *writable_property_name;
const GimpDataFactoryLoaderEntry *loader_entries;
gint n_loader_entries;
GimpDataNewFunc data_new_func;
GimpDataGetStandardFunc data_get_standard_func;
};
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_data_foreach (GimpDataFactory *factory,
gboolean skip_internal,
GimpDataForeachFunc callback,
gpointer user_data);
static void gimp_data_factory_data_load (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache);
static GFile * gimp_data_factory_get_save_dir (GimpDataFactory *factory,
GError **error);
static void gimp_data_factory_load_directory (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache,
gboolean dir_writable,
GFile *directory,
GFile *top_directory);
static void gimp_data_factory_load_data (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache,
gboolean dir_writable,
GFile *file,
guint64 mtime,
GFile *top_directory);
G_DEFINE_TYPE (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->finalize = gimp_data_factory_finalize;
gimp_object_class->get_memsize = gimp_data_factory_get_memsize;
g_type_class_add_private (klass, sizeof (GimpDataFactoryPriv));
}
static void
gimp_data_factory_init (GimpDataFactory *factory)
{
factory->priv = G_TYPE_INSTANCE_GET_PRIVATE (factory,
GIMP_TYPE_DATA_FACTORY,
GimpDataFactoryPriv);
factory->priv->gimp = NULL;
factory->priv->container = NULL;
factory->priv->container_obsolete = NULL;
factory->priv->path_property_name = NULL;
factory->priv->writable_property_name = NULL;
factory->priv->loader_entries = NULL;
factory->priv->n_loader_entries = 0;
factory->priv->data_new_func = NULL;
factory->priv->data_get_standard_func = NULL;
}
static void
gimp_data_factory_finalize (GObject *object)
{
GimpDataFactory *factory = GIMP_DATA_FACTORY (object);
if (factory->priv->container)
{
g_object_unref (factory->priv->container);
factory->priv->container = NULL;
}
if (factory->priv->container_obsolete)
{
g_object_unref (factory->priv->container_obsolete);
factory->priv->container_obsolete = NULL;
}
if (factory->priv->path_property_name)
{
g_free (factory->priv->path_property_name);
factory->priv->path_property_name = NULL;
}
if (factory->priv->writable_property_name)
{
g_free (factory->priv->writable_property_name);
factory->priv->writable_property_name = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
gimp_data_factory_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpDataFactory *factory = GIMP_DATA_FACTORY (object);
gint64 memsize = 0;
memsize += gimp_object_get_memsize (GIMP_OBJECT (factory->priv->container),
gui_size);
memsize += gimp_object_get_memsize (GIMP_OBJECT (factory->priv->container_obsolete),
gui_size);
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
GimpDataFactory *
gimp_data_factory_new (Gimp *gimp,
GType data_type,
const gchar *path_property_name,
const gchar *writable_property_name,
const GimpDataFactoryLoaderEntry *loader_entries,
gint n_loader_entries,
GimpDataNewFunc new_func,
GimpDataGetStandardFunc get_standard_func)
{
GimpDataFactory *factory;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (g_type_is_a (data_type, GIMP_TYPE_DATA), NULL);
g_return_val_if_fail (path_property_name != NULL, NULL);
g_return_val_if_fail (writable_property_name != NULL, NULL);
g_return_val_if_fail (loader_entries != NULL, NULL);
g_return_val_if_fail (n_loader_entries > 0, NULL);
factory = g_object_new (GIMP_TYPE_DATA_FACTORY, NULL);
factory->priv->gimp = gimp;
factory->priv->container = gimp_list_new (data_type, TRUE);
gimp_list_set_sort_func (GIMP_LIST (factory->priv->container),
(GCompareFunc) gimp_data_compare);
factory->priv->container_obsolete = gimp_list_new (data_type, TRUE);
gimp_list_set_sort_func (GIMP_LIST (factory->priv->container_obsolete),
(GCompareFunc) gimp_data_compare);
factory->priv->path_property_name = g_strdup (path_property_name);
factory->priv->writable_property_name = g_strdup (writable_property_name);
factory->priv->loader_entries = loader_entries;
factory->priv->n_loader_entries = n_loader_entries;
factory->priv->data_new_func = new_func;
factory->priv->data_get_standard_func = get_standard_func;
return factory;
}
void
gimp_data_factory_data_init (GimpDataFactory *factory,
GimpContext *context,
gboolean no_data)
{
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
g_return_if_fail (GIMP_IS_CONTEXT (context));
/* Freeze and thaw the container even if no_data,
* this creates the standard data that serves as fallback.
*/
gimp_container_freeze (factory->priv->container);
if (! no_data)
{
if (factory->priv->gimp->be_verbose)
{
const gchar *name = gimp_object_get_name (factory);
g_print ("Loading '%s' data\n", name ? name : "???");
}
gimp_data_factory_data_load (factory, context, NULL);
}
gimp_container_thaw (factory->priv->container);
}
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);
}
static void
gimp_data_factory_refresh_cache_add (GimpDataFactory *factory,
GimpData *data,
gpointer user_data)
{
GFile *file = gimp_data_get_file (data);
if (file)
{
GHashTable *cache = user_data;
GList *list;
g_object_ref (data);
gimp_container_remove (factory->priv->container, GIMP_OBJECT (data));
list = g_hash_table_lookup (cache, file);
list = g_list_prepend (list, data);
g_hash_table_insert (cache, file, list);
}
}
static gboolean
gimp_data_factory_refresh_cache_remove (gpointer key,
gpointer value,
gpointer user_data)
{
GList *list;
for (list = value; list; list = list->next)
g_object_unref (list->data);
g_list_free (value);
return TRUE;
}
static void
gimp_data_factory_data_foreach (GimpDataFactory *factory,
gboolean skip_internal,
GimpDataForeachFunc callback,
gpointer user_data)
{
GList *list = GIMP_LIST (factory->priv->container)->list;
if (skip_internal)
{
while (list && gimp_data_is_internal (GIMP_DATA (list->data)))
list = g_list_next (list);
}
while (list)
{
GList *next = g_list_next (list);
callback (factory, list->data, user_data);
list = next;
}
}
static void
gimp_data_factory_data_load (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache)
{
gchar *p;
gchar *wp;
GList *path;
GList *writable_path;
GList *list;
g_object_get (factory->priv->gimp->config,
factory->priv->path_property_name, &p,
factory->priv->writable_property_name, &wp,
NULL);
path = gimp_config_path_expand_to_files (p, NULL);
writable_path = gimp_config_path_expand_to_files (wp, NULL);
g_free (p);
g_free (wp);
for (list = path; list; list = g_list_next (list))
{
gboolean dir_writable = FALSE;
if (g_list_find_custom (writable_path, list->data,
(GCompareFunc) gimp_file_compare))
dir_writable = TRUE;
gimp_data_factory_load_directory (factory, context, cache,
dir_writable,
list->data,
list->data);
}
g_list_free_full (path, (GDestroyNotify) g_object_unref);
g_list_free_full (writable_path, (GDestroyNotify) g_object_unref);
}
void
gimp_data_factory_data_refresh (GimpDataFactory *factory,
GimpContext *context)
{
GHashTable *cache;
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
g_return_if_fail (GIMP_IS_CONTEXT (context));
gimp_container_freeze (factory->priv->container);
/* First, save all dirty data objects */
gimp_data_factory_data_save (factory);
cache = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
gimp_data_factory_data_foreach (factory, TRUE,
gimp_data_factory_refresh_cache_add, cache);
/* Now the cache contains a GFile => list-of-objects mapping of
* the old objects. So we should now traverse the directory and for
* each file load it only if its mtime is newer.
*
* Once a file was added, it is removed from the cache, so the only
* objects remaining there will be those that are not present on
* the disk (that have to be destroyed)
*/
gimp_data_factory_data_load (factory, context, cache);
/* Now all the data is loaded. Free what remains in the cache */
g_hash_table_foreach_remove (cache,
gimp_data_factory_refresh_cache_remove, NULL);
g_hash_table_destroy (cache);
gimp_container_thaw (factory->priv->container);
}
void
gimp_data_factory_data_save (GimpDataFactory *factory)
{
GList *list;
GFile *writable_dir;
GError *error = NULL;
g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
if (gimp_container_is_empty (factory->priv->container))
return;
writable_dir = gimp_data_factory_get_save_dir (factory, &error);
if (! writable_dir)
{
gimp_message (factory->priv->gimp, NULL, GIMP_MESSAGE_ERROR,
_("Failed to save data:\n\n%s"),
error->message);
g_clear_error (&error);
return;
}
for (list = GIMP_LIST (factory->priv->container)->list;
list;
list = g_list_next (list))
{
GimpData *data = list->data;
if (! gimp_data_get_file (data))
gimp_data_create_filename (data, writable_dir);
if (gimp_data_is_dirty (data) &&
gimp_data_is_writable (data))
{
GError *error = NULL;
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 (factory->priv->gimp, NULL, GIMP_MESSAGE_ERROR,
_("Failed to save data:\n\n%s"),
error->message);
g_clear_error (&error);
}
}
}
}
g_object_unref (writable_dir);
}
static void
gimp_data_factory_remove_cb (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_container_freeze (factory->priv->container);
gimp_data_factory_data_foreach (factory, TRUE,
gimp_data_factory_remove_cb, NULL);
gimp_container_thaw (factory->priv->container);
}
GimpData *
gimp_data_factory_data_new (GimpDataFactory *factory,
GimpContext *context,
const gchar *name)
{
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);
if (factory->priv->data_new_func)
{
GimpData *data = factory->priv->data_new_func (context, name);
if (data)
{
gimp_container_add (factory->priv->container, GIMP_OBJECT (data));
g_object_unref (data);
return data;
}
g_warning ("%s: factory->priv->data_new_func() returned NULL", G_STRFUNC);
}
return NULL;
}
GimpData *
gimp_data_factory_data_duplicate (GimpDataFactory *factory,
GimpData *data)
{
GimpData *new_data;
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
g_return_val_if_fail (GIMP_IS_DATA (data), NULL);
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 (factory->priv->container, GIMP_OBJECT (new_data));
g_object_unref (new_data);
}
return new_data;
}
gboolean
gimp_data_factory_data_delete (GimpDataFactory *factory,
GimpData *data,
gboolean delete_from_disk,
GError **error)
{
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);
if (gimp_container_have (factory->priv->container, GIMP_OBJECT (data)))
{
g_object_ref (data);
gimp_container_remove (factory->priv->container, GIMP_OBJECT (data));
if (delete_from_disk && gimp_data_get_file (data))
retval = gimp_data_delete_from_disk (data, error);
g_object_unref (data);
}
return retval;
}
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;
}
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 (! 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;
}
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;
}
Gimp *
gimp_data_factory_get_gimp (GimpDataFactory *factory)
{
g_return_val_if_fail (GIMP_IS_DATA_FACTORY (factory), NULL);
return factory->priv->gimp;
}
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;
}
/* private functions */
static GFile *
gimp_data_factory_get_save_dir (GimpDataFactory *factory,
GError **error)
{
gchar *p;
gchar *wp;
GList *path;
GList *writable_path;
GFile *writable_dir = NULL;
g_object_get (factory->priv->gimp->config,
factory->priv->path_property_name, &p,
factory->priv->writable_property_name, &wp,
NULL);
path = gimp_config_path_expand_to_files (p, NULL);
writable_path = gimp_config_path_expand_to_files (wp, NULL);
g_free (p);
g_free (wp);
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;
}
static void
gimp_data_factory_load_directory (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache,
gboolean dir_writable,
GFile *directory,
GFile *top_directory)
{
GFileEnumerator *enumerator;
enumerator = g_file_enumerate_children (directory,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
G_FILE_ATTRIBUTE_TIME_MODIFIED,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (enumerator)
{
GFileInfo *info;
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
{
GFileType file_type;
GFile *child;
if (g_file_info_get_is_hidden (info))
{
g_object_unref (info);
continue;
}
file_type = g_file_info_get_file_type (info);
child = g_file_enumerator_get_child (enumerator, info);
if (file_type == G_FILE_TYPE_DIRECTORY)
{
gimp_data_factory_load_directory (factory, context, cache,
dir_writable,
child,
top_directory);
}
else if (file_type == G_FILE_TYPE_REGULAR)
{
guint64 mtime;
mtime = g_file_info_get_attribute_uint64 (info,
G_FILE_ATTRIBUTE_TIME_MODIFIED);
gimp_data_factory_load_data (factory, context, cache,
dir_writable,
child, mtime,
top_directory);
}
g_object_unref (child);
g_object_unref (info);
}
g_object_unref (enumerator);
}
}
static void
gimp_data_factory_load_data (GimpDataFactory *factory,
GimpContext *context,
GHashTable *cache,
gboolean dir_writable,
GFile *file,
guint64 mtime,
GFile *top_directory)
{
const GimpDataFactoryLoaderEntry *loader = NULL;
GList *data_list = NULL;
GInputStream *input;
gint i;
GError *error = NULL;
for (i = 0; i < factory->priv->n_loader_entries; i++)
{
loader = &factory->priv->loader_entries[i];
/* a loder matches if its extension matches, or if it doesn't
* have an extension, which is the case for the fallback loader,
* which must be last in the loader array
*/
if (! loader->extension ||
gimp_file_has_extension (file, loader->extension))
{
goto insert;
}
}
return;
insert:
if (cache)
{
GList *cached_data = g_hash_table_lookup (cache, file);
if (cached_data &&
gimp_data_get_mtime (cached_data->data) != 0 &&
gimp_data_get_mtime (cached_data->data) == mtime)
{
GList *list;
for (list = cached_data; list; list = g_list_next (list))
gimp_container_add (factory->priv->container, list->data);
return;
}
}
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
if (input)
{
data_list = loader->load_func (context, file, input, &error);
if (error)
{
g_prefix_error (&error,
_("Error loading '%s': "),
gimp_file_get_utf8_name (file));
}
else if (! data_list)
{
g_set_error (&error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
_("Error loading '%s'"),
gimp_file_get_utf8_name (file));
}
g_object_unref (input);
}
else
{
g_prefix_error (&error,
_("Could not open '%s' for reading: "),
gimp_file_get_utf8_name (file));
}
if (G_LIKELY (data_list))
{
GList *list;
gchar *uri;
gboolean obsolete;
gboolean writable = FALSE;
gboolean deletable = FALSE;
uri = g_file_get_uri (file);
obsolete = (strstr (uri, GIMP_OBSOLETE_DATA_DIR_NAME) != 0);
g_free (uri);
/* obsolete files are immutable, don't check their writability */
if (! obsolete)
{
deletable = (g_list_length (data_list) == 1 && dir_writable);
writable = (deletable && loader->writable);
}
for (list = data_list; list; list = g_list_next (list))
{
GimpData *data = list->data;
gimp_data_set_file (data, file, writable, deletable);
gimp_data_set_mtime (data, mtime);
gimp_data_clean (data);
if (obsolete)
{
gimp_container_add (factory->priv->container_obsolete,
GIMP_OBJECT (data));
}
else
{
gimp_data_set_folder_tags (data, top_directory);
gimp_container_add (factory->priv->container,
GIMP_OBJECT (data));
}
g_object_unref (data);
}
g_list_free (data_list);
}
/* not else { ... } because loader->load_func() can return a list
* of data objects *and* an error message if loading failed after
* something was already loaded
*/
if (G_UNLIKELY (error))
{
gimp_message (factory->priv->gimp, NULL, GIMP_MESSAGE_ERROR,
_("Failed to load data:\n\n%s"), error->message);
g_clear_error (&error);
}
}