From 7c0ba83b260ac53c1eddcc8dfb283c4b9d9c939e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Jan 2012 14:59:21 -0300 Subject: [PATCH] ges: Add an API to Formatter to be able to handle moved sources API: GESFormatter::source-moved signal API: GESFormatter::update_source_uri virtual method Conflicts: ges/ges-formatter.h --- docs/libs/ges-sections.txt | 1 + ges/ges-formatter.c | 90 ++++++++++++++++++++++++++++++++++++-- ges/ges-formatter.h | 24 ++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/docs/libs/ges-sections.txt b/docs/libs/ges-sections.txt index cab3976131..6a0f8cae8b 100644 --- a/docs/libs/ges-sections.txt +++ b/docs/libs/ges-sections.txt @@ -752,6 +752,7 @@ GESFormatter GESFormatterClass GESFormatterLoadFromURIMethod GESFormatterSaveToURIMethod +GESFormatterSourceMovedMethod ges_default_formatter_new ges_formatter_load_from_uri ges_formatter_save_to_uri diff --git a/ges/ges-formatter.c b/ges/ges-formatter.c index 530733b2fb..a43ea7ca9f 100644 --- a/ges/ges-formatter.c +++ b/ges/ges-formatter.c @@ -42,9 +42,12 @@ #include #include + +#include "gesmarshal.h" #include "ges-formatter.h" #include "ges-keyfile-formatter.h" #include "ges-internal.h" +#include "ges.h" G_DEFINE_ABSTRACT_TYPE (GESFormatter, ges_formatter, G_TYPE_OBJECT); @@ -52,6 +55,10 @@ struct _GESFormatterPrivate { gchar *data; gsize length; + + /* Make sure not to emit several times "moved-source" when the user already + * provided the new source URI. */ + GHashTable *uri_newuri_table; }; static void ges_formatter_dispose (GObject * object); @@ -61,6 +68,16 @@ static gboolean save_to_uri (GESFormatter * formatter, GESTimeline * timeline, const gchar * uri); static gboolean default_can_load_uri (const gchar * uri); static gboolean default_can_save_uri (const gchar * uri); +static void discovery_error_cb (GESTimeline * timeline, + GESTimelineFileSource * tfs, GError * error, GESFormatter * formatter); + +enum +{ + SOURCE_MOVED_SIGNAL, + LAST_SIGNAL +}; + +static guint ges_formatter_signals[LAST_SIGNAL] = { 0 }; static void ges_formatter_class_init (GESFormatterClass * klass) @@ -69,12 +86,25 @@ ges_formatter_class_init (GESFormatterClass * klass) g_type_class_add_private (klass, sizeof (GESFormatterPrivate)); + /** + * GESFormatter::source-moved: + * @formatter: the #GESFormatter + * @source: The #GESTimelineFileSource that has an invalid URI. When this happens, + * you can call #ges_formatter_update_source_uri with the new URI of the source so + * the project can be loaded properly. + */ + ges_formatter_signals[SOURCE_MOVED_SIGNAL] = + g_signal_new ("source-moved", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, ges_marshal_VOID__OBJECT, G_TYPE_NONE, + 1, GES_TYPE_TIMELINE_FILE_SOURCE); + object_class->dispose = ges_formatter_dispose; klass->can_load_uri = default_can_load_uri; klass->can_save_uri = default_can_save_uri; klass->load_from_uri = load_from_uri; klass->save_to_uri = save_to_uri; + klass->update_source_uri = NULL; } static void @@ -82,6 +112,9 @@ ges_formatter_init (GESFormatter * object) { object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, GES_TYPE_FORMATTER, GESFormatterPrivate); + + object->priv->uri_newuri_table = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, g_free); } static void @@ -92,6 +125,7 @@ ges_formatter_dispose (GObject * object) if (priv->data) { g_free (priv->data); } + g_hash_table_destroy (priv->uri_newuri_table); } /** @@ -144,7 +178,7 @@ default_can_save_uri (const gchar * uri) /** * ges_formatter_can_load_uri: * @uri: a #gchar * pointing to the URI - * + * * Checks if there is a #GESFormatter available which can load a #GESTimeline * from the given URI. * @@ -177,7 +211,7 @@ ges_formatter_can_load_uri (const gchar * uri) /** * ges_formatter_can_save_uri: * @uri: a #gchar * pointing to a URI - * + * * Returns TRUE if there is a #GESFormatter available which can save a * #GESTimeline to the given URI. * @@ -334,7 +368,7 @@ ges_formatter_save (GESFormatter * formatter, GESTimeline * timeline) * @formatter: a #GESFormatter * @timeline: a #GESTimeline * @uri: a #gchar * pointing to a URI - * + * * Load data from the given URI into timeline. * * Returns: TRUE if the timeline data was successfully loaded from the URI, @@ -347,6 +381,11 @@ ges_formatter_load_from_uri (GESFormatter * formatter, GESTimeline * timeline, { GESFormatterClass *klass = GES_FORMATTER_GET_CLASS (formatter); + g_return_val_if_fail (GES_IS_FORMATTER (formatter), FALSE); + g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE); + + g_signal_connect (timeline, "discovery-error", + G_CALLBACK (discovery_error_cb), formatter); if (klass->load_from_uri) return klass->load_from_uri (formatter, timeline, uri); @@ -451,3 +490,48 @@ save_to_uri (GESFormatter * formatter, GESTimeline * timeline, return ret; } + +gboolean +ges_formatter_update_source_uri (GESFormatter * formatter, + GESTimelineFileSource * source, gchar * new_uri) +{ + GESFormatterClass *klass = GES_FORMATTER_GET_CLASS (formatter); + + if (klass->update_source_uri) { + const gchar *uri = ges_timeline_filesource_get_uri (source); + gchar *cached_uri = + g_hash_table_lookup (formatter->priv->uri_newuri_table, uri); + + if (!cached_uri) { + g_hash_table_insert (formatter->priv->uri_newuri_table, g_strdup (uri), + g_strdup (new_uri)); + + GST_DEBUG ("Adding %s to the new uri cache", new_uri); + } + + return klass->update_source_uri (formatter, source, new_uri); + } + + GST_ERROR ("not implemented!"); + + return FALSE; +} + +static void +discovery_error_cb (GESTimeline * timeline, + GESTimelineFileSource * tfs, GError * error, GESFormatter * formatter) +{ + if (error->domain == GST_RESOURCE_ERROR && + error->code == GST_RESOURCE_ERROR_NOT_FOUND) { + const gchar *uri = ges_timeline_filesource_get_uri (tfs); + gchar *new_uri = + g_hash_table_lookup (formatter->priv->uri_newuri_table, uri); + + if (new_uri) { + ges_formatter_update_source_uri (formatter, tfs, new_uri); + GST_DEBUG ("%s found in the cache, new uri: %s", uri, new_uri); + } else + g_signal_emit (formatter, ges_formatter_signals[SOURCE_MOVED_SIGNAL], 0, + tfs); + } +} diff --git a/ges/ges-formatter.h b/ges/ges-formatter.h index 22dc841dd8..0d003587a1 100644 --- a/ges/ges-formatter.h +++ b/ges/ges-formatter.h @@ -100,6 +100,23 @@ typedef gboolean (*GESFormatterSaveMethod) (GESFormatter * formatter, typedef gboolean (*GESFormatterLoadMethod) (GESFormatter * formatter, GESTimeline * timeline); +/** + * GESFormatterSourceMovedMethod: + * @formatter: a #GESFormatter + * @tfs: a #GESTimelineFileSource + * @new_uri: the new URI of @tfs + * + * Virtual method for changing the URI of a #GESTimelineFileSource that has been + * moved between the saving and the loading of the timeline. + * + * This virtual method is not 100% necessary to be implemented as it is an + * extra feature. + * + * Returns: %TRUE if the source URI could be modified properly, %FALSE otherwize. + */ +typedef gboolean (*GESFormatterSourceMovedMethod) (GESFormatter *formatter, + GESTimelineFileSource *tfs, gchar *new_uri); + /** * GESFormatterClass: * @parent_class: the parent class structure @@ -107,6 +124,8 @@ typedef gboolean (*GESFormatterLoadMethod) (GESFormatter * formatter, * @can_save_uri: Whether the URI can be saved * @load_from_uri: class method to deserialize data from a URI * @save_to_uri: class method to serialize data to a URI + * @update_source_uri: virtual method to specify that a source has moved, and thus its URI + * must be set to its new location (specified by the user) * * GES Formatter class. Override the vmethods to implement the formatter functionnality. */ @@ -118,6 +137,7 @@ struct _GESFormatterClass { GESFormatterCanSaveURIMethod can_save_uri; GESFormatterLoadFromURIMethod load_from_uri; GESFormatterSaveToURIMethod save_to_uri; + GESFormatterSourceMovedMethod update_source_uri; /*< private >*/ /* FIXME : formatter name */ @@ -148,6 +168,10 @@ gboolean ges_formatter_save_to_uri (GESFormatter * formatter, GESTimeline *timeline, const gchar *uri); +gboolean +ges_formatter_update_source_uri (GESFormatter * formatter, + GESTimelineFileSource * source, gchar * new_uri); + /* Non-standard methods. WILL BE DEPRECATED */ gboolean ges_formatter_load (GESFormatter * formatter, GESTimeline * timeline);