/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimpdata.c * Copyright (C) 2001 Michael Natterer * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef G_OS_WIN32 #include #define F_OK 0 #define W_OK 2 #define R_OK 4 #define X_OK 0 /* not really */ #define access(f,p) _access(f,p) #endif #include "libgimpbase/gimpbase.h" #include "core-types.h" #include "gimpdata.h" #include "gimpmarshal.h" #include "gimp-intl.h" enum { DIRTY, LAST_SIGNAL }; static void gimp_data_class_init (GimpDataClass *klass); static void gimp_data_init (GimpData *data, GimpDataClass *data_class); static void gimp_data_finalize (GObject *object); static void gimp_data_name_changed (GimpObject *object); static gint64 gimp_data_get_memsize (GimpObject *object, gint64 *gui_size); static void gimp_data_real_dirty (GimpData *data); static guint data_signals[LAST_SIGNAL] = { 0 }; static GimpViewableClass *parent_class = NULL; GType gimp_data_get_type (void) { static GType data_type = 0; if (! data_type) { static const GTypeInfo data_info = { sizeof (GimpDataClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gimp_data_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GimpData), 0, /* n_preallocs */ (GInstanceInitFunc) gimp_data_init, }; data_type = g_type_register_static (GIMP_TYPE_VIEWABLE, "GimpData", &data_info, 0); } return data_type; } static void gimp_data_class_init (GimpDataClass *klass) { GObjectClass *object_class; GimpObjectClass *gimp_object_class; object_class = G_OBJECT_CLASS (klass); gimp_object_class = GIMP_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); data_signals[DIRTY] = g_signal_new ("dirty", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpDataClass, dirty), NULL, NULL, gimp_marshal_VOID__VOID, G_TYPE_NONE, 0); object_class->finalize = gimp_data_finalize; gimp_object_class->name_changed = gimp_data_name_changed; gimp_object_class->get_memsize = gimp_data_get_memsize; klass->dirty = gimp_data_real_dirty; klass->save = NULL; klass->get_extension = NULL; klass->duplicate = NULL; } static void gimp_data_init (GimpData *data, GimpDataClass *data_class) { data->filename = NULL; data->writable = TRUE; data->deletable = TRUE; data->dirty = TRUE; data->internal = FALSE; data->freeze_count = 0; /* look at the passed class pointer, not at GIMP_DATA_GET_CLASS(data) * here, because the latter is always GimpDataClass itself */ if (! data_class->save) data->writable = FALSE; } static void gimp_data_finalize (GObject *object) { GimpData *data = GIMP_DATA (object); if (data->filename) { g_free (data->filename); data->filename = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static void gimp_data_name_changed (GimpObject *object) { if (GIMP_OBJECT_CLASS (parent_class)->name_changed) GIMP_OBJECT_CLASS (parent_class)->name_changed (object); gimp_data_dirty (GIMP_DATA (object)); } static gint64 gimp_data_get_memsize (GimpObject *object, gint64 *gui_size) { GimpData *data = GIMP_DATA (object); gint64 memsize = 0; if (data->filename) memsize += strlen (data->filename) + 1; return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static void gimp_data_real_dirty (GimpData *data) { data->dirty = TRUE; gimp_viewable_invalidate_preview (GIMP_VIEWABLE (data)); } gboolean gimp_data_save (GimpData *data, GError **error) { gboolean success = FALSE; g_return_val_if_fail (GIMP_IS_DATA (data), FALSE); g_return_val_if_fail (data->writable == TRUE, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (data->internal) { data->dirty = FALSE; return TRUE; } g_return_val_if_fail (data->filename != NULL, FALSE); if (GIMP_DATA_GET_CLASS (data)->save) success = GIMP_DATA_GET_CLASS (data)->save (data, error); if (success) data->dirty = FALSE; return success; } void gimp_data_dirty (GimpData *data) { g_return_if_fail (GIMP_IS_DATA (data)); if (data->freeze_count == 0) g_signal_emit (data, data_signals[DIRTY], 0); } void gimp_data_freeze (GimpData *data) { g_return_if_fail (GIMP_IS_DATA (data)); data->freeze_count++; } void gimp_data_thaw (GimpData *data) { g_return_if_fail (GIMP_IS_DATA (data)); g_return_if_fail (data->freeze_count > 0); data->freeze_count--; if (data->freeze_count == 0) gimp_data_dirty (data); } gboolean gimp_data_delete_from_disk (GimpData *data, GError **error) { g_return_val_if_fail (GIMP_IS_DATA (data), FALSE); g_return_val_if_fail (data->filename != NULL, FALSE); g_return_val_if_fail (data->deletable == TRUE, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (data->internal) return TRUE; if (unlink (data->filename) == -1) { g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_DELETE, _("Could not delete '%s': %s"), gimp_filename_to_utf8 (data->filename), g_strerror (errno)); return FALSE; } return TRUE; } const gchar * gimp_data_get_extension (GimpData *data) { g_return_val_if_fail (GIMP_IS_DATA (data), NULL); if (GIMP_DATA_GET_CLASS (data)->get_extension) return GIMP_DATA_GET_CLASS (data)->get_extension (data); return NULL; } void gimp_data_set_filename (GimpData *data, const gchar *filename, gboolean writable) { g_return_if_fail (GIMP_IS_DATA (data)); g_return_if_fail (filename != NULL); g_return_if_fail (g_path_is_absolute (filename)); if (data->internal) return; if (data->filename) g_free (data->filename); data->filename = g_strdup (filename); data->writable = FALSE; data->deletable = FALSE; /* if the data is supposed to be writable, still check if it really is */ if (writable) { gchar *dirname = g_path_get_dirname (filename); if ((access (filename, F_OK) == 0 && /* check if the file exists */ access (filename, W_OK) == 0) || /* and is writable */ (access (filename, F_OK) != 0 && /* OR doesn't exist */ access (dirname, W_OK) == 0)) /* and we can write to its dir */ { data->writable = TRUE; data->deletable = TRUE; } g_free (dirname); /* if we can't save, we are not writable */ if (! GIMP_DATA_GET_CLASS (data)->save) data->writable = FALSE; } } void gimp_data_create_filename (GimpData *data, const gchar *dest_dir) { gchar *safename; gchar *filename; gchar *fullpath; gint i; gint unum = 1; g_return_if_fail (GIMP_IS_DATA (data)); g_return_if_fail (dest_dir != NULL); g_return_if_fail (g_path_is_absolute (dest_dir)); safename = g_filename_from_utf8 (gimp_object_get_name (GIMP_OBJECT (data)), -1, NULL, NULL, NULL); if (safename[0] == '.') safename[0] = '-'; for (i = 0; safename[i]; i++) if (safename[i] == G_DIR_SEPARATOR || g_ascii_isspace (safename[i])) safename[i] = '-'; filename = g_strconcat (safename, gimp_data_get_extension (data), NULL); fullpath = g_build_filename (dest_dir, filename, NULL); g_free (filename); while (g_file_test (fullpath, G_FILE_TEST_EXISTS)) { g_free (fullpath); filename = g_strdup_printf ("%s-%d%s", safename, unum++, gimp_data_get_extension (data)); fullpath = g_build_filename (dest_dir, filename, NULL); g_free (filename); } g_free (safename); gimp_data_set_filename (data, fullpath, TRUE); g_free (fullpath); } GimpData * gimp_data_duplicate (GimpData *data, gboolean stingy_memory_use) { g_return_val_if_fail (GIMP_IS_DATA (data), NULL); if (GIMP_DATA_GET_CLASS (data)->duplicate) return GIMP_DATA_GET_CLASS (data)->duplicate (data, stingy_memory_use); return NULL; } void gimp_data_make_internal (GimpData *data) { g_return_if_fail (GIMP_IS_DATA (data)); if (data->filename) { g_free (data->filename); data->filename = NULL; } data->internal = TRUE; data->writable = FALSE; data->deletable = FALSE; } gint gimp_data_name_compare (GimpData *data1, GimpData *data2) { /* move the internal objects (like the FG -> BG) gradient) to the top */ if (data1->internal != data2->internal) return data1->internal ? -1 : 1; return gimp_object_name_collate ((GimpObject *) data1, (GimpObject *) data2); } GQuark gimp_data_error_quark (void) { static GQuark quark = 0; if (! quark) quark = g_quark_from_static_string ("gimp-data-error-quark"); return quark; }