From 2271707479533be4bc9ee77e98c615db18621ac3 Mon Sep 17 00:00:00 2001 Message-Id: <2271707479533be4bc9ee77e98c615db18621ac3.1713996567.git.mdw@distorted.org.uk> From: Mark Wooding Date: Wed, 11 Jun 2008 12:31:12 +0100 Subject: [PATCH] Remove tracks now works again. queue_entry pointers are now stashed in the list store, making this rather easier. Organization: Straylight/Edgeware From: Richard Kettlewell --- disobedience/queue-generic.c | 48 +++++++++++++++++++++++++++--------- disobedience/queue-generic.h | 2 ++ disobedience/queue-menu.c | 43 +++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/disobedience/queue-generic.c b/disobedience/queue-generic.c index 5196995..f165832 100644 --- a/disobedience/queue-generic.c +++ b/disobedience/queue-generic.c @@ -215,7 +215,7 @@ const char *column_who(const struct queue_entry *q, /** @brief Format one of the track name columns */ const char *column_namepart(const struct queue_entry *q, - const char *data) { + const char *data) { D(("column_namepart")); return namepart(q->track, "display", data); } @@ -253,19 +253,25 @@ const char *column_length(const struct queue_entry *q, /* Selection processing ---------------------------------------------------- */ +static void save_selection_callback(GtkTreeModel *model, + GtkTreePath attribute((unused)) *path, + GtkTreeIter *iter, + gpointer data) { + hash *h = data; + struct queuelike *ql = g_object_get_data(G_OBJECT(model), "ql"); + + hash_add(h, ql_iter_to_q(ql, iter)->id, "", HASH_INSERT); +} + /** @brief Stash the selection of @c ql->view * @param ql Queuelike of interest * @return Hash representing current selection */ static hash *save_selection(struct queuelike *ql) { hash *h = hash_new(1); - GtkTreeIter iter[1]; - gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ql->store), iter); - for(const struct queue_entry *q = ql->q; q; q = q->next) { - if(gtk_tree_selection_iter_is_selected(ql->selection, iter)) - hash_add(h, q->id, "", HASH_INSERT); - gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), iter); - } + gtk_tree_selection_selected_foreach(ql->selection, + save_selection_callback, + h); return h; } @@ -296,6 +302,22 @@ static void restore_selection(struct queuelike *ql, hash *h) { /* List store maintenance -------------------------------------------------- */ +/** @brief Return the @ref queue_entry corresponding to @p iter + * @param ql Owning queuelike + * @param iter Tree iterator + * @return ID string + */ +struct queue_entry *ql_iter_to_q(struct queuelike *ql, + GtkTreeIter *iter) { + GValue v[1]; + memset(v, 0, sizeof v); + gtk_tree_model_get_value(GTK_TREE_MODEL(ql->store), iter, ql->ncolumns, v); + assert(G_VALUE_TYPE(v) == G_TYPE_POINTER); + struct queue_entry *const q = g_value_get_pointer(v); + g_value_unset(v); + return q; +} + /** @brief Update one row of a list store * @param q Queue entry * @param iter Iterator referring to row or NULL to work it out @@ -322,6 +344,8 @@ void ql_update_row(struct queue_entry *q, col, ql->columns[col].value(q, ql->columns[col].data), -1); + /* The hidden extra column is the queue entry */ + gtk_list_store_set(ql->store, iter, ql->ncolumns, q, -1); } /** @brief Update the list store @@ -371,11 +395,13 @@ void ql_new_queue(struct queuelike *ql, /** @brief Initialize a @ref queuelike */ GtkWidget *init_queuelike(struct queuelike *ql) { D(("init_queuelike")); - /* Create the list store */ - GType *types = xcalloc(ql->ncolumns, sizeof (GType)); + /* Create the list store. We add an extra column to hold the ID. */ + GType *types = xcalloc(ql->ncolumns + 1, sizeof (GType)); for(int n = 0; n < ql->ncolumns; ++n) types[n] = G_TYPE_STRING; - ql->store = gtk_list_store_newv(ql->ncolumns, types); + types[ql->ncolumns] = G_TYPE_POINTER; + ql->store = gtk_list_store_newv(ql->ncolumns + 1, types); + g_object_set_data(G_OBJECT(ql->store), "ql", (void *)ql); /* Create the view */ ql->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ql->store)); diff --git a/disobedience/queue-generic.h b/disobedience/queue-generic.h index c2cb119..8733a43 100644 --- a/disobedience/queue-generic.h +++ b/disobedience/queue-generic.h @@ -152,6 +152,8 @@ const char *column_namepart(const struct queue_entry *q, const char *column_length(const struct queue_entry *q, const char *data); struct tabtype *ql_tabtype(struct queuelike *ql); +struct queue_entry *ql_iter_to_q(struct queuelike *ql, + GtkTreeIter *iter); #endif /* QUEUE_GENERIC_H */ diff --git a/disobedience/queue-menu.c b/disobedience/queue-menu.c index 5254871..a8cd691 100644 --- a/disobedience/queue-menu.c +++ b/disobedience/queue-menu.c @@ -82,14 +82,49 @@ void ql_scratch_activate(GtkMenuItem attribute((unused)) *menuitem, /* Remove */ +static void remove_sensitive_callback(GtkTreeModel *model, + GtkTreePath attribute((unused)) *path, + GtkTreeIter *iter, + gpointer data) { + struct queuelike *ql = g_object_get_data(G_OBJECT(model), "ql"); + struct queue_entry *q = ql_iter_to_q(ql, iter); + const int removable = (q != playing_track + && right_removable(last_rights, config->username, q)); + int *const counts = data; + ++counts[removable]; +} + int ql_remove_sensitive(struct queuelike *ql) { - return gtk_tree_selection_count_selected_rows(ql->selection) > 0; - /* TODO ... but not if only selected track is playing track */ + int counts[2] = { 0, 0 }; + gtk_tree_selection_selected_foreach(ql->selection, + remove_sensitive_callback, + counts); + /* Remove will work if we have at least some removable tracks selected, and + * no unremovable ones */ + return counts[1] > 0 && counts[0] == 0; +} + +static void remove_completed(void attribute((unused)) *v, const char *error) { + if(error) + popup_protocol_error(0, error); +} + +static void remove_activate_callback(GtkTreeModel *model, + GtkTreePath attribute((unused)) *path, + GtkTreeIter *iter, + gpointer attribute((unused)) data) { + struct queuelike *ql = g_object_get_data(G_OBJECT(model), "ql"); + struct queue_entry *q = ql_iter_to_q(ql, iter); + + disorder_eclient_remove(client, q->id, remove_completed, q); } void ql_remove_activate(GtkMenuItem attribute((unused)) *menuitem, - gpointer attribute((unused)) user_data) { - /* TODO */ + gpointer user_data) { + struct queuelike *ql = user_data; + gtk_tree_selection_selected_foreach(ql->selection, + remove_activate_callback, + 0); } /* Play */ -- [mdw]