846 lines
26 KiB
C
846 lines
26 KiB
C
/* LIBPIKA - The PIKA Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* pikaprofilestore.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 <gegl.h>
|
|
|
|
#include "libpikabase/pikabase.h"
|
|
#include "libpikacolor/pikacolor.h"
|
|
#include "libpikaconfig/pikaconfig.h"
|
|
|
|
#include "pikawidgetstypes.h"
|
|
|
|
#include "pikacolorprofilestore.h"
|
|
#include "pikacolorprofilestore-private.h"
|
|
|
|
#include "libpika/libpika-intl.h"
|
|
|
|
|
|
/**
|
|
* SECTION: pikacolorprofilestore
|
|
* @title: PikaColorProfileStore
|
|
* @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
|
|
};
|
|
|
|
|
|
struct _PikaColorProfileStorePrivate
|
|
{
|
|
GFile *history;
|
|
};
|
|
|
|
#define GET_PRIVATE(obj) (((PikaColorProfileStore *) (obj))->priv)
|
|
|
|
|
|
static void pika_color_profile_store_constructed (GObject *object);
|
|
static void pika_color_profile_store_dispose (GObject *object);
|
|
static void pika_color_profile_store_finalize (GObject *object);
|
|
static void pika_color_profile_store_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void pika_color_profile_store_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static gboolean pika_color_profile_store_history_insert (PikaColorProfileStore *store,
|
|
GtkTreeIter *iter,
|
|
GFile *file,
|
|
const gchar *label,
|
|
gint index);
|
|
static void pika_color_profile_store_get_separator (PikaColorProfileStore *store,
|
|
GtkTreeIter *iter,
|
|
gboolean top);
|
|
static gboolean pika_color_profile_store_save (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
GError **error);
|
|
static gboolean pika_color_profile_store_load (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
GError **error);
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorProfileStore, pika_color_profile_store,
|
|
GTK_TYPE_LIST_STORE)
|
|
|
|
#define parent_class pika_color_profile_store_parent_class
|
|
|
|
|
|
static void
|
|
pika_color_profile_store_class_init (PikaColorProfileStoreClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->constructed = pika_color_profile_store_constructed;
|
|
object_class->dispose = pika_color_profile_store_dispose;
|
|
object_class->finalize = pika_color_profile_store_finalize;
|
|
object_class->set_property = pika_color_profile_store_set_property;
|
|
object_class->get_property = pika_color_profile_store_get_property;
|
|
|
|
/**
|
|
* PikaColorProfileStore:history:
|
|
*
|
|
* #GFile 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_object ("history",
|
|
"History",
|
|
"Filen of the color history used to populate the profile store",
|
|
G_TYPE_FILE,
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
PIKA_PARAM_READWRITE));
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_init (PikaColorProfileStore *store)
|
|
{
|
|
GType types[] =
|
|
{
|
|
G_TYPE_INT, /* PIKA_COLOR_PROFILE_STORE_ITEM_TYPE */
|
|
G_TYPE_STRING, /* PIKA_COLOR_PROFILE_STORE_LABEL */
|
|
G_TYPE_FILE, /* PIKA_COLOR_PROFILE_STORE_FILE */
|
|
G_TYPE_INT /* PIKA_COLOR_PROFILE_STORE_INDEX */
|
|
};
|
|
|
|
store->priv = pika_color_profile_store_get_instance_private (store);
|
|
|
|
gtk_list_store_set_column_types (GTK_LIST_STORE (store),
|
|
G_N_ELEMENTS (types), types);
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_constructed (GObject *object)
|
|
{
|
|
PikaColorProfileStore *store = PIKA_COLOR_PROFILE_STORE (object);
|
|
PikaColorProfileStorePrivate *private = GET_PRIVATE (store);
|
|
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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_DIALOG,
|
|
PIKA_COLOR_PROFILE_STORE_LABEL,
|
|
_("Select color profile from disk..."),
|
|
-1);
|
|
|
|
if (private->history)
|
|
pika_color_profile_store_load (store, private->history, NULL);
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_dispose (GObject *object)
|
|
{
|
|
PikaColorProfileStore *store = PIKA_COLOR_PROFILE_STORE (object);
|
|
PikaColorProfileStorePrivate *private = GET_PRIVATE (store);
|
|
|
|
if (private->history)
|
|
pika_color_profile_store_save (store, private->history, NULL);
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_finalize (GObject *object)
|
|
{
|
|
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
|
|
|
|
g_clear_object (&private->history);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_HISTORY:
|
|
g_return_if_fail (private->history == NULL);
|
|
private->history = g_value_dup_object (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_HISTORY:
|
|
g_value_set_object (value, private->history);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* pika_color_profile_store_new:
|
|
* @history: #GFile of the profilerc (or %NULL for no history)
|
|
*
|
|
* Creates a new #PikaColorProfileStore 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 #GFile passed as @history is typically created using the
|
|
* following code snippet:
|
|
* <informalexample><programlisting>
|
|
* gchar *history = pika_personal_rc_file ("profilerc");
|
|
* </programlisting></informalexample>
|
|
*
|
|
* Returns: a new #PikaColorProfileStore
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
GtkListStore *
|
|
pika_color_profile_store_new (GFile *history)
|
|
{
|
|
g_return_val_if_fail (history == NULL || G_IS_FILE (history), NULL);
|
|
|
|
return g_object_new (PIKA_TYPE_COLOR_PROFILE_STORE,
|
|
"history", history,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* pika_color_profile_store_add_file:
|
|
* @store: a #PikaColorProfileStore
|
|
* @file: #GFile of the profile to add (or %NULL)
|
|
* @label: label to use for the profile
|
|
* (may only be %NULL if @file is %NULL)
|
|
*
|
|
* Adds a color profile item to the #PikaColorProfileStore. 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
|
|
pika_color_profile_store_add_file (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
const gchar *label)
|
|
{
|
|
GtkTreeIter separator;
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (PIKA_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");
|
|
|
|
pika_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_FILE,
|
|
PIKA_COLOR_PROFILE_STORE_FILE, file,
|
|
PIKA_COLOR_PROFILE_STORE_LABEL, label,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, -1,
|
|
-1);
|
|
}
|
|
|
|
/**
|
|
* _pika_color_profile_store_history_add:
|
|
* @store: a #PikaColorProfileStore
|
|
* @file: file of the profile to add (or %NULL)
|
|
* @label: label to use for the profile (or %NULL)
|
|
* @iter: a #GtkTreeIter
|
|
*
|
|
* Returns: %TRUE if the iter is valid and pointing to the item
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
gboolean
|
|
_pika_color_profile_store_history_add (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
const gchar *label,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkTreeModel *model;
|
|
gboolean iter_valid;
|
|
gint max = -1;
|
|
|
|
g_return_val_if_fail (PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
|
|
-1);
|
|
|
|
if (type != PIKA_COLOR_PROFILE_STORE_ITEM_FILE)
|
|
continue;
|
|
|
|
if (index > max)
|
|
max = index;
|
|
|
|
/* check if we found a filename match */
|
|
gtk_tree_model_get (model, iter,
|
|
PIKA_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,
|
|
PIKA_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 = pika_color_profile_store_history_insert (store, iter,
|
|
file, label,
|
|
++max);
|
|
}
|
|
else
|
|
{
|
|
const gchar *utf8 = pika_file_get_utf8_name (file);
|
|
gchar *basename = g_path_get_basename (utf8);
|
|
|
|
iter_valid = pika_color_profile_store_history_insert (store, iter,
|
|
file, basename,
|
|
++max);
|
|
g_free (basename);
|
|
}
|
|
|
|
return iter_valid;
|
|
}
|
|
|
|
/**
|
|
* _pika_color_profile_store_history_find_profile:
|
|
* @store: a #PikaColorProfileStore
|
|
* @profile: a #PikaColorProfile to find (or %NULL)
|
|
* @iter: a #GtkTreeIter
|
|
*
|
|
* Returns: %TRUE if the iter is valid and pointing to the item
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
gboolean
|
|
_pika_color_profile_store_history_find_profile (PikaColorProfileStore *store,
|
|
PikaColorProfile *profile,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkTreeModel *model;
|
|
gboolean iter_valid;
|
|
gint max = -1;
|
|
|
|
g_return_val_if_fail (PIKA_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 *file;
|
|
PikaColorProfile *combo_profile = NULL;
|
|
|
|
gtk_tree_model_get (model, iter,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
|
|
-1);
|
|
|
|
if (type != PIKA_COLOR_PROFILE_STORE_ITEM_FILE)
|
|
continue;
|
|
|
|
if (index > max)
|
|
max = index;
|
|
|
|
/* check if we found a filename match */
|
|
gtk_tree_model_get (model, iter,
|
|
PIKA_COLOR_PROFILE_STORE_FILE, &file,
|
|
-1);
|
|
|
|
/* Convert file to PikaColorProfile */
|
|
if (file)
|
|
combo_profile = pika_color_profile_new_from_file (file, NULL);
|
|
|
|
if ((combo_profile && profile &&
|
|
pika_color_profile_is_equal (profile, combo_profile)) ||
|
|
(! file && ! profile))
|
|
{
|
|
if (file)
|
|
g_object_unref (file);
|
|
if (combo_profile)
|
|
g_object_unref (combo_profile);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (file)
|
|
g_object_unref (file);
|
|
if (combo_profile)
|
|
g_object_unref (combo_profile);
|
|
}
|
|
|
|
if (! profile)
|
|
return FALSE;
|
|
|
|
return iter_valid;
|
|
}
|
|
|
|
/**
|
|
* _pika_color_profile_store_history_reorder
|
|
* @store: a #PikaColorProfileStore
|
|
* @iter: a #GtkTreeIter
|
|
*
|
|
* Moves the entry pointed to by @iter to the front of the MRU list.
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
void
|
|
_pika_color_profile_store_history_reorder (PikaColorProfileStore *store,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkTreeModel *model;
|
|
gint index;
|
|
gboolean iter_valid;
|
|
|
|
g_return_if_fail (PIKA_IS_COLOR_PROFILE_STORE (store));
|
|
g_return_if_fail (iter != NULL);
|
|
|
|
model = GTK_TREE_MODEL (store);
|
|
|
|
gtk_tree_model_get (model, iter,
|
|
PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, &this_index,
|
|
-1);
|
|
|
|
if (type == PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, this_index,
|
|
-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
pika_color_profile_store_history_insert (PikaColorProfileStore *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);
|
|
|
|
pika_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, &this_index,
|
|
-1);
|
|
|
|
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM)
|
|
{
|
|
gtk_list_store_insert_before (GTK_LIST_STORE (store),
|
|
iter, &sibling);
|
|
break;
|
|
}
|
|
|
|
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_FILE && this_index > -1)
|
|
{
|
|
gchar *this_label;
|
|
|
|
gtk_tree_model_get (model, &sibling,
|
|
PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_FILE,
|
|
PIKA_COLOR_PROFILE_STORE_FILE, file,
|
|
PIKA_COLOR_PROFILE_STORE_LABEL, label,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, index,
|
|
-1);
|
|
|
|
return iter_valid;
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_create_separator (PikaColorProfileStore *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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
-1);
|
|
|
|
if (type == PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
|
|
top ?
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP :
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, -1,
|
|
-1);
|
|
}
|
|
|
|
static void
|
|
pika_color_profile_store_get_separator (PikaColorProfileStore *store,
|
|
GtkTreeIter *iter,
|
|
gboolean top)
|
|
{
|
|
GtkTreeModel *model = GTK_TREE_MODEL (store);
|
|
gboolean iter_valid;
|
|
gint needle;
|
|
|
|
needle = (top ?
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP :
|
|
PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
-1);
|
|
|
|
if (type == needle)
|
|
return;
|
|
}
|
|
|
|
pika_color_profile_store_create_separator (store, iter, top);
|
|
}
|
|
|
|
static GTokenType
|
|
pika_color_profile_store_load_profile (PikaColorProfileStore *store,
|
|
GScanner *scanner,
|
|
gint index)
|
|
{
|
|
GtkTreeIter iter;
|
|
gchar *label = NULL;
|
|
gchar *path = NULL;
|
|
|
|
if (pika_scanner_parse_string (scanner, &label) &&
|
|
pika_scanner_parse_string (scanner, &path))
|
|
{
|
|
GFile *file = NULL;
|
|
|
|
if (g_str_has_prefix (path, "file://"))
|
|
{
|
|
file = g_file_new_for_uri (path);
|
|
}
|
|
else
|
|
{
|
|
file = pika_file_new_for_config_path (path, NULL);
|
|
}
|
|
|
|
if (file)
|
|
{
|
|
if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_REGULAR)
|
|
{
|
|
pika_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
|
|
pika_color_profile_store_load (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
GError **error)
|
|
{
|
|
GScanner *scanner;
|
|
GTokenType token;
|
|
gint i = 0;
|
|
|
|
scanner = pika_scanner_new_file (file, 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 = pika_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);
|
|
}
|
|
|
|
pika_scanner_unref (scanner);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
pika_color_profile_store_save (PikaColorProfileStore *store,
|
|
GFile *file,
|
|
GError **error)
|
|
{
|
|
PikaConfigWriter *writer;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
gchar *labels[HISTORY_SIZE] = { NULL, };
|
|
GFile *files[HISTORY_SIZE] = { NULL, };
|
|
gboolean iter_valid;
|
|
gint i;
|
|
|
|
writer = pika_config_writer_new_from_file (file,
|
|
TRUE,
|
|
"PIKA 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,
|
|
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
|
|
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
|
|
-1);
|
|
|
|
if (type == PIKA_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,
|
|
PIKA_COLOR_PROFILE_STORE_LABEL,
|
|
&labels[index],
|
|
PIKA_COLOR_PROFILE_STORE_FILE,
|
|
&files[index],
|
|
-1);
|
|
}
|
|
}
|
|
|
|
|
|
for (i = 0; i < HISTORY_SIZE; i++)
|
|
{
|
|
if (files[i] && labels[i])
|
|
{
|
|
gchar *path = pika_file_get_config_path (files[i], NULL);
|
|
|
|
if (path)
|
|
{
|
|
pika_config_writer_open (writer, "color-profile");
|
|
pika_config_writer_string (writer, labels[i]);
|
|
pika_config_writer_string (writer, path);
|
|
pika_config_writer_close (writer);
|
|
|
|
g_free (path);
|
|
}
|
|
}
|
|
|
|
if (files[i])
|
|
g_object_unref (files[i]);
|
|
|
|
g_free (labels[i]);
|
|
}
|
|
|
|
return pika_config_writer_finish (writer,
|
|
"end of color profile history", error);
|
|
}
|