diff options
author | Bastien Nocera <hadess@hadess.net> | 2014-02-21 16:22:22 +0100 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2020-08-26 12:36:14 +0200 |
commit | 95dd1c21806c732bb61ad9a79645c51698cdddd4 (patch) | |
tree | 7284a453d1dfb40640cd792dc8d94db784cacefd | |
parent | dc6be701e124ed78b14347bb0c131715d3f011c8 (diff) | |
download | grilo-wip/hadess/remove-op-flags.tar.gz |
core: Add remove operation flagswip/hadess/remove-op-flags
Allow passing remove flags to backends to implement various
kinds of removals (deletion, moving to trash, marking as
read/watched, etc.)
https://bugzilla.gnome.org/show_bug.cgi?id=724308
-rw-r--r-- | src/grl-caps.c | 35 | ||||
-rw-r--r-- | src/grl-caps.h | 26 | ||||
-rw-r--r-- | src/grl-operation-options-priv.h | 1 | ||||
-rw-r--r-- | src/grl-operation-options.c | 57 | ||||
-rw-r--r-- | src/grl-operation-options.h | 5 | ||||
-rw-r--r-- | src/grl-source.c | 122 | ||||
-rw-r--r-- | src/grl-source.h | 14 | ||||
-rw-r--r-- | tools/grilo-test-ui/main.c | 35 |
8 files changed, 282 insertions, 13 deletions
diff --git a/src/grl-caps.c b/src/grl-caps.c index 4e9368f..00c185e 100644 --- a/src/grl-caps.c +++ b/src/grl-caps.c @@ -56,6 +56,7 @@ struct _GrlCapsPrivate { GHashTable *data; GrlTypeFilter type_filter; + GrlRemoveFlags remove_flags; GList *key_filter; GList *key_range_filter; }; @@ -90,6 +91,7 @@ grl_caps_init (GrlCaps *self) self->priv->type_filter = GRL_TYPE_FILTER_NONE; self->priv->key_filter = NULL; self->priv->key_range_filter = NULL; + self->priv->remove_flags = GRL_REMOVE_FLAG_UNKNOWN; } static void @@ -195,6 +197,39 @@ grl_caps_set_type_filter (GrlCaps *caps, GrlTypeFilter filter) } /** + * grl_caps_get_remove_flags: + * @caps: a #GrlCaps instance + * + * Returns: the supported #GrlRemoveFlags + * + * Since: 0.2.0 + **/ +GrlRemoveFlags +grl_caps_get_remove_flags (GrlCaps *caps) +{ + g_return_val_if_fail (caps != NULL, GRL_REMOVE_FLAG_UNKNOWN); + + return caps->priv->remove_flags; +} + +/** + * grl_caps_set_remove_flags: + * @caps: a #GrlCaps instance + * @remove_flags: a #GrlRemoveFlags + * + * Sets the supported remove capability. + * + * Since: 0.2.0 + **/ +void +grl_caps_set_remove_flags (GrlCaps *caps, GrlRemoveFlags remove_flags) +{ + g_return_if_fail (caps != NULL); + + caps->priv->remove_flags = remove_flags; +} + +/** * grl_caps_get_key_filter: * @caps: a #GrlCaps instance * diff --git a/src/grl-caps.h b/src/grl-caps.h index df2e939..5825a0b 100644 --- a/src/grl-caps.h +++ b/src/grl-caps.h @@ -84,6 +84,28 @@ typedef enum { GRL_TYPE_FILTER_ALL = (GRL_TYPE_FILTER_AUDIO | GRL_TYPE_FILTER_VIDEO | GRL_TYPE_FILTER_IMAGE) } GrlTypeFilter; +/** + * GrlRemoveFlags: + * @GRL_REMOVE_FLAG_UNKNOWN: the #GrlSource did not set any GrlRemoveFlags + * @GRL_REMOVE_FLAG_NONE: does not support removals + * @GRL_REMOVE_FLAG_DELETE: will unrecoverably delete media + * @GRL_REMOVE_FLAG_TRASH: will move media to the trash + * @GRL_REMOVE_FLAG_ARCHIVE: will move the media to an archive (which might + * or might not be available through grilo) + * @GRL_REMOVE_FLAG_REFERENCE: will remove the reference to the media, not the media. + * + * Bitwise flags which reflect the kind of removal that a + * #GrlSource supports. + */ +typedef enum{ + GRL_REMOVE_FLAG_UNKNOWN = -1, + GRL_REMOVE_FLAG_NONE = 0, + GRL_REMOVE_FLAG_DELETE = 1, + GRL_REMOVE_FLAG_TRASH = 1 << 1, + GRL_REMOVE_FLAG_ARCHIVE = 1 << 2, + GRL_REMOVE_FLAG_REFERENCE = 1 << 3 +} GrlRemoveFlags; + GType grl_caps_get_type (void); @@ -109,6 +131,10 @@ void grl_caps_set_key_range_filter (GrlCaps *caps, GList *keys); gboolean grl_caps_is_key_range_filter (GrlCaps *caps, GrlKeyID key); +GrlRemoveFlags grl_caps_get_remove_flags (GrlCaps *caps); + +void grl_caps_set_remove_flags (GrlCaps *caps, GrlRemoveFlags remove_flags); + G_END_DECLS #endif /* _GRL_CAPS_H_ */ diff --git a/src/grl-operation-options-priv.h b/src/grl-operation-options-priv.h index 49de323..6cd8d3b 100644 --- a/src/grl-operation-options-priv.h +++ b/src/grl-operation-options-priv.h @@ -34,6 +34,7 @@ #define GRL_OPERATION_OPTION_SKIP "skip" #define GRL_OPERATION_OPTION_COUNT "count" #define GRL_OPERATION_OPTION_RESOLUTION_FLAGS "resolution-flags" +#define GRL_OPERATION_OPTION_REMOVE_FLAGS "remove-flags" #define GRL_OPERATION_OPTION_TYPE_FILTER "type-filter" #define GRL_OPERATION_OPTION_KEY_EQUAL_FILTER "key-equal-filter" #define GRL_OPERATION_OPTION_KEY_RANGE_FILTER "key-range-filter" diff --git a/src/grl-operation-options.c b/src/grl-operation-options.c index ec50d65..c1c9791 100644 --- a/src/grl-operation-options.c +++ b/src/grl-operation-options.c @@ -49,6 +49,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (GrlOperationOptions, grl_operation_options, G_TYPE_O #define SKIP_DEFAULT 0; #define COUNT_DEFAULT GRL_COUNT_INFINITY; #define RESOLUTION_FLAGS_DEFAULT GRL_RESOLVE_NORMAL; +#define REMOVE_FLAGS_DEFAULT GRL_REMOVE_FLAG_UNKNOWN #define TYPE_FILTER_DEFAULT GRL_TYPE_FILTER_ALL; static void @@ -208,6 +209,7 @@ grl_operation_options_obey_caps (GrlOperationOptions *options, copy_option (options, *supported_options, GRL_OPERATION_OPTION_SKIP); copy_option (options, *supported_options, GRL_OPERATION_OPTION_COUNT); copy_option (options, *supported_options, GRL_OPERATION_OPTION_RESOLUTION_FLAGS); + copy_option (options, *supported_options, GRL_OPERATION_OPTION_REMOVE_FLAGS); } if (unsupported_options) @@ -279,6 +281,7 @@ grl_operation_options_copy (GrlOperationOptions *options) copy_option (options, copy, GRL_OPERATION_OPTION_SKIP); copy_option (options, copy, GRL_OPERATION_OPTION_COUNT); copy_option (options, copy, GRL_OPERATION_OPTION_RESOLUTION_FLAGS); + copy_option (options, copy, GRL_OPERATION_OPTION_REMOVE_FLAGS); copy_option (options, copy, GRL_OPERATION_OPTION_TYPE_FILTER); g_hash_table_foreach (options->priv->key_filter, @@ -466,6 +469,60 @@ grl_operation_options_get_resolution_flags (GrlOperationOptions *options) } /** + * grl_operation_options_set_remove_flags: + * @options: a #GrlOperationOptions instance + * @flags: the remove flags to be set for an operation. See + * #GrlRemoveFlags for possible values. + * + * Set the remove flags for a remove operation. Will only succeed if @flags obey + * to the inherent capabilities of @options. + * + * Returns: %TRUE if @flags could be set, %FALSE otherwise. + * + * Since: 0.2.0 + */ +gboolean +grl_operation_options_set_remove_flags (GrlOperationOptions *options, + GrlRemoveFlags flags) +{ + GValue value = { 0, }; + + /* FIXME: I think we should use mk_enum to have a GType for + * GrlRemoveFlags */ + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, flags); + set_value (options, GRL_OPERATION_OPTION_REMOVE_FLAGS, &value); + g_value_unset (&value); + + return TRUE; +} + +/** + * grl_operation_options_get_remove_flags: + * @options: a #GrlOperationOptions instance + * + * Returns: remove flags of @options. + * + * Since: 0.2.0 + */ +GrlRemoveFlags +grl_operation_options_get_remove_flags (GrlOperationOptions *options) +{ + const GValue *value; + + if (options) + value = g_hash_table_lookup (options->priv->data, + GRL_OPERATION_OPTION_REMOVE_FLAGS); + else + value = NULL; + + if (value) + return g_value_get_uint (value); + + return REMOVE_FLAGS_DEFAULT; +} + +/** * grl_operation_options_set_type_filter: * @options: a #GrlOperationOptions instance * @filter: the type of media to get diff --git a/src/grl-operation-options.h b/src/grl-operation-options.h index 60bb10d..65a88db 100644 --- a/src/grl-operation-options.h +++ b/src/grl-operation-options.h @@ -117,6 +117,11 @@ gboolean grl_operation_options_set_resolution_flags (GrlOperationOptions *option GrlResolutionFlags grl_operation_options_get_resolution_flags (GrlOperationOptions *options); +gboolean grl_operation_options_set_remove_flags (GrlOperationOptions *options, + GrlRemoveFlags flags); +GrlRemoveFlags + grl_operation_options_get_remove_flags (GrlOperationOptions *options); + gboolean grl_operation_options_set_type_filter (GrlOperationOptions *options, GrlTypeFilter filter); diff --git a/src/grl-source.c b/src/grl-source.c index b368c88..fb340b3 100644 --- a/src/grl-source.c +++ b/src/grl-source.c @@ -1208,6 +1208,7 @@ remove_relay_free (struct RemoveRelayCb *rrc) if (rrc->spec) { g_object_unref (rrc->spec->source); g_object_unref (rrc->spec->media); + g_object_unref (rrc->spec->options); g_free (rrc->spec->media_id); g_free (rrc->spec); } @@ -4159,8 +4160,42 @@ grl_source_query_sync (GrlSource *source, } static gboolean +remove_flags_supported (GrlSource *source, + GrlOperationOptions *options) +{ + GrlRemoveFlags flags, source_flags; + guint i, num_flags; + GrlCaps *caps; + + flags = grl_operation_options_get_remove_flags (options); + + /* 1) Check that no more than one flag is set */ + if (flags == GRL_REMOVE_FLAG_UNKNOWN) + return TRUE; + if (flags == GRL_REMOVE_FLAG_NONE) + return FALSE; + + num_flags = 0; + for (i = 1; i <= 4; i++) { + if (flags & (1 << i)) + num_flags++; + } + if (num_flags > 1) + return FALSE; + + /* 2) Check that it matches what the source supports */ + caps = grl_source_get_caps (source, GRL_OP_REMOVE); + source_flags = grl_caps_get_remove_flags (caps); + if (!(source_flags & flags)) + return FALSE; + + return TRUE; +} + +static gboolean grl_source_store_remove_impl (GrlSource *source, GrlMedia *media, + GrlOperationOptions *options, GrlSourceRemoveCb callback, gpointer user_data) { @@ -4183,6 +4218,14 @@ grl_source_store_remove_impl (GrlSource *source, rrc->user_callback = callback; rrc->user_data = user_data; + if (!remove_flags_supported (source, options)) { + rrc->error = g_error_new (GRL_CORE_ERROR, + GRL_CORE_ERROR_REMOVE_FAILED, + _("Removal type not supported, cannot remove")); + rrc->spec = NULL; + goto end; + } + /* Check that we have the minimum information we need */ id = grl_media_get_id (media); if (!id) { @@ -4190,17 +4233,20 @@ grl_source_store_remove_impl (GrlSource *source, GRL_CORE_ERROR_REMOVE_FAILED, _("Media has no “id”, cannot remove")); rrc->spec = NULL; - } else { - rrc->error = NULL; - rs = g_new0 (GrlSourceRemoveSpec, 1); - rs->source = g_object_ref (source); - rs->media_id = g_strdup (id); - rs->media = g_object_ref (media); - rs->callback = remove_result_relay_cb; - rs->user_data = rrc; - rrc->spec = rs; + goto end; } + rrc->error = NULL; + rs = g_new0 (GrlSourceRemoveSpec, 1); + rs->source = g_object_ref (source); + rs->media_id = g_strdup (id); + rs->media = g_object_ref (media); + rs->options = options ? g_object_ref (options) : NULL; + rs->callback = remove_result_relay_cb; + rs->user_data = rrc; + rrc->spec = rs; + +end: tag_id = g_idle_add (remove_idle, rrc); g_source_set_name_by_id (tag_id, "[grilo] remove_idle"); @@ -4226,7 +4272,7 @@ grl_source_remove (GrlSource *source, GrlSourceRemoveCb callback, gpointer user_data) { - grl_source_store_remove_impl (source, media, callback, user_data); + grl_source_store_remove_impl (source, media, NULL, callback, user_data); } /** @@ -4246,12 +4292,59 @@ grl_source_remove_sync (GrlSource *source, GrlMedia *media, GError **error) { + grl_source_remove_with_options_sync (source, media, NULL, error); +} + +/** + * grl_source_remove_with_options: + * @source: a source + * @media: a data transfer object + * @options: options to pass to this operation + * @callback: (scope notified): the user defined callback + * @user_data: the user data to pass in the callback + * + * Remove a @media from the @source repository. + * + * This method is asynchronous. + * + * Since: 0.2.12 + */ +void +grl_source_remove_with_options (GrlSource *source, + GrlMedia *media, + GrlOperationOptions *options, + GrlSourceRemoveCb callback, + gpointer user_data) +{ + grl_source_store_remove_impl (source, media, options, callback, user_data); +} + +/** + * grl_source_remove_with_options_sync: + * @source: a source + * @media: a data transfer object + * @options: options to pass to this operation + * @error: a #GError, or @NULL + * + * Remove a @media from the @source repository. + * + * This method is synchronous. + * + * Since: 0.2.12 + */ +void +grl_source_remove_with_options_sync (GrlSource *source, + GrlMedia *media, + GrlOperationOptions *options, + GError **error) +{ GrlDataSync *ds; ds = g_slice_new0 (GrlDataSync); if (grl_source_store_remove_impl (source, media, + options, remove_async_cb, ds)) grl_wait_for_async_operation_complete (ds); @@ -4664,6 +4757,7 @@ grl_source_get_caps (GrlSource *source, GrlSupportedOps operation) { static GrlCaps *default_caps = NULL; + static GrlCaps *default_caps_no_remove = NULL; GrlSourceClass *klass = GRL_SOURCE_GET_CLASS (source); if (klass->get_caps) @@ -4671,6 +4765,12 @@ grl_source_get_caps (GrlSource *source, if (!default_caps) default_caps = grl_caps_new (); + if (!default_caps_no_remove) { + default_caps_no_remove = grl_caps_new (); + grl_caps_set_remove_flags (default_caps_no_remove, GRL_REMOVE_FLAG_NONE); + } - return default_caps; + if (grl_source_supported_operations (source) & GRL_OP_REMOVE) + return default_caps; + return default_caps_no_remove; } diff --git a/src/grl-source.h b/src/grl-source.h index 574d608..97b6fb5 100644 --- a/src/grl-source.h +++ b/src/grl-source.h @@ -360,9 +360,10 @@ typedef struct { GrlMedia *media; GrlSourceRemoveCb callback; gpointer user_data; + GrlOperationOptions *options; /*< private >*/ - gpointer _grl_reserved[GRL_PADDING]; + gpointer _grl_reserved[GRL_PADDING - 1]; } GrlSourceRemoveSpec; /** @@ -597,6 +598,17 @@ void grl_source_remove_sync (GrlSource *source, GrlMedia *media, GError **error); +void grl_source_remove_with_options (GrlSource *source, + GrlMedia *media, + GrlOperationOptions *options, + GrlSourceRemoveCb callback, + gpointer user_data); + +void grl_source_remove_with_options_sync (GrlSource *source, + GrlMedia *media, + GrlOperationOptions *options, + GError **error); + void grl_source_store (GrlSource *source, GrlMedia *parent, GrlMedia *media, diff --git a/tools/grilo-test-ui/main.c b/tools/grilo-test-ui/main.c index 17e5389..8976b91 100644 --- a/tools/grilo-test-ui/main.c +++ b/tools/grilo-test-ui/main.c @@ -1001,6 +1001,33 @@ tags_to_str (char **tags) return g_string_free (s, FALSE); } +static char * +remove_flags_to_str (GrlCaps *caps) +{ + GrlRemoveFlags flags; + GString *str; + + if (caps == NULL) + return NULL; + flags = grl_caps_get_remove_flags (caps); + if (flags == GRL_REMOVE_FLAG_UNKNOWN) + return g_strdup ("unknown"); + if (flags == GRL_REMOVE_FLAG_NONE) + return g_strdup ("none"); + str = g_string_new (""); + if (flags & GRL_REMOVE_FLAG_DELETE) + g_string_append (str, "delete, "); + if (flags & GRL_REMOVE_FLAG_TRASH) + g_string_append (str, "trash, "); + if (flags & GRL_REMOVE_FLAG_ARCHIVE) + g_string_append (str, "archive, "); + if (flags & GRL_REMOVE_FLAG_REFERENCE) + g_string_append (str, "reference, "); + if (str->len > 0) + g_string_set_size (str, str->len - 2); + return g_string_free (str, FALSE); +} + static void populate_source_metadata (GrlSource *source) { @@ -1025,6 +1052,7 @@ populate_source_metadata (GrlSource *source) GrlSupportedMedia supported_media; GIcon *icon; char **tags; + GrlCaps *caps; for (i = 0; i < G_N_ELEMENTS (str_props); i++) { g_object_get (G_OBJECT (source), str_props[i], &str, NULL); @@ -1063,6 +1091,11 @@ populate_source_metadata (GrlSource *source) add_source_metadata (view->metadata_model, "source-tags", str); g_free (str); g_strfreev (tags); + + caps = grl_source_get_caps (source, GRL_OP_REMOVE); + str = remove_flags_to_str (caps); + add_source_metadata (view->metadata_model, "remove-flags", str); + g_free (str); } gtk_widget_set_sensitive (view->show_btn, FALSE); @@ -1349,7 +1382,7 @@ remove_btn_clicked_cb (GtkButton *btn, gpointer user_data) BROWSER_MODEL_CONTENT, &media, -1); - grl_source_remove (source, media, remove_cb, NULL); + grl_source_remove_with_options (source, media, NULL, remove_cb, NULL); g_clear_object (&source); g_clear_object (&media); |