hash_add(h, id, empty, HASH_INSERT);
nqd = hash_find(h, id);
}
- if(old)
+ if(old) {
+#if DEBUG_QUEUE
+ fprintf(stderr, " old: %s\n", id);
+#endif
nqd->old = old;
- if(new)
+ }
+ if(new) {
+#if DEBUG_QUEUE
+ fprintf(stderr, " new: %s\n", id);
+#endif
nqd->new = new;
+ }
}
-#if 0
+#if DEBUG_QUEUE
static void dump_queue(struct queue_entry *head, struct queue_entry *mark) {
for(struct queue_entry *q = head; q; q = q->next) {
if(q == mark)
- fprintf(stderr, "!");
- fprintf(stderr, "%s", q->id);
- if(q->next)
- fprintf(stderr, " ");
+ fprintf(stderr, " !");
+ fprintf(stderr, " %s\n", q->id);
}
- fprintf(stderr, "\n");
}
static void dump_rows(struct queuelike *ql) {
while(it) {
struct queue_entry *q = ql_iter_to_q(GTK_TREE_MODEL(ql->store), iter);
it = gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), iter);
- fprintf(stderr, "%s", q->id);
- if(it)
- fprintf(stderr, " ");
+ fprintf(stderr, " %s\n", q->id);
}
- fprintf(stderr, "\n");
}
#endif
++suppress_actions;
/* Tell every queue entry which queue owns it */
- //fprintf(stderr, "%s: filling in q->ql\n", ql->name);
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: filling in q->ql\n", ql->name);
+#endif
for(struct queue_entry *q = newq; q; q = q->next)
q->ql = ql;
- //fprintf(stderr, "%s: constructing h\n", ql->name);
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: constructing h\n", ql->name);
+#endif
/* Construct map from id to new and old structures */
hash *h = hash_new(sizeof(struct newqueue_data));
for(struct queue_entry *q = ql->q; q; q = q->next)
/* The easy bit: delete rows not present any more. In the same pass we
* update the secret column containing the queue_entry pointer. */
- //fprintf(stderr, "%s: deleting rows...\n", ql->name);
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: deleting rows...\n", ql->name);
+#endif
GtkTreeIter iter[1];
gboolean it = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ql->store),
iter);
++kept;
} else {
/* Delete this row (and move iter to the next one) */
- //fprintf(stderr, " delete %s", q->id);
+#if DEBUG_QUEUE
+ fprintf(stderr, " delete %s\n", q->id);
+#endif
it = gtk_list_store_remove(ql->store, iter);
++deleted;
}
/* We're going to have to support arbitrary rearrangements, so we might as
* well add new elements at the end. */
- //fprintf(stderr, "%s: adding rows...\n", ql->name);
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: adding rows...\n", ql->name);
+#endif
struct queue_entry *after = 0;
for(struct queue_entry *q = newq; q; q = q->next) {
const struct newqueue_data *nqd = hash_find(h, q->id);
gtk_list_store_set(ql->store, iter,
ql->ncolumns + QUEUEPOINTER_COLUMN, q,
-1);
- //fprintf(stderr, " add %s", q->id);
+#if DEBUG_QUEUE
+ fprintf(stderr, " add %s\n", q->id);
+#endif
++inserted;
}
after = newq;
* The current code is simple but amounts to a bubble-sort - we might easily
* called gtk_tree_model_iter_next a couple of thousand times.
*/
- //fprintf(stderr, "%s: rearranging rows\n", ql->name);
- //fprintf(stderr, "%s: queue state: ", ql->name);
- //dump_queue(newq, 0);
- //fprintf(stderr, "%s: row state: ", ql->name);
- //dump_rows(ql);
- it = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ql->store),
- iter);
- struct queue_entry *rq = newq; /* r for 'right, correct' */
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: rearranging rows\n", ql->name);
+ fprintf(stderr, "%s: target state:\n", ql->name);
+ dump_queue(newq, 0);
+ fprintf(stderr, "%s: current state:\n", ql->name);
+ dump_rows(ql);
+#endif
+ it = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ql->store), iter);
+ struct queue_entry *tq = newq; /* t-for-target */
int swaps = 0, searches = 0;
+ int row = 0;
while(it) {
- struct queue_entry *q = ql_iter_to_q(GTK_TREE_MODEL(ql->store), iter);
- //fprintf(stderr, " rq = %p, q = %p\n", rq, q);
- //fprintf(stderr, " rq->id = %s, q->id = %s\n", rq->id, q->id);
-
- if(q != rq) {
- //fprintf(stderr, " mismatch\n");
+ struct queue_entry *cq = ql_iter_to_q(GTK_TREE_MODEL(ql->store), iter);
+ /* c-for-current */
+
+ /* Everything has the right queue pointer (see above) so it's sufficient to
+ * compare pointers to detect mismatches */
+ if(cq != tq) {
+#if DEBUG_QUEUE
+ fprintf(stderr, " pointer mismatch at row %d\n", row);
+ fprintf(stderr, " target id %s\n", tq->id);
+ fprintf(stderr, " actual id %s\n", cq->id);
+#endif
+ /* Start looking for the target row fromn the next row */
GtkTreeIter next[1] = { *iter };
gboolean nit = gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), next);
while(nit) {
struct queue_entry *nq = ql_iter_to_q(GTK_TREE_MODEL(ql->store), next);
- //fprintf(stderr, " candidate: %s\n", nq->id);
- if(nq == rq)
+#if DEBUG_QUEUE
+ fprintf(stderr, " candidate: %s\n", nq->id);
+#endif
+ if(nq == tq)
break;
nit = gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), next);
++searches;
}
assert(nit);
- //fprintf(stderr, " found it\n");
gtk_list_store_swap(ql->store, iter, next);
*iter = *next;
- //fprintf(stderr, "%s: new row state: ", ql->name);
- //dump_rows(ql);
+#if DEBUG_QUEUE
+ fprintf(stderr, "%s: found it. new row state:\n", ql->name);
+ dump_rows(ql);
+#endif
++swaps;
}
/* ...and onto the next one */
it = gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), iter);
- rq = rq->next;
+ tq = tq->next;
+ ++row;
}
-#if 0
+#if DEBUG_QUEUE
fprintf(stderr, "%6s: %3d kept %3d inserted %3d deleted %3d swaps %4d searches\n", ql->name,
kept, inserted, deleted, swaps, searches);
+ fprintf(stderr, "done\n");
#endif
- //fprintf(stderr, "done\n");
ql->q = newq;
/* Set the rest of the columns in new rows */
ql_update_list_store(ql);
* This is used by ql_drag_motion() and ql_drag_data_received() to identify a
* drop would or does land. It's important that they use the same code since
* otherwise the visual feedback can be inconsistent with the actual effect!
+ *
+ * Remember to free the returned path.
*/
static GtkTreePath *ql_drop_path(GtkWidget *w,
GtkTreeModel *model,
if(path)
gtk_tree_path_free(path);
}
- /* TODO _something_ is not quite right here. Supposedly if action=0 we
- * should probably be returning FALSE; _but_ actually we always want to
- * support dropping, as dropping into the big empty space at the bottom
- * should be the same as dropping at the end of the last row.
- *
- * As the code stands the drop works but the visual feedback is not quite
- * right.
- */
autoscroll_add(GTK_TREE_VIEW(w));
return TRUE; /* We are (always) in a drop zone */
}
ql->drop(ql, tracks->nvec, tracks->vec, NULL, q);
break;
}
+ if(path)
+ gtk_tree_path_free(path);
}
/** @brief Initialize a @ref queuelike */
/* The selection should support multiple things being selected */
ql->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ql->view));
+ g_object_ref(ql->selection);
gtk_tree_selection_set_mode(ql->selection, GTK_SELECTION_MULTIPLE);
/* Catch button presses */
/* TODO style? */
- ql->init(ql);
+ if(ql->init)
+ ql->init(ql);
/* Update display text when lookups complete */
event_register("lookups-completed", queue_lookups_completed, ql);
return scrolled;
}
+/** @brief Destroy a queuelike
+ * @param ql Queuelike to destroy
+ *
+ * Returns @p ql to its initial state.
+ */
+void destroy_queuelike(struct queuelike *ql) {
+ if(ql->store) {
+ g_object_unref(ql->store);
+ ql->store = NULL;
+ }
+ if(ql->view) {
+ gtk_object_destroy(GTK_OBJECT(ql->view));
+ ql->view = NULL;
+ }
+ if(ql->menu) {
+ gtk_object_destroy(GTK_OBJECT(ql->menu));
+ ql->menu = NULL;
+ }
+ if(ql->selection) {
+ g_object_unref(ql->selection);
+ ql->selection = NULL;
+ }
+ ql->q = NULL;
+}
+
/*
Local Variables:
c-basic-offset:2