summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2014-02-21 16:22:22 +0100
committerBastien Nocera <hadess@hadess.net>2020-08-26 12:36:14 +0200
commit95dd1c21806c732bb61ad9a79645c51698cdddd4 (patch)
tree7284a453d1dfb40640cd792dc8d94db784cacefd
parentdc6be701e124ed78b14347bb0c131715d3f011c8 (diff)
downloadgrilo-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.c35
-rw-r--r--src/grl-caps.h26
-rw-r--r--src/grl-operation-options-priv.h1
-rw-r--r--src/grl-operation-options.c57
-rw-r--r--src/grl-operation-options.h5
-rw-r--r--src/grl-source.c122
-rw-r--r--src/grl-source.h14
-rw-r--r--tools/grilo-test-ui/main.c35
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);