2005-03-05 07:01:48 +08:00
|
|
|
/* xmp-model.c - treeview model for XMP metadata
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005, Raphaël Quinet <raphael@gimp.org>
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This library is free software: you can redistribute it and/or
|
2005-03-05 07:01:48 +08:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
2009-01-18 06:28:01 +08:00
|
|
|
* version 3 of the License, or (at your option) any later version.
|
2005-03-05 07:01:48 +08:00
|
|
|
*
|
|
|
|
* 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
|
2009-01-18 06:28:01 +08:00
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
2005-03-05 07:01:48 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
2007-06-27 20:04:28 +08:00
|
|
|
|
2005-03-05 07:01:48 +08:00
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
2005-04-22 23:04:29 +08:00
|
|
|
#include "xmp-schemas.h"
|
2005-03-05 07:01:48 +08:00
|
|
|
#include "xmp-parse.h"
|
|
|
|
#include "xmp-model.h"
|
|
|
|
|
2009-07-28 14:16:37 +08:00
|
|
|
|
2009-08-15 17:44:32 +08:00
|
|
|
enum {
|
|
|
|
PROPERTY_CHANGED,
|
|
|
|
SCHEMA_CHANGED,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
xmp_model_iface_init (GtkTreeModelIface *iface)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (XMPModel, xmp_model,
|
|
|
|
GTK_TYPE_TREE_STORE,
|
|
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
|
|
|
|
xmp_model_iface_init));
|
|
|
|
|
|
|
|
static guint xmp_model_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
|
2009-07-28 14:16:37 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
xmp_model_init (XMPModel *xmp_model)
|
2005-03-05 07:01:48 +08:00
|
|
|
{
|
2009-08-15 17:44:32 +08:00
|
|
|
GType types[XMP_MODEL_NUM_COLUMNS];
|
|
|
|
|
|
|
|
types[COL_XMP_NAME] = G_TYPE_STRING;
|
|
|
|
types[COL_XMP_VALUE] = G_TYPE_STRING;
|
|
|
|
types[COL_XMP_VALUE_RAW] = G_TYPE_POINTER;
|
|
|
|
types[COL_XMP_TYPE_XREF] = G_TYPE_POINTER;
|
|
|
|
types[COL_XMP_WIDGET_XREF] = G_TYPE_POINTER;
|
|
|
|
types[COL_XMP_EDITABLE] = G_TYPE_INT;
|
|
|
|
types[COL_XMP_EDIT_ICON] = GDK_TYPE_PIXBUF;
|
|
|
|
types[COL_XMP_VISIBLE] = G_TYPE_BOOLEAN;
|
|
|
|
types[COL_XMP_WEIGHT] = G_TYPE_INT;
|
|
|
|
types[COL_XMP_WEIGHT_SET] = G_TYPE_BOOLEAN;
|
|
|
|
|
|
|
|
gtk_tree_store_set_column_types (GTK_TREE_STORE (xmp_model),
|
|
|
|
XMP_MODEL_NUM_COLUMNS, types);
|
|
|
|
|
2009-07-28 14:16:37 +08:00
|
|
|
xmp_model->custom_schemas = NULL;
|
|
|
|
xmp_model->custom_properties = NULL;
|
|
|
|
xmp_model->cached_schema = NULL;
|
|
|
|
}
|
2005-03-05 07:01:48 +08:00
|
|
|
|
2009-07-28 14:16:37 +08:00
|
|
|
static void
|
|
|
|
xmp_model_class_init (XMPModelClass *klass)
|
|
|
|
{
|
2009-08-15 17:44:32 +08:00
|
|
|
xmp_model_signals[PROPERTY_CHANGED] =
|
|
|
|
g_signal_new ("property-changed",
|
|
|
|
GIMP_TYPE_XMP_MODEL,
|
|
|
|
G_SIGNAL_DETAILED,
|
|
|
|
G_STRUCT_OFFSET (XMPModelClass, property_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
GTK_TYPE_TREE_ITER);
|
|
|
|
|
|
|
|
klass->property_changed = NULL;
|
2009-07-28 14:16:37 +08:00
|
|
|
}
|
2005-03-05 07:01:48 +08:00
|
|
|
|
2009-08-15 17:44:32 +08:00
|
|
|
|
2005-03-05 07:01:48 +08:00
|
|
|
/**
|
|
|
|
* xmp_model_new:
|
|
|
|
*
|
|
|
|
* Return value: a new #XMPModel.
|
|
|
|
**/
|
|
|
|
XMPModel *
|
|
|
|
xmp_model_new (void)
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
return g_object_new (GIMP_TYPE_XMP_MODEL, NULL);
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_free:
|
|
|
|
* @xmp_model: an #XMPModel
|
|
|
|
*
|
|
|
|
* Frees an #XMPModel.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
xmp_model_free (XMPModel *xmp_model)
|
|
|
|
{
|
|
|
|
GtkTreeModel *model;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeIter child;
|
|
|
|
gchar **value_array;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_if_fail (xmp_model != NULL);
|
|
|
|
/* we used XMP_FLAG_DEFER_VALUE_FREE for the parser, so now we must free
|
|
|
|
all value arrays */
|
|
|
|
model = xmp_model_get_tree_model (xmp_model);
|
|
|
|
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (gtk_tree_model_iter_children (model, &child, &iter))
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
gchar **last_value_array = NULL;
|
|
|
|
|
2005-03-05 07:01:48 +08:00
|
|
|
do
|
|
|
|
{
|
|
|
|
gtk_tree_model_get (model, &child,
|
|
|
|
COL_XMP_VALUE_RAW, &value_array,
|
|
|
|
-1);
|
2005-04-22 23:04:29 +08:00
|
|
|
if (value_array != last_value_array)
|
|
|
|
{
|
|
|
|
/* FIXME: this does not free everything */
|
|
|
|
for (i = 0; value_array[i] != NULL; i++)
|
|
|
|
g_free (value_array[i]);
|
|
|
|
g_free (value_array);
|
|
|
|
}
|
|
|
|
last_value_array = value_array;
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &child));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
}
|
2009-07-28 14:16:37 +08:00
|
|
|
g_object_unref (xmp_model);
|
2005-03-05 07:01:48 +08:00
|
|
|
/* FIXME: free custom schemas */
|
|
|
|
g_free (xmp_model);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_is_empty:
|
|
|
|
* @xmp_model: an #XMPModel
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if @xmp_model is empty (no shemas, no properties)
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
xmp_model_is_empty (XMPModel *xmp_model)
|
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
|
|
|
|
g_return_val_if_fail (xmp_model != NULL, TRUE);
|
|
|
|
if ((xmp_model->custom_schemas != NULL)
|
|
|
|
|| (xmp_model->custom_properties != NULL))
|
|
|
|
return FALSE;
|
2009-07-28 14:16:37 +08:00
|
|
|
return !gtk_tree_model_get_iter_first (GTK_TREE_MODEL (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the given schema_uri matches a known schema; else return NULL */
|
|
|
|
static XMPSchema *
|
|
|
|
find_xmp_schema (XMPModel *xmp_model,
|
|
|
|
const gchar *schema_uri)
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
int i;
|
|
|
|
GSList *list;
|
|
|
|
const gchar *c;
|
2005-03-05 07:01:48 +08:00
|
|
|
|
|
|
|
/* check if we know about this schema (exact match for URI) */
|
|
|
|
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
|
|
|
{
|
|
|
|
if (! strcmp (xmp_schemas[i].uri, schema_uri))
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
2005-03-05 07:01:48 +08:00
|
|
|
if (xmp_schemas[i].name != NULL)
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("%s \t[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
2005-03-05 07:01:48 +08:00
|
|
|
else
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("(no name) \t[%s]\n", xmp_schemas[i].uri);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
return &(xmp_schemas[i]);
|
|
|
|
}
|
|
|
|
}
|
2005-04-22 23:04:29 +08:00
|
|
|
/* this is not a standard shema; now check the custom schemas */
|
|
|
|
for (list = xmp_model->custom_schemas; list != NULL; list = list->next)
|
|
|
|
{
|
|
|
|
if (! strcmp (((XMPSchema *)(list->data))->uri, schema_uri))
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("CUSTOM %s \t[%s]\n",
|
|
|
|
((XMPSchema *)(list->data))->name,
|
|
|
|
((XMPSchema *)(list->data))->uri);
|
|
|
|
#endif
|
|
|
|
return (XMPSchema *)(list->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* now check for some common errors and results of bad encoding: */
|
|
|
|
/* - check for "http:" without "//", or missing "http://" */
|
2005-03-05 07:01:48 +08:00
|
|
|
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
|
|
|
{
|
|
|
|
if (g_str_has_prefix (xmp_schemas[i].uri, "http://")
|
|
|
|
&& ((! strcmp (xmp_schemas[i].uri + 7, schema_uri))
|
|
|
|
|| (g_str_has_prefix (schema_uri, "http:")
|
|
|
|
&& ! strcmp (xmp_schemas[i].uri + 7, schema_uri + 5))
|
|
|
|
))
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("%s \t~~~[%s]\n", xmp_schemas[i].name, xmp_schemas[i].uri);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
return &(xmp_schemas[i]);
|
|
|
|
}
|
|
|
|
}
|
2005-04-22 23:04:29 +08:00
|
|
|
/* - check for errors such as "name (uri)" or "name (prefix, uri)" */
|
|
|
|
for (c = schema_uri; *c; c++)
|
|
|
|
if ((*c == '(') || (*c == ' ') || (*c == ','))
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
c++;
|
|
|
|
while (*c == ' ')
|
|
|
|
c++;
|
|
|
|
if (! *c)
|
|
|
|
break;
|
|
|
|
for (len = 1; c[len]; len++)
|
|
|
|
if ((c[len] == ')') || (c[len] == ' '))
|
|
|
|
break;
|
|
|
|
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
|
|
|
{
|
|
|
|
if (! strncmp (xmp_schemas[i].uri, c, len))
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("%s \t~~~[%s]\n", xmp_schemas[i].name,
|
|
|
|
xmp_schemas[i].uri);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
2005-04-22 23:04:29 +08:00
|
|
|
return &(xmp_schemas[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("Unknown schema URI %s\n", schema_uri);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the given prefix matches a known schema; else return NULL */
|
|
|
|
static XMPSchema *
|
|
|
|
find_xmp_schema_prefix (XMPModel *xmp_model,
|
|
|
|
const gchar *prefix)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GSList *list;
|
|
|
|
|
|
|
|
for (i = 0; xmp_schemas[i].uri != NULL; ++i)
|
|
|
|
if (! strcmp (xmp_schemas[i].prefix, prefix))
|
|
|
|
return &(xmp_schemas[i]);
|
|
|
|
for (list = xmp_model->custom_schemas; list != NULL; list = list->next)
|
|
|
|
if (! strcmp (((XMPSchema *)(list->data))->prefix, prefix))
|
|
|
|
return (XMPSchema *)(list->data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make the next lookup a bit faster if the tree is not modified */
|
|
|
|
static void
|
2005-04-22 23:04:29 +08:00
|
|
|
cache_iter_for_schema (XMPModel *xmp_model,
|
2005-03-05 07:01:48 +08:00
|
|
|
XMPSchema *schema,
|
|
|
|
GtkTreeIter *iter)
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
xmp_model->cached_schema = schema;
|
2005-03-05 07:01:48 +08:00
|
|
|
if (iter != NULL)
|
2005-04-22 23:04:29 +08:00
|
|
|
memcpy (&(xmp_model->cached_schema_iter), iter, sizeof (GtkTreeIter));
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* find the GtkTreeIter for the given schema and return TRUE if the schema was
|
|
|
|
found in the tree; else return FALSE */
|
|
|
|
static gboolean
|
|
|
|
find_iter_for_schema (XMPModel *xmp_model,
|
|
|
|
XMPSchema *schema,
|
|
|
|
GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
XMPSchema *schema_xref;
|
|
|
|
|
2005-04-22 23:04:29 +08:00
|
|
|
/* common case: return the cached iter */
|
|
|
|
if (schema == xmp_model->cached_schema)
|
2005-03-05 07:01:48 +08:00
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
memcpy (iter, &(xmp_model->cached_schema_iter), sizeof (GtkTreeIter));
|
2005-03-05 07:01:48 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2005-04-22 23:04:29 +08:00
|
|
|
/* find where this schema has been stored in the tree */
|
2009-07-28 14:16:37 +08:00
|
|
|
if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
iter))
|
|
|
|
return FALSE;
|
|
|
|
do
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (xmp_model), iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_TYPE_XREF, &schema_xref,
|
|
|
|
-1);
|
|
|
|
if (schema_xref == schema)
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
cache_iter_for_schema (xmp_model, schema, iter);
|
2005-03-05 07:01:48 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2009-07-28 14:16:37 +08:00
|
|
|
while (gtk_tree_model_iter_next (GTK_TREE_MODEL (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
iter));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove a property from the list of children of schema_iter */
|
|
|
|
static void
|
|
|
|
find_and_remove_property (XMPModel *xmp_model,
|
|
|
|
XMPProperty *property,
|
|
|
|
GtkTreeIter *schema_iter)
|
|
|
|
{
|
|
|
|
GtkTreeIter child_iter;
|
|
|
|
XMPProperty *property_xref;
|
|
|
|
|
2009-07-28 14:16:37 +08:00
|
|
|
if (! gtk_tree_model_iter_children (GTK_TREE_MODEL (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&child_iter, schema_iter))
|
|
|
|
return;
|
|
|
|
for (;;)
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_TYPE_XREF, &property_xref,
|
|
|
|
-1);
|
|
|
|
if (property_xref == property)
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
if (! gtk_tree_store_remove (GTK_TREE_STORE (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&child_iter))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
if (! gtk_tree_model_iter_next (GTK_TREE_MODEL(xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&child_iter))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add a schema to the tree */
|
|
|
|
static void
|
|
|
|
add_known_schema (XMPModel *xmp_model,
|
|
|
|
XMPSchema *schema,
|
|
|
|
GtkTreeIter *iter)
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), iter, NULL);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, schema->name,
|
|
|
|
COL_XMP_VALUE, schema->uri,
|
|
|
|
COL_XMP_VALUE_RAW, NULL,
|
|
|
|
COL_XMP_TYPE_XREF, schema,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, FALSE,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, FALSE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
|
|
COL_XMP_WEIGHT_SET, TRUE,
|
|
|
|
-1);
|
2005-04-22 23:04:29 +08:00
|
|
|
cache_iter_for_schema (xmp_model, schema, iter);
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* called by the XMP parser - new schema */
|
|
|
|
static gpointer
|
|
|
|
parse_start_schema (XMPParseContext *context,
|
|
|
|
const gchar *ns_uri,
|
|
|
|
const gchar *ns_prefix,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
XMPModel *xmp_model = user_data;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
XMPSchema *schema;
|
|
|
|
|
|
|
|
g_return_val_if_fail (xmp_model != NULL, NULL);
|
|
|
|
schema = find_xmp_schema (xmp_model, ns_uri);
|
|
|
|
if (schema == NULL)
|
|
|
|
{
|
|
|
|
/* add schema to custom_schemas */
|
|
|
|
schema = g_new (XMPSchema, 1);
|
|
|
|
schema->uri = g_strdup (ns_uri);
|
|
|
|
schema->prefix = g_strdup (ns_prefix);
|
|
|
|
schema->name = schema->uri;
|
|
|
|
schema->properties = NULL;
|
|
|
|
xmp_model->custom_schemas = g_slist_prepend (xmp_model->custom_schemas,
|
|
|
|
schema);
|
|
|
|
}
|
|
|
|
else if (find_iter_for_schema (xmp_model, schema, &iter))
|
|
|
|
{
|
|
|
|
/* already in the tree, so no need to add it again */
|
|
|
|
return schema;
|
|
|
|
}
|
|
|
|
/* schemas with NULL names are special and should not go in the tree */
|
|
|
|
if (schema->name == NULL)
|
|
|
|
{
|
2005-04-22 23:04:29 +08:00
|
|
|
cache_iter_for_schema (xmp_model, NULL, NULL);
|
2005-03-05 07:01:48 +08:00
|
|
|
return schema;
|
|
|
|
}
|
|
|
|
/* if the schema is not in the tree yet, add it now */
|
|
|
|
add_known_schema (xmp_model, schema, &iter);
|
|
|
|
return schema;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* called by the XMP parser - end of schema */
|
|
|
|
static void
|
|
|
|
parse_end_schema (XMPParseContext *context,
|
|
|
|
gpointer ns_user_data,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
XMPModel *xmp_model = user_data;
|
|
|
|
XMPSchema *schema = ns_user_data;
|
|
|
|
|
|
|
|
g_return_if_fail (xmp_model != NULL);
|
|
|
|
g_return_if_fail (schema != NULL);
|
2005-04-22 23:04:29 +08:00
|
|
|
xmp_model->cached_schema = NULL;
|
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
if (schema->name)
|
|
|
|
g_print ("End of %s\n", schema->name);
|
|
|
|
#endif
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* called by the XMP parser - new property */
|
|
|
|
static void
|
|
|
|
parse_set_property (XMPParseContext *context,
|
|
|
|
const gchar *name,
|
|
|
|
XMPParseType type,
|
|
|
|
const gchar **value,
|
|
|
|
gpointer ns_user_data,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
XMPModel *xmp_model = user_data;
|
|
|
|
XMPSchema *schema = ns_user_data;
|
|
|
|
int i;
|
|
|
|
const gchar *ns_prefix;
|
|
|
|
XMPProperty *property;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeIter child_iter;
|
|
|
|
gchar *tmp_name;
|
|
|
|
gchar *tmp_value;
|
|
|
|
|
|
|
|
g_return_if_fail (xmp_model != NULL);
|
|
|
|
g_return_if_fail (schema != NULL);
|
|
|
|
if (! find_iter_for_schema (xmp_model, schema, &iter))
|
|
|
|
{
|
2007-10-02 17:15:34 +08:00
|
|
|
g_printerr ("Unable to set XMP property '%s' because its schema is bad",
|
|
|
|
name);
|
2005-03-05 07:01:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ns_prefix = schema->prefix;
|
|
|
|
property = NULL;
|
|
|
|
if (schema->properties != NULL)
|
|
|
|
for (i = 0; schema->properties[i].name != NULL; ++i)
|
|
|
|
if (! strcmp (schema->properties[i].name, name))
|
|
|
|
{
|
|
|
|
property = &(schema->properties[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* if the same property was already present, remove it (replace it) */
|
|
|
|
if (property != NULL)
|
|
|
|
find_and_remove_property (xmp_model, property, &iter);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case XMP_PTYPE_TEXT:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("\t%s:%s = \"%s\"\n", ns_prefix, name, value[0]);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
|
|
|
property->type = XMP_TYPE_TEXT;
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, name,
|
|
|
|
COL_XMP_VALUE, value[0],
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
2009-08-15 17:44:32 +08:00
|
|
|
xmp_model_property_changed (xmp_model, schema, &child_iter);
|
2005-03-05 07:01:48 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XMP_PTYPE_RESOURCE:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("\t%s:%s @ = \"%s\"\n", ns_prefix, name,
|
2005-03-05 07:01:48 +08:00
|
|
|
value[0]);
|
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
|
|
|
property->type = XMP_TYPE_URI;
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
tmp_name = g_strconcat (name, " @", NULL);
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, tmp_name,
|
|
|
|
COL_XMP_VALUE, value[0],
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
|
|
|
g_free (tmp_name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XMP_PTYPE_ORDERED_LIST:
|
|
|
|
case XMP_PTYPE_UNORDERED_LIST:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("\t%s:%s [] =", ns_prefix, name);
|
2005-03-05 07:01:48 +08:00
|
|
|
for (i = 0; value[i] != NULL; i++)
|
|
|
|
if (i == 0)
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print (" \"%s\"", value[i]);
|
2005-03-05 07:01:48 +08:00
|
|
|
else
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print (", \"%s\"", value[i]);
|
|
|
|
g_print ("\n");
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
|
|
|
property->type = ((type == XMP_PTYPE_ORDERED_LIST)
|
|
|
|
? XMP_TYPE_TEXT_BAG
|
|
|
|
: XMP_TYPE_TEXT_SEQ);
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_name = g_strconcat (name, " []", NULL);
|
|
|
|
tmp_value = g_strjoinv ("; ", (gchar **) value);
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, tmp_name,
|
|
|
|
COL_XMP_VALUE, tmp_value,
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
|
|
|
g_free (tmp_value);
|
|
|
|
g_free (tmp_name);
|
|
|
|
break;
|
|
|
|
|
2005-04-12 00:53:17 +08:00
|
|
|
case XMP_PTYPE_ALT_THUMBS:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
2005-04-12 00:53:17 +08:00
|
|
|
for (i = 0; value[i] != NULL; i += 2)
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("\t%s:%s [size:%d] = \"...\"\n", ns_prefix, name,
|
2005-04-12 00:53:17 +08:00
|
|
|
*(int *)(value[i]));
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("\n");
|
2005-04-12 00:53:17 +08:00
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
|
|
|
property->type = XMP_TYPE_THUMBNAIL_ALT;
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_name = g_strconcat (name, " []", NULL);
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-04-12 00:53:17 +08:00
|
|
|
COL_XMP_NAME, tmp_name,
|
|
|
|
COL_XMP_VALUE, "[FIXME: display thumbnails]",
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
|
|
|
g_free (tmp_name);
|
|
|
|
break;
|
|
|
|
|
2005-03-05 07:01:48 +08:00
|
|
|
case XMP_PTYPE_ALT_LANG:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
2005-03-05 07:01:48 +08:00
|
|
|
for (i = 0; value[i] != NULL; i += 2)
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("\t%s:%s [lang:%s] = \"%s\"\n", ns_prefix, name,
|
2005-03-05 07:01:48 +08:00
|
|
|
value[i], value[i + 1]);
|
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
|
|
|
property->type = XMP_TYPE_LANG_ALT;
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
for (i = 0; value[i] != NULL; i += 2)
|
|
|
|
{
|
|
|
|
tmp_name = g_strconcat (name, " [", value[i], "]", NULL);
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, tmp_name,
|
|
|
|
COL_XMP_VALUE, value[i + 1],
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
|
|
|
g_free (tmp_name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XMP_PTYPE_STRUCTURE:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
2005-03-05 07:01:48 +08:00
|
|
|
for (i = 2; value[i] != NULL; i += 2)
|
2005-04-22 23:04:29 +08:00
|
|
|
g_print ("\t%s:%s [%s] = \"%s\"\n", ns_prefix, name,
|
2005-03-05 07:01:48 +08:00
|
|
|
value[i], value[i + 1]);
|
|
|
|
#endif
|
|
|
|
if (property != NULL)
|
|
|
|
/* FIXME */;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (name);
|
2005-04-22 23:04:29 +08:00
|
|
|
property->type = XMP_TYPE_GENERIC_STRUCTURE;
|
2005-03-05 07:01:48 +08:00
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
for (i = 2; value[i] != NULL; i += 2)
|
|
|
|
{
|
|
|
|
tmp_name = g_strconcat (name, " [", value[i], "]", NULL);
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, tmp_name,
|
|
|
|
COL_XMP_VALUE, value[i + 1],
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
|
|
|
g_free (tmp_name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-04-22 23:04:29 +08:00
|
|
|
#ifdef DEBUG_XMP_MODEL
|
|
|
|
g_print ("\t%s:%s = ?\n", ns_prefix, name);
|
2005-03-05 07:01:48 +08:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* called by the XMP parser - parse error */
|
|
|
|
static void
|
|
|
|
parse_error (XMPParseContext *context,
|
|
|
|
GError *error,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2007-10-02 17:15:34 +08:00
|
|
|
g_printerr ("While parsing XMP metadata:\n%s\n", error->message);
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static XMPParser xmp_parser = {
|
|
|
|
parse_start_schema,
|
|
|
|
parse_end_schema,
|
|
|
|
parse_set_property,
|
|
|
|
parse_error
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_parse_buffer:
|
|
|
|
* @xmp_model: pointer to the #XMPModel in which the results will be stored
|
|
|
|
* @buffer: buffer to be parsed
|
|
|
|
* @buffer_length: length of the @buffer
|
|
|
|
* @skip_other_data: if %TRUE, allow arbitrary data before XMP packet marker
|
|
|
|
* @error: return location for a #GError
|
|
|
|
*
|
|
|
|
* Parse a buffer containing XMP metadata and merge the parsed contents into
|
|
|
|
* the supplied @xmp_model. If @skip_other_data is %TRUE, then the parser
|
|
|
|
* will try to find the <?xpacket...?> marker in the buffer, skipping any
|
|
|
|
* unknown data found before it.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE on success, %FALSE if an error was set
|
|
|
|
*
|
|
|
|
* (Note: this calls the functions from xmp_parse.c, which will call the
|
|
|
|
* functions in this file through the xmp_parser structure defined above.)
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
xmp_model_parse_buffer (XMPModel *xmp_model,
|
|
|
|
const gchar *buffer,
|
|
|
|
gssize buffer_length,
|
|
|
|
gboolean skip_other_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
XMPParseFlags flags;
|
|
|
|
XMPParseContext *context;
|
|
|
|
|
|
|
|
flags = XMP_FLAG_DEFER_VALUE_FREE; /* we will free the array ourselves */
|
|
|
|
if (skip_other_data)
|
|
|
|
flags |= XMP_FLAG_FIND_XPACKET;
|
|
|
|
|
|
|
|
context = xmp_parse_context_new (&xmp_parser, flags, xmp_model, NULL);
|
|
|
|
|
|
|
|
if (! xmp_parse_context_parse (context, buffer, buffer_length, error))
|
|
|
|
{
|
|
|
|
xmp_parse_context_free (context);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! xmp_parse_context_end_parse (context, error))
|
|
|
|
{
|
|
|
|
xmp_parse_context_free (context);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmp_parse_context_free (context);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_parse_file:
|
|
|
|
* @xmp_model: pointer to the #XMPModel in which the results will be stored
|
|
|
|
* @filename: name of the file containing XMP metadata to parse
|
|
|
|
* @error: return location for a #GError
|
|
|
|
*
|
|
|
|
* Try to find XMP metadata in a file and merge its contents into the supplied
|
|
|
|
* @xmp_model.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE on success, %FALSE if an error was set
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
xmp_model_parse_file (XMPModel *xmp_model,
|
|
|
|
const gchar *filename,
|
|
|
|
GError **error)
|
|
|
|
{
|
2005-08-03 09:15:36 +08:00
|
|
|
gchar *buffer;
|
|
|
|
gsize buffer_length;
|
2005-03-05 07:01:48 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
|
|
if (! g_file_get_contents (filename, &buffer, &buffer_length, error))
|
|
|
|
return FALSE;
|
2005-08-03 09:15:36 +08:00
|
|
|
if (! xmp_model_parse_buffer (xmp_model, buffer, buffer_length, TRUE, error))
|
2005-03-05 07:01:48 +08:00
|
|
|
return FALSE;
|
|
|
|
g_free (buffer);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_get_tree_model:
|
|
|
|
* @xmp_model: pointer to an #XMPModel
|
|
|
|
*
|
|
|
|
* Return a pointer to the #GtkTreeModel contained in the #XMPModel.
|
|
|
|
**/
|
|
|
|
GtkTreeModel *
|
|
|
|
xmp_model_get_tree_model (XMPModel *xmp_model)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (xmp_model != NULL, NULL);
|
2009-07-28 14:16:37 +08:00
|
|
|
return GTK_TREE_MODEL (xmp_model);
|
2005-03-05 07:01:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_get_scalar_property:
|
|
|
|
* @xmp_model: pointer to an #XMPModel
|
|
|
|
* @schema_name: full URI or usual prefix of the schema
|
|
|
|
* @property_name: name of the property to store
|
|
|
|
*
|
|
|
|
* Store a new value for the specified XMP property.
|
|
|
|
*
|
|
|
|
* Return value: string representation of the value of that property, or %NULL if the property does not exist
|
|
|
|
**/
|
|
|
|
const gchar *
|
|
|
|
xmp_model_get_scalar_property (XMPModel *xmp_model,
|
|
|
|
const gchar *schema_name,
|
|
|
|
const gchar *property_name)
|
|
|
|
{
|
|
|
|
XMPSchema *schema;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
XMPProperty *property = NULL;
|
|
|
|
GtkTreeIter child_iter;
|
|
|
|
int i;
|
|
|
|
XMPProperty *property_xref;
|
|
|
|
const gchar *value;
|
|
|
|
|
|
|
|
g_return_val_if_fail (xmp_model != NULL, NULL);
|
|
|
|
g_return_val_if_fail (schema_name != NULL, NULL);
|
|
|
|
g_return_val_if_fail (property_name != NULL, NULL);
|
|
|
|
schema = find_xmp_schema (xmp_model, schema_name);
|
|
|
|
if (! schema)
|
|
|
|
schema = find_xmp_schema_prefix (xmp_model, schema_name);
|
|
|
|
if (! schema)
|
|
|
|
return NULL;
|
|
|
|
if (! find_iter_for_schema (xmp_model, schema, &iter))
|
|
|
|
return NULL;
|
|
|
|
if (schema->properties != NULL)
|
|
|
|
for (i = 0; schema->properties[i].name != NULL; ++i)
|
|
|
|
if (! strcmp (schema->properties[i].name, property_name))
|
|
|
|
{
|
|
|
|
property = &(schema->properties[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (property == NULL)
|
|
|
|
return NULL;
|
2009-07-28 14:16:37 +08:00
|
|
|
if (! gtk_tree_model_iter_children (GTK_TREE_MODEL (xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&child_iter, &iter))
|
|
|
|
return NULL;
|
|
|
|
do
|
|
|
|
{
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_TYPE_XREF, &property_xref,
|
|
|
|
COL_XMP_VALUE, &value,
|
|
|
|
-1);
|
|
|
|
if (property_xref == property)
|
|
|
|
return value;
|
|
|
|
}
|
2009-07-28 14:16:37 +08:00
|
|
|
while (gtk_tree_model_iter_next (GTK_TREE_MODEL(xmp_model),
|
2005-03-05 07:01:48 +08:00
|
|
|
&child_iter));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_set_scalar_property:
|
|
|
|
* @xmp_model: pointer to an #XMPModel
|
|
|
|
* @schema_name: full URI or usual prefix of the schema
|
|
|
|
* @property_name: name of the property to store
|
|
|
|
* @property_value: value to store
|
|
|
|
*
|
|
|
|
* Store a new value for the specified XMP property.
|
|
|
|
*
|
2005-08-22 04:28:05 +08:00
|
|
|
* Return value: %TRUE if the property was set, %FALSE if an error occurred (for example, the @schema_name is invalid)
|
2005-03-05 07:01:48 +08:00
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
xmp_model_set_scalar_property (XMPModel *xmp_model,
|
|
|
|
const gchar *schema_name,
|
|
|
|
const gchar *property_name,
|
|
|
|
const gchar *property_value)
|
|
|
|
{
|
|
|
|
XMPSchema *schema;
|
|
|
|
XMPProperty *property = NULL;
|
2009-07-28 14:16:37 +08:00
|
|
|
GtkTreeIter iter;
|
2005-03-05 07:01:48 +08:00
|
|
|
GtkTreeIter child_iter;
|
|
|
|
int i;
|
|
|
|
gchar **value;
|
|
|
|
|
|
|
|
g_return_val_if_fail (xmp_model != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (schema_name != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (property_name != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (property_value != NULL, FALSE);
|
|
|
|
schema = find_xmp_schema (xmp_model, schema_name);
|
|
|
|
if (! schema)
|
|
|
|
schema = find_xmp_schema_prefix (xmp_model, schema_name);
|
|
|
|
if (! schema)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (! find_iter_for_schema (xmp_model, schema, &iter))
|
|
|
|
add_known_schema (xmp_model, schema, &iter);
|
|
|
|
|
|
|
|
if (schema->properties != NULL)
|
|
|
|
for (i = 0; schema->properties[i].name != NULL; ++i)
|
|
|
|
if (! strcmp (schema->properties[i].name, property_name))
|
|
|
|
{
|
|
|
|
property = &(schema->properties[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (property != NULL)
|
|
|
|
find_and_remove_property (xmp_model, property, &iter);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
property = g_new (XMPProperty, 1);
|
|
|
|
property->name = g_strdup (property_name);
|
|
|
|
property->type = XMP_TYPE_TEXT;
|
|
|
|
property->editable = TRUE;
|
|
|
|
xmp_model->custom_properties =
|
|
|
|
g_slist_prepend (xmp_model->custom_properties, property);
|
|
|
|
}
|
|
|
|
|
|
|
|
value = g_new (gchar *, 2);
|
|
|
|
value[0] = g_strdup (property_value);
|
|
|
|
value[1] = NULL;
|
2009-07-28 14:16:37 +08:00
|
|
|
gtk_tree_store_append (GTK_TREE_STORE (xmp_model), &child_iter, &iter);
|
|
|
|
gtk_tree_store_set (GTK_TREE_STORE (xmp_model), &child_iter,
|
2005-03-05 07:01:48 +08:00
|
|
|
COL_XMP_NAME, g_strdup (property_name),
|
|
|
|
COL_XMP_VALUE, value[0],
|
|
|
|
COL_XMP_VALUE_RAW, value,
|
|
|
|
COL_XMP_TYPE_XREF, property,
|
|
|
|
COL_XMP_WIDGET_XREF, NULL,
|
|
|
|
COL_XMP_EDITABLE, property->editable,
|
|
|
|
COL_XMP_EDIT_ICON, NULL,
|
|
|
|
COL_XMP_VISIBLE, TRUE,
|
|
|
|
COL_XMP_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
|
|
COL_XMP_WEIGHT_SET, FALSE,
|
|
|
|
-1);
|
2009-08-15 17:44:32 +08:00
|
|
|
xmp_model_property_changed (xmp_model, schema, &child_iter);
|
2005-03-05 07:01:48 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2009-08-15 17:44:32 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* xmp_model_property_changed:
|
|
|
|
* @xmp_model: An #XMPModel
|
|
|
|
* @schema: An #XMPSchema the property belongs to
|
|
|
|
* @iter: A valid #GtkTreeIter pointing to the changed row
|
|
|
|
*
|
|
|
|
* Emits the "property-changed" event based on the @tree_model with
|
|
|
|
* detail. The detail is a joined string of xmp-schema-prefix and
|
|
|
|
* xmp-property-name (e.g. property-changed::dc:DocumentID).
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
xmp_model_property_changed (XMPModel *xmp_model,
|
|
|
|
XMPSchema *schema,
|
|
|
|
GtkTreeIter *iter)
|
|
|
|
{
|
|
|
|
GQuark detail;
|
|
|
|
gchar *joined;
|
|
|
|
const gchar *property_name;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_XMP_MODEL (xmp_model));
|
|
|
|
g_return_if_fail (iter != NULL);
|
|
|
|
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (xmp_model), iter,
|
|
|
|
COL_XMP_NAME, &property_name,
|
|
|
|
-1);
|
|
|
|
joined = g_strjoin (":", schema->prefix, property_name, NULL);
|
|
|
|
detail = g_quark_from_string (joined);
|
|
|
|
|
|
|
|
g_signal_emit (xmp_model, xmp_model_signals[PROPERTY_CHANGED], detail, iter);
|
|
|
|
}
|