diff options
Diffstat (limited to 'libgimpwidgets/gimpcolorprofilestore.c')
-rw-r--r-- | libgimpwidgets/gimpcolorprofilestore.c | 794 |
1 files changed, 794 insertions, 0 deletions
diff --git a/libgimpwidgets/gimpcolorprofilestore.c b/libgimpwidgets/gimpcolorprofilestore.c new file mode 100644 index 0000000..324e4c6 --- /dev/null +++ b/libgimpwidgets/gimpcolorprofilestore.c @@ -0,0 +1,794 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpprofilestore.c + * Copyright (C) 2004-2008 Sven Neumann <sven@gimp.org> + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <gtk/gtk.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "gimpwidgetstypes.h" + +#include "gimpcolorprofilestore.h" +#include "gimpcolorprofilestore-private.h" + +#include "libgimp/libgimp-intl.h" + + +/** + * SECTION: gimpcolorprofilestore + * @title: GimpColorProfileStore + * @short_description: A #GtkListStore subclass that keep color profiles. + * + * A #GtkListStore subclass that keep color profiles. + **/ + + +#define HISTORY_SIZE 8 + +enum +{ + PROP_0, + PROP_HISTORY +}; + + +static void gimp_color_profile_store_constructed (GObject *object); +static void gimp_color_profile_store_dispose (GObject *object); +static void gimp_color_profile_store_finalize (GObject *object); +static void gimp_color_profile_store_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_color_profile_store_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gboolean gimp_color_profile_store_history_insert (GimpColorProfileStore *store, + GtkTreeIter *iter, + GFile *file, + const gchar *label, + gint index); +static void gimp_color_profile_store_get_separator (GimpColorProfileStore *store, + GtkTreeIter *iter, + gboolean top); +static gboolean gimp_color_profile_store_save (GimpColorProfileStore *store, + const gchar *filename, + GError **error); +static gboolean gimp_color_profile_store_load (GimpColorProfileStore *store, + const gchar *filename, + GError **error); + + +G_DEFINE_TYPE (GimpColorProfileStore, + gimp_color_profile_store, GTK_TYPE_LIST_STORE) + +#define parent_class gimp_color_profile_store_parent_class + + +static void +gimp_color_profile_store_class_init (GimpColorProfileStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = gimp_color_profile_store_constructed; + object_class->dispose = gimp_color_profile_store_dispose; + object_class->finalize = gimp_color_profile_store_finalize; + object_class->set_property = gimp_color_profile_store_set_property; + object_class->get_property = gimp_color_profile_store_get_property; + + /** + * GimpColorProfileStore:history: + * + * Filename of the color history used to populate the profile store. + * + * Since: 2.4 + */ + g_object_class_install_property (object_class, + PROP_HISTORY, + g_param_spec_string ("history", + "History", + "Filename of the color history used to populate the profile store", + NULL, + G_PARAM_CONSTRUCT_ONLY | + GIMP_PARAM_READWRITE)); +} + +static void +gimp_color_profile_store_init (GimpColorProfileStore *store) +{ + GType types[] = + { + G_TYPE_INT, /* GIMP_COLOR_PROFILE_STORE_ITEM_TYPE */ + G_TYPE_STRING, /* GIMP_COLOR_PROFILE_STORE_LABEL */ + G_TYPE_FILE, /* GIMP_COLOR_PROFILE_STORE_FILE */ + G_TYPE_INT /* GIMP_COLOR_PROFILE_STORE_INDEX */ + }; + + gtk_list_store_set_column_types (GTK_LIST_STORE (store), + G_N_ELEMENTS (types), types); +} + +static void +gimp_color_profile_store_constructed (GObject *object) +{ + GimpColorProfileStore *store = GIMP_COLOR_PROFILE_STORE (object); + GtkTreeIter iter; + + G_OBJECT_CLASS (parent_class)->constructed (object); + + gtk_list_store_append (GTK_LIST_STORE (store), &iter); + gtk_list_store_set (GTK_LIST_STORE (store), &iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, + GIMP_COLOR_PROFILE_STORE_ITEM_DIALOG, + GIMP_COLOR_PROFILE_STORE_LABEL, + _("Select color profile from disk..."), + -1); + + if (store->history) + { + gimp_color_profile_store_load (store, store->history, NULL); + } +} + +static void +gimp_color_profile_store_dispose (GObject *object) +{ + GimpColorProfileStore *store = GIMP_COLOR_PROFILE_STORE (object); + + if (store->history) + { + gimp_color_profile_store_save (store, store->history, NULL); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_color_profile_store_finalize (GObject *object) +{ + GimpColorProfileStore *store = GIMP_COLOR_PROFILE_STORE (object); + + g_clear_pointer (&store->history, g_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_color_profile_store_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpColorProfileStore *store = GIMP_COLOR_PROFILE_STORE (object); + + switch (property_id) + { + case PROP_HISTORY: + g_return_if_fail (store->history == NULL); + store->history = g_value_dup_string (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_color_profile_store_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpColorProfileStore *store = GIMP_COLOR_PROFILE_STORE (object); + + switch (property_id) + { + case PROP_HISTORY: + g_value_set_string (value, store->history); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +/** + * gimp_color_profile_store_new: + * @history: filename of the profilerc (or %NULL for no history) + * + * Creates a new #GimpColorProfileStore object and populates it with + * last used profiles read from the file @history. The updated history + * is written back to disk when the store is disposed. + * + * The filename passed as @history is typically created using the + * following code snippet: + * <informalexample><programlisting> + * gchar *history = gimp_personal_rc_file ("profilerc"); + * </programlisting></informalexample> + * + * Return value: a new #GimpColorProfileStore + * + * Since: 2.4 + **/ +GtkListStore * +gimp_color_profile_store_new (const gchar *history) +{ + return g_object_new (GIMP_TYPE_COLOR_PROFILE_STORE, + "history", history, + NULL); +} + +/** + * gimp_color_profile_store_add: + * @store: a #GimpColorProfileStore + * @filename: filename of the profile to add (or %NULL) + * @label: label to use for the profile + * (may only be %NULL if @filename is %NULL) + * + * Adds a color profile item to the #GimpColorProfileStore. Items + * added with this function will be kept at the top, separated from + * the history of last used color profiles. + * + * This function is often used to add a selectable item for the %NULL + * filename. If you pass %NULL for both @filename and @label, the + * @label will be set to the string "None" for you (and translated for + * the user). + * + * Deprecated: use gimp_color_profile_store_add_file() instead. + * + * Since: 2.4 + **/ +void +gimp_color_profile_store_add (GimpColorProfileStore *store, + const gchar *filename, + const gchar *label) +{ + GFile *file = NULL; + + g_return_if_fail (GIMP_IS_COLOR_PROFILE_STORE (store)); + g_return_if_fail (label != NULL || filename == NULL); + + if (filename) + file = g_file_new_for_path (filename); + + gimp_color_profile_store_add_file (store, file, label); + + g_object_unref (file); +} + +/** + * gimp_color_profile_store_add_file: + * @store: a #GimpColorProfileStore + * @file: file of the profile to add (or %NULL) + * @label: label to use for the profile + * (may only be %NULL if @filename is %NULL) + * + * Adds a color profile item to the #GimpColorProfileStore. Items + * added with this function will be kept at the top, separated from + * the history of last used color profiles. + * + * This function is often used to add a selectable item for the %NULL + * file. If you pass %NULL for both @file and @label, the @label will + * be set to the string "None" for you (and translated for the user). + * + * Since: 2.10 + **/ +void +gimp_color_profile_store_add_file (GimpColorProfileStore *store, + GFile *file, + const gchar *label) +{ + GtkTreeIter separator; + GtkTreeIter iter; + + g_return_if_fail (GIMP_IS_COLOR_PROFILE_STORE (store)); + g_return_if_fail (label != NULL || file == NULL); + g_return_if_fail (file == NULL || G_IS_FILE (file)); + + if (! file && ! label) + label = C_("profile", "None"); + + gimp_color_profile_store_get_separator (store, &separator, TRUE); + + gtk_list_store_insert_before (GTK_LIST_STORE (store), &iter, &separator); + gtk_list_store_set (GTK_LIST_STORE (store), &iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, + GIMP_COLOR_PROFILE_STORE_ITEM_FILE, + GIMP_COLOR_PROFILE_STORE_FILE, file, + GIMP_COLOR_PROFILE_STORE_LABEL, label, + GIMP_COLOR_PROFILE_STORE_INDEX, -1, + -1); +} + +/** + * _gimp_color_profile_store_history_add: + * @store: a #GimpColorProfileStore + * @file: file of the profile to add (or %NULL) + * @label: label to use for the profile (or %NULL) + * @iter: a #GtkTreeIter + * + * Return value: %TRUE if the iter is valid and pointing to the item + * + * Since: 2.4 + **/ +gboolean +_gimp_color_profile_store_history_add (GimpColorProfileStore *store, + GFile *file, + const gchar *label, + GtkTreeIter *iter) +{ + GtkTreeModel *model; + gboolean iter_valid; + gint max = -1; + + g_return_val_if_fail (GIMP_IS_COLOR_PROFILE_STORE (store), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + model = GTK_TREE_MODEL (store); + + for (iter_valid = gtk_tree_model_get_iter_first (model, iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, iter)) + { + gint type; + gint index; + GFile *this; + + gtk_tree_model_get (model, iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + GIMP_COLOR_PROFILE_STORE_INDEX, &index, + -1); + + if (type != GIMP_COLOR_PROFILE_STORE_ITEM_FILE) + continue; + + if (index > max) + max = index; + + /* check if we found a filename match */ + gtk_tree_model_get (model, iter, + GIMP_COLOR_PROFILE_STORE_FILE, &this, + -1); + + if ((this && file && g_file_equal (this, file)) || + (! this && ! file)) + { + /* update the label */ + if (label && *label) + gtk_list_store_set (GTK_LIST_STORE (store), iter, + GIMP_COLOR_PROFILE_STORE_LABEL, label, + -1); + + if (this) + g_object_unref (this); + + return TRUE; + } + + if (this) + g_object_unref (this); + } + + if (! file) + return FALSE; + + if (label && *label) + { + iter_valid = gimp_color_profile_store_history_insert (store, iter, + file, label, + ++max); + } + else + { + const gchar *utf8 = gimp_file_get_utf8_name (file); + gchar *basename = g_path_get_basename (utf8); + + iter_valid = gimp_color_profile_store_history_insert (store, iter, + file, basename, + ++max); + g_free (basename); + } + + return iter_valid; +} + +/** + * _gimp_color_profile_store_history_reorder + * @store: a #GimpColorProfileStore + * @iter: a #GtkTreeIter + * + * Moves the entry pointed to by @iter to the front of the MRU list. + * + * Since: 2.4 + **/ +void +_gimp_color_profile_store_history_reorder (GimpColorProfileStore *store, + GtkTreeIter *iter) +{ + GtkTreeModel *model; + gint index; + gboolean iter_valid; + + g_return_if_fail (GIMP_IS_COLOR_PROFILE_STORE (store)); + g_return_if_fail (iter != NULL); + + model = GTK_TREE_MODEL (store); + + gtk_tree_model_get (model, iter, + GIMP_COLOR_PROFILE_STORE_INDEX, &index, + -1); + + if (index == 0) + return; /* already at the top */ + + for (iter_valid = gtk_tree_model_get_iter_first (model, iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, iter)) + { + gint type; + gint this_index; + + gtk_tree_model_get (model, iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + GIMP_COLOR_PROFILE_STORE_INDEX, &this_index, + -1); + + if (type == GIMP_COLOR_PROFILE_STORE_ITEM_FILE && this_index > -1) + { + if (this_index < index) + { + this_index++; + } + else if (this_index == index) + { + this_index = 0; + } + + gtk_list_store_set (GTK_LIST_STORE (store), iter, + GIMP_COLOR_PROFILE_STORE_INDEX, this_index, + -1); + } + } +} + +static gboolean +gimp_color_profile_store_history_insert (GimpColorProfileStore *store, + GtkTreeIter *iter, + GFile *file, + const gchar *label, + gint index) +{ + GtkTreeModel *model = GTK_TREE_MODEL (store); + GtkTreeIter sibling; + gboolean iter_valid; + + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (index > -1, FALSE); + + gimp_color_profile_store_get_separator (store, iter, FALSE); + + for (iter_valid = gtk_tree_model_get_iter_first (model, &sibling); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, &sibling)) + { + gint type; + gint this_index; + + gtk_tree_model_get (model, &sibling, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + GIMP_COLOR_PROFILE_STORE_INDEX, &this_index, + -1); + + if (type == GIMP_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM) + { + gtk_list_store_insert_before (GTK_LIST_STORE (store), + iter, &sibling); + break; + } + + if (type == GIMP_COLOR_PROFILE_STORE_ITEM_FILE && this_index > -1) + { + gchar *this_label; + + gtk_tree_model_get (model, &sibling, + GIMP_COLOR_PROFILE_STORE_LABEL, &this_label, + -1); + + if (this_label && g_utf8_collate (label, this_label) < 0) + { + gtk_list_store_insert_before (GTK_LIST_STORE (store), + iter, &sibling); + g_free (this_label); + break; + } + + g_free (this_label); + } + } + + if (iter_valid) + gtk_list_store_set (GTK_LIST_STORE (store), iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, + GIMP_COLOR_PROFILE_STORE_ITEM_FILE, + GIMP_COLOR_PROFILE_STORE_FILE, file, + GIMP_COLOR_PROFILE_STORE_LABEL, label, + GIMP_COLOR_PROFILE_STORE_INDEX, index, + -1); + + return iter_valid; +} + +static void +gimp_color_profile_store_create_separator (GimpColorProfileStore *store, + GtkTreeIter *iter, + gboolean top) +{ + if (top) + { + gtk_list_store_prepend (GTK_LIST_STORE (store), iter); + } + else + { + GtkTreeModel *model = GTK_TREE_MODEL (store); + GtkTreeIter sibling; + gboolean iter_valid; + + for (iter_valid = gtk_tree_model_get_iter_first (model, &sibling); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, &sibling)) + { + gint type; + + gtk_tree_model_get (model, &sibling, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + -1); + + if (type == GIMP_COLOR_PROFILE_STORE_ITEM_DIALOG) + break; + } + + if (iter_valid) + gtk_list_store_insert_before (GTK_LIST_STORE (store), iter, &sibling); + } + + gtk_list_store_set (GTK_LIST_STORE (store), iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, + top ? + GIMP_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP : + GIMP_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM, + GIMP_COLOR_PROFILE_STORE_INDEX, -1, + -1); +} + +static void +gimp_color_profile_store_get_separator (GimpColorProfileStore *store, + GtkTreeIter *iter, + gboolean top) +{ + GtkTreeModel *model = GTK_TREE_MODEL (store); + gboolean iter_valid; + gint needle; + + needle = (top ? + GIMP_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP : + GIMP_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM); + + for (iter_valid = gtk_tree_model_get_iter_first (model, iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, iter)) + { + gint type; + + gtk_tree_model_get (model, iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + -1); + + if (type == needle) + return; + } + + gimp_color_profile_store_create_separator (store, iter, top); +} + +static GTokenType +gimp_color_profile_store_load_profile (GimpColorProfileStore *store, + GScanner *scanner, + gint index) +{ + GtkTreeIter iter; + gchar *label = NULL; + gchar *path = NULL; + + if (gimp_scanner_parse_string (scanner, &label) && + gimp_scanner_parse_string (scanner, &path)) + { + GFile *file = NULL; + + if (g_str_has_prefix (path, "file://")) + { + file = g_file_new_for_uri (path); + } + else + { + file = gimp_file_new_for_config_path (path, NULL); + } + + if (file) + { + if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_REGULAR) + { + gimp_color_profile_store_history_insert (store, &iter, + file, label, index); + } + + g_object_unref (file); + } + + g_free (label); + g_free (path); + + return G_TOKEN_RIGHT_PAREN; + } + + g_free (label); + g_free (path); + + return G_TOKEN_STRING; +} + +static gboolean +gimp_color_profile_store_load (GimpColorProfileStore *store, + const gchar *filename, + GError **error) +{ + GScanner *scanner; + GTokenType token; + gint i = 0; + + scanner = gimp_scanner_new_file (filename, error); + if (! scanner) + return FALSE; + + g_scanner_scope_add_symbol (scanner, 0, "color-profile", NULL); + + token = G_TOKEN_LEFT_PAREN; + + while (g_scanner_peek_next_token (scanner) == token) + { + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_SYMBOL; + break; + + case G_TOKEN_SYMBOL: + token = gimp_color_profile_store_load_profile (store, scanner, i++); + break; + + case G_TOKEN_RIGHT_PAREN: + token = G_TOKEN_LEFT_PAREN; + break; + + default: /* do nothing */ + break; + } + } + + if (token != G_TOKEN_LEFT_PAREN) + { + g_scanner_get_next_token (scanner); + g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, + _("fatal parse error"), TRUE); + } + + gimp_scanner_destroy (scanner); + + return TRUE; +} + +static gboolean +gimp_color_profile_store_save (GimpColorProfileStore *store, + const gchar *filename, + GError **error) +{ + GimpConfigWriter *writer; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *labels[HISTORY_SIZE] = { NULL, }; + GFile *files[HISTORY_SIZE] = { NULL, }; + gboolean iter_valid; + gint i; + + writer = gimp_config_writer_new_file (filename, + TRUE, + "GIMP color profile history", + error); + if (! writer) + return FALSE; + + model = GTK_TREE_MODEL (store); + + for (iter_valid = gtk_tree_model_get_iter_first (model, &iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, &iter)) + { + gint type; + gint index; + + gtk_tree_model_get (model, &iter, + GIMP_COLOR_PROFILE_STORE_ITEM_TYPE, &type, + GIMP_COLOR_PROFILE_STORE_INDEX, &index, + -1); + + if (type == GIMP_COLOR_PROFILE_STORE_ITEM_FILE && + index >= 0 && + index < HISTORY_SIZE) + { + if (labels[index] || files[index]) + g_warning ("%s: double index %d", G_STRFUNC, index); + + gtk_tree_model_get (model, &iter, + GIMP_COLOR_PROFILE_STORE_LABEL, + &labels[index], + GIMP_COLOR_PROFILE_STORE_FILE, + &files[index], + -1); + } + } + + + for (i = 0; i < HISTORY_SIZE; i++) + { + if (files[i] && labels[i]) + { + gchar *path = gimp_file_get_config_path (files[i], NULL); + + if (path) + { + gimp_config_writer_open (writer, "color-profile"); + gimp_config_writer_string (writer, labels[i]); + gimp_config_writer_string (writer, path); + gimp_config_writer_close (writer); + + g_free (path); + } + } + + if (files[i]) + g_object_unref (files[i]); + + g_free (labels[i]); + } + + return gimp_config_writer_finish (writer, + "end of color profile history", error); +} |