[easytag/wip/musicbrainz-support-merge: 9/75] Implemented Cancellation of Manual Search using GCancellable
- From: Abhinav Jangda <abhijangda src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [easytag/wip/musicbrainz-support-merge: 9/75] Implemented Cancellation of Manual Search using GCancellable
- Date: Fri, 15 Aug 2014 19:09:34 +0000 (UTC)
commit 40e13e6a10aa382f174db697c4df029b73b4b5ce
Author: Abhinav <abhijangda hotmail com>
Date: Sun May 25 21:31:13 2014 +0530
Implemented Cancellation of Manual Search using GCancellable
Added various cancellation checks in all the modified files
Created a new GCancellable and pass it to every GSimpleResult thread function
Added a Stop button to allow cancellation
src/mb_search.c | 137 ++++++++++++++++++++++++++++++++++++++++------
src/mb_search.h | 8 ++-
src/mbentityview.c | 83 ++++++++++++++++++++++++++--
src/musicbrainz_dialog.c | 58 +++++++++++++++++---
4 files changed, 253 insertions(+), 33 deletions(-)
---
diff --git a/src/mb_search.c b/src/mb_search.c
index 326c5e4..f6e3d19 100644
--- a/src/mb_search.c
+++ b/src/mb_search.c
@@ -21,6 +21,14 @@
#include "mb_search.h"
#include "musicbrainz_dialog.h"
+void
+et_set_cancel_error (GError **error)
+{
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+}
+
/*
* et_mb5_search_error_quark:
*
@@ -36,19 +44,21 @@ et_mb5_search_error_quark (void)
/*
* et_musicbrainz_search_in_entity:
- * @string:
- * @child_type:
- * @parent_type:
- * @parent_mbid:
- * @root:
+ * @child_type: Type of the children to get.
+ * @parent_type: Type of the parent.
+ * @parent_mbid: MBID of parent entity.
+ * @root: GNode of parent.
+ * @error: GError
*
+ * To retrieve children entities of a parent entity.
*
+ * Returns: TRUE if successfull, FALSE if not.
*/
gboolean
et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
enum MB_ENTITY_TYPE parent_type,
gchar *parent_mbid, GNode *root,
- GError **error)
+ GError **error, GCancellable *cancellable)
{
Mb5Query query;
Mb5Metadata metadata;
@@ -57,6 +67,15 @@ et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
char *param_values[1];
char *param_names[1];
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
param_names [0] = "inc";
query = mb5_query_new ("easytag", NULL, 0);
@@ -77,6 +96,17 @@ et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
Mb5Artist artist;
gchar *message;
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
artist = mb5_metadata_get_artist (metadata);
list = mb5_artist_get_releaselist (artist);
param_values[0] = "artists release-groups";
@@ -96,6 +126,17 @@ et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
EtMbEntity *entity;
int size;
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
size = mb5_release_get_title ((Mb5Release)release, buf,
sizeof (buf));
buf [size] = '\0';
@@ -174,6 +215,17 @@ et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
{
Mb5Recording recording;
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
recording = mb5_track_get_recording (mb5_track_list_item (track_list, j));
size = mb5_recording_get_title (recording, buf,
sizeof (buf));
@@ -263,15 +315,18 @@ et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
/*
* et_musicbrainz_search:
- * @string:
- * @type:
- * @root:
+ * @string: String to search in MusicBrainz database.
+ * @type: Type of entity to search.
+ * @root: Root of the mbTree.
+ * @error: GError.
*
+ * To search for an entity in MusicBrainz Database.
*
+ * Returns: TRUE if successfull, FALSE if not.
*/
gboolean
et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
- GError **error)
+ GError **error, GCancellable *cancellable)
{
Mb5Query query;
Mb5Metadata metadata;
@@ -287,12 +342,24 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
param_values [1] = SEARCH_LIMIT_STR;
query = mb5_query_new ("easytag", NULL, 0);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
if (type == MB_ENTITY_TYPE_ARTIST)
{
param_values [0] = g_strconcat ("artist:", string, NULL);
metadata = mb5_query_query (query, "artist", "", "", 2, param_names,
param_values);
+ g_free (param_values [0]);
result = mb5_query_get_lastresult (query);
+
if (result == eQuery_Success)
{
if (metadata)
@@ -304,7 +371,20 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
for (i = 0; i < mb5_artist_list_size (list); i++)
{
Mb5Artist artist;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
artist = mb5_artist_list_item (list, i);
+
if (artist)
{
GNode *node;
@@ -319,7 +399,6 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
}
}
- g_free (param_values [0]);
mb5_metadata_delete (metadata);
}
else
@@ -342,20 +421,33 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
{
int i;
Mb5ReleaseList list;
+ gchar *message;
+
list = mb5_metadata_get_releaselist (metadata);
param_names [0] = "inc";
param_values [0] = "artists release-groups";
+ message = g_strdup_printf ("Found %d Album(s)",
+ mb5_release_list_size (list));
+ et_show_status_msg_in_idle (message);
+ g_free (message);
for (i = 0; i < mb5_release_list_size (list); i++)
{
Mb5Release release;
- gchar *message;
- message = g_strdup_printf ("Found %d Album(s)", mb5_release_list_size (list));
- et_show_status_msg_in_idle (message);
- g_free (message);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
release = mb5_release_list_item (list, i);
+
if (release)
{
Mb5Metadata metadata_release;
@@ -432,6 +524,17 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
EtMbEntity *entity;
int size;
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ mb5_query_delete (query);
+ mb5_metadata_delete (metadata);
+ g_assert (error == NULL || *error != NULL);
+ return FALSE;
+ }
+
recording = mb5_recording_list_item (list, i);
size = mb5_recording_get_title (recording, buf, sizeof (buf));
buf [size] = '\0';
@@ -517,9 +620,9 @@ et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
/*
* free_mb_tree:
- * @node:
- *
+ * @node: Root of the tree to start freeing with.
*
+ * To free the memory occupied by the tree.
*/
void
free_mb_tree (GNode *node)
diff --git a/src/mb_search.h b/src/mb_search.h
index 6ba9e7b..156f9c6 100644
--- a/src/mb_search.h
+++ b/src/mb_search.h
@@ -52,6 +52,7 @@ GQuark et_mb5_search_error_quark (void);
* @ET_MB5_SEARCH_ERROR_FETCH: Cannot Fetch Data
* @ET_MB5_SEARCH_ERROR_REQUEST: Request to MusicBrainz Server cannot be made
* @ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND: Resource user is trying to search is not found
+ * @ET_MB5_SEARCH_ERROR_CANCELLED: Operation was cancelled
*
* Errors while searching MusicBrainz Server.
*/
@@ -63,6 +64,7 @@ typedef enum
ET_MB5_SEARCH_ERROR_FETCH,
ET_MB5_SEARCH_ERROR_REQUEST,
ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
} EtMB5SearchError;
enum MB_ENTITY_TYPE
@@ -88,10 +90,12 @@ gboolean
et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
enum MB_ENTITY_TYPE parent_type,
gchar *parent_mbid, GNode *root,
- GError **error);
+ GError **error, GCancellable *cancellable);
gboolean
et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
- GError **error);
+ GError **error, GCancellable *cancellable);
void
free_mb_tree (GNode *node);
+void
+et_set_cancel_error (GError **error);
#endif /* __MB_SEARCH_H__ */
diff --git a/src/mbentityview.c b/src/mbentityview.c
index 43ab295..c3fd8dc 100644
--- a/src/mbentityview.c
+++ b/src/mbentityview.c
@@ -54,13 +54,17 @@ static GSimpleAsyncResult *async_result;
/*
* EtMbEntityViewPrivate:
* @bread_crumb_box: GtkBox which represents the BreadCrumbWidget
- * @tree_view: GtkTreeView to display the recieved music brainz data
* @bread_crumb_nodes: Array of GNode being displayed by the GtkToggleButton
+ * @tree_view: GtkTreeView to display the recieved music brainz data
* @list_store: GtkTreeStore for treeView
* @scrolled_window: GtkScrolledWindow for treeView
* @mb_tree_root: Root Node of the Mb5Entity Tree
* @mb_tree_current_node: Current node being displayed by EtMbEntityView
* @active_toggle_button: Current active GtkToggleToolButton
+ * @filter: GtkTreeModelFilter to filter rows based on the conditions
+ * @search_or_red: Toggle Red Lines or Search in results
+ * @toggle_red_lines: Display Red Lines or not
+ * @text_to_search_in_results: Text to search in results
*
* Private data for EtMbEntityView.
*/
@@ -75,11 +79,19 @@ typedef struct
GNode *mb_tree_current_node;
GtkWidget *active_toggle_button;
GtkTreeModel *filter;
- gboolean search_or_red;
+ int search_or_red;
gboolean toggle_red_lines;
const gchar *text_to_search_in_results;
} EtMbEntityViewPrivate;
+/*
+ * SearchInLevelThreadData:
+ * @entity_view: EtMbEntityView
+ * @child: GNode for which to retrieve children
+ * @iter: Iter to the row of GNode
+ *
+ * Used for passing to Thread Function of Search In Levels.
+ */
typedef struct
{
EtMbEntityView *entity_view;
@@ -113,6 +125,16 @@ tree_filter_visible_func (GtkTreeModel *model, GtkTreeIter *iter,
* Functions *
*************/
+/*
+ * tree_filter_visible_func:
+ * @model: GtkTreeModel
+ * @iter: GtkTreeIter of current tree row
+ * @data: user data passed
+ *
+ * Filter function of GtkTreeModelFilter
+ *
+ * Returns: TRUE if row should be displayed or FALSE if it shouldn't.
+ */
static gboolean
tree_filter_visible_func (GtkTreeModel *model, GtkTreeIter *iter,
gpointer data)
@@ -269,7 +291,6 @@ add_iter_to_list_store (GtkListStore *list_store, GNode *node)
{
case MB_ENTITY_TYPE_ARTIST:
mb5_artist_get_name ((Mb5Artist)entity, name, sizeof (name));
- //gtk_list_store_append (list_store, &iter);
gtk_list_store_insert_with_values (list_store, &iter, -1,
MB_ARTIST_COLUMNS_N, "black", -1);
gtk_list_store_set (list_store, &iter,
@@ -300,7 +321,6 @@ add_iter_to_list_store (GtkListStore *list_store, GNode *node)
case MB_ENTITY_TYPE_ALBUM:
mb5_release_get_title ((Mb5Release)entity, name,
sizeof (name));
- //gtk_list_store_append (list_store, &iter);
gtk_list_store_insert_with_values (list_store, &iter, -1,
MB_ALBUM_COLUMNS_N, "black", -1);
gtk_list_store_set (list_store, &iter,
@@ -552,6 +572,14 @@ toggle_button_clicked (GtkWidget *btn, gpointer user_data)
show_data_in_entity_view (entity_view);
}
+/*
+ * manual_search_callback:
+ * @source: Source Object
+ * @res: GAsyncResult
+ * @user_data: User data
+ *
+ * Callback function for GAsyncResult for Search In Levels.
+ */
static void
search_in_levels_callback (GObject *source, GAsyncResult *res,
gpointer user_data)
@@ -564,6 +592,13 @@ search_in_levels_callback (GObject *source, GAsyncResult *res,
GList *children;
GList *active_child;
+ if (!g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res)))
+ {
+ g_object_unref (res);
+ g_free (user_data);
+ return;
+ }
+
thread_data = user_data;
entity_view = thread_data->entity_view;
priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
@@ -605,6 +640,14 @@ search_in_levels_callback (GObject *source, GAsyncResult *res,
g_free (thread_data);
}
+/*
+ * manual_search_callback:
+ * @res: GAsyncResult
+ * @obj: Source Object
+ * @cancellable: User data
+ *
+ * Search in Levels Thread Function
+ */
static void
search_in_levels_thread_func (GSimpleAsyncResult *res, GObject *obj,
GCancellable *cancellable)
@@ -618,6 +661,18 @@ search_in_levels_thread_func (GSimpleAsyncResult *res, GObject *obj,
child_entity_type_str = NULL;
thread_data = g_async_result_get_user_data (G_ASYNC_RESULT (res));
+ g_simple_async_result_set_op_res_gboolean (res, FALSE);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (&error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ g_simple_async_report_gerror_in_idle (NULL,
+ mb5_search_error_callback,
+ NULL, error);
+ return;
+ }
if (((EtMbEntity *)thread_data->child->data)->type ==
MB_ENTITY_TYPE_TRACK)
@@ -650,14 +705,29 @@ search_in_levels_thread_func (GSimpleAsyncResult *res, GObject *obj,
g_free (status_msg);
g_free (child_entity_type_str);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error (&error, ET_MB5_SEARCH_ERROR,
+ ET_MB5_SEARCH_ERROR_CANCELLED,
+ "Operation cancelled by user");
+ g_simple_async_report_gerror_in_idle (NULL,
+ mb5_search_error_callback,
+ NULL, error);
+ return;
+ }
+
if (!et_musicbrainz_search_in_entity (((EtMbEntity *)thread_data->child->data)->type + 1,
((EtMbEntity *)thread_data->child->data)->type,
- mbid, thread_data->child, &error))
+ mbid, thread_data->child, &error,
+ cancellable))
{
g_simple_async_report_gerror_in_idle (NULL,
mb5_search_error_callback,
thread_data, error);
+ return;
}
+
+ g_simple_async_result_set_op_res_gboolean (res, TRUE);
}
/*
@@ -714,9 +784,10 @@ tree_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path,
search_in_levels_callback,
thread_data,
tree_view_row_activated);
+ mb5_search_cancellable = g_cancellable_new ();
g_simple_async_result_run_in_thread (async_result,
search_in_levels_thread_func,
- 0, NULL);
+ 0, mb5_search_cancellable);
}
/*
diff --git a/src/musicbrainz_dialog.c b/src/musicbrainz_dialog.c
index d36ad78..2287d4b 100644
--- a/src/musicbrainz_dialog.c
+++ b/src/musicbrainz_dialog.c
@@ -62,6 +62,15 @@ manual_search_callback (GObject *source, GAsyncResult *res,
{
GtkComboBoxText *combo_box;
+ if (!g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res)))
+ {
+ g_object_unref (res);
+ g_free (user_data);
+ free_mb_tree (mb_tree_root);
+ mb_tree_root = g_node_new (NULL);
+ return;
+ }
+
et_mb_entity_view_set_tree_root (ET_MB_ENTITY_VIEW (entityView),
mb_tree_root);
gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
@@ -98,7 +107,7 @@ et_show_status_msg_in_idle_cb (GObject *obj, GAsyncResult *res,
* @res: GAsyncResult
* @user_data: User data
*
- * Function to Display StatusBar Message.
+ * Function to Display StatusBar Messages in Main Thread.
*/
void
et_show_status_msg_in_idle (gchar *message)
@@ -113,12 +122,12 @@ et_show_status_msg_in_idle (gchar *message)
}
/*
- * et_show_status_msg_in_idle_cb:
+ * mb5_search_error_callback:
* @obj: Source Object
* @res: GAsyncResult
* @user_data: User data
*
- * Callback function for Displaying StatusBar Message.
+ * Callback function for displaying errors.
*/
void
mb5_search_error_callback (GObject *source, GAsyncResult *res,
@@ -133,7 +142,6 @@ mb5_search_error_callback (GObject *source, GAsyncResult *res,
gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
0, dest->message);
g_error_free (dest);
- g_free (user_data);
}
/*
@@ -153,18 +161,52 @@ manual_search_thread_func (GSimpleAsyncResult *res, GObject *obj,
gchar *status_msg;
error = NULL;
+ g_simple_async_result_set_op_res_gboolean (res, FALSE);
+
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ et_set_cancel_error (&error);
+ g_simple_async_report_gerror_in_idle (NULL,
+ mb5_search_error_callback,
+ NULL, error);
+ return;
+ }
+
thread_data = (ManualSearchThreadData *)g_async_result_get_user_data (G_ASYNC_RESULT (res));
- status_msg = g_strconcat ("Searching ", thread_data->text_to_search, NULL);
+ status_msg = g_strconcat ("Searching ", thread_data->text_to_search,
+ NULL);
et_show_status_msg_in_idle (status_msg);
g_free (status_msg);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ et_set_cancel_error (&error);
+ g_simple_async_report_gerror_in_idle (NULL,
+ mb5_search_error_callback,
+ thread_data, error);
+ return;
+ }
+
if (!et_musicbrainz_search (thread_data->text_to_search,
- thread_data->type, mb_tree_root, &error))
+ thread_data->type, mb_tree_root, &error,
+ cancellable))
+ {
+ g_simple_async_report_gerror_in_idle (NULL,
+ mb5_search_error_callback,
+ thread_data, error);
+ return;
+ }
+
+ if (g_cancellable_is_cancelled (cancellable))
{
+ et_set_cancel_error (&error);
g_simple_async_report_gerror_in_idle (NULL,
mb5_search_error_callback,
thread_data, error);
+ return;
}
+
+ g_simple_async_result_set_op_res_gboolean (res, TRUE);
}
/*
@@ -197,7 +239,6 @@ btn_manual_find_clicked (GtkWidget *btn, gpointer user_data)
thread_data->type = type;
thread_data->text_to_search = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cb_manual_search));
mb5_search_cancellable = g_cancellable_new ();
- /* TODO: Add Cancellable object */
gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
0, "Starting MusicBrainz Search");
async_result = g_simple_async_result_new (NULL, manual_search_callback,
@@ -330,7 +371,8 @@ static void
entry_tree_view_search_changed (GtkEditable *editable, gpointer user_data)
{
et_mb_entity_view_search_in_results (ET_MB_ENTITY_VIEW (entityView),
- gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder,
"entryTreeViewSearch"))));
+ gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder,
+ "entryTreeViewSearch"))));
}
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]