* TODO:
* - sweep up contracted nodes
* - update when content may have changed (e.g. after a rescan)
- * - searching!
* - proper sorting
*/
/** @brief The selection tree's selection */
GtkTreeSelection *choose_selection;
+/** @brief Count of file listing operations in flight */
+static int choose_list_in_flight;
+
+/** @brief Count of files inserted in current batch of listing operations */
+static int choose_inserted;
+
static char *choose_get_string(GtkTreeIter *iter, int column) {
gchar *gs;
gtk_tree_model_get(GTK_TREE_MODEL(choose_store), iter,
LENGTH_COLUMN, length,
STATE_COLUMN, queued(track),
-1);
+ if(choose_is_search_result(track))
+ gtk_tree_store_set(choose_store, it,
+ BG_COLUMN, SEARCH_RESULT_BG,
+ FG_COLUMN, SEARCH_RESULT_FG,
+ -1);
+ else
+ gtk_tree_store_set(choose_store, it,
+ BG_COLUMN, (char *)0,
+ FG_COLUMN, (char *)0,
+ -1);
}
return FALSE; /* continue walking */
}
static void choose_populate(GtkTreeRowReference *parent_ref,
int nvec, char **vec,
int isfile) {
+ const char *type = isfile ? "track" : "dir";
/* Compute parent_* */
GtkTreeIter pit[1], *parent_it;
GtkTreePath *parent_path;
pit, parent_path);
assert(pitv);
/*fprintf(stderr, "choose_populate %s: parent path is [%s]\n",
- choose_type_map[type],
+ type,
gtk_tree_path_to_string(parent_path));*/
} else {
parent_path = 0;
parent_it = 0;
/*fprintf(stderr, "choose_populate %s: populating the root\n",
- choose_type_map[type]);*/
+ type);*/
}
/* Remove unwanted nodes and find out which we must add */
- //fprintf(stderr, " trimming unwanted %s nodes\n", choose_type_map[type]);
- char *found = xmalloc(nvec);
+ //fprintf(stderr, " trimming unwanted %s nodes\n", type);
+ struct tracksort_data *td = tracksort_init(nvec, vec, type);
GtkTreeIter it[1];
gboolean itv = gtk_tree_model_iter_children(GTK_TREE_MODEL(choose_store),
it,
keep = 0;
} else if(choose_is_file(it) == isfile) {
/* This is the type we care about */
- //fprintf(stderr, " %s is a %s\n", track, isfile ? "file" : "dir");
+ //fprintf(stderr, " %s is a %s\n", track, type);
int n;
- for(n = 0; n < nvec && strcmp(vec[n], track); ++n)
+ for(n = 0; n < nvec && strcmp(td[n].track, track); ++n)
;
if(n < nvec) {
//fprintf(stderr, " ... and survives\n");
- found[n] = 1;
+ td[n].extra = td;
keep = 1;
} else {
//fprintf(stderr, " ... and is to be removed\n");
}
/* Add nodes we don't have */
int inserted = 0;
- //fprintf(stderr, " inserting new %s nodes\n", choose_type_map[type]);
- const char *typename = isfile ? "track" : "dir";
+ //fprintf(stderr, " inserting new %s nodes\n", type);
for(int n = 0; n < nvec; ++n) {
- if(!found[n]) {
- //fprintf(stderr, " %s was not found\n", vec[n]);
+ if(!td[n].extra) {
+ //fprintf(stderr, " %s was not found\n", td[n].track);
gtk_tree_store_append(choose_store, it, parent_it);
gtk_tree_store_set(choose_store, it,
- NAME_COLUMN, trackname_transform(typename,
- vec[n],
- "display"),
+ NAME_COLUMN, td[n].display,
ISFILE_COLUMN, isfile,
- TRACK_COLUMN, vec[n],
- SORT_COLUMN, trackname_transform(typename,
- vec[n],
- "sort"),
+ TRACK_COLUMN, td[n].track,
+ SORT_COLUMN, td[n].sort,
-1);
/* Update length and state; we expect this to kick off length lookups
* rather than necessarily get the right value the first time round. */
gtk_tree_row_reference_free(parent_ref);
gtk_tree_path_free(parent_path);
}
+ /* We only notify others that we've inserted tracks when there are no more
+ * insertions pending, so that they don't have to keep track of how many
+ * requests they've made. */
+ choose_inserted += inserted;
+ if(--choose_list_in_flight == 0) {
+ /* Notify interested parties that we inserted some tracks, AFTER making
+ * sure that the row is properly expanded */
+ if(choose_inserted) {
+ event_raise("choose-inserted-tracks", parent_it);
+ choose_inserted = 0;
+ }
+ }
}
static void choose_dirs_completed(void *v,
gtk_tree_row_reference_new(GTK_TREE_MODEL(choose_store),
path));
/* The row references are destroyed in the _completed handlers. */
+ choose_list_in_flight += 2;
}
/** @brief Create the choose tab */
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
G_TYPE_STRING);
/* Create the view */
/* Create cell renderers and columns */
/* TODO use a table */
{
- GtkCellRenderer *r = gtk_cell_renderer_text_new();
+ GtkCellRenderer *r = gtk_cell_renderer_toggle_new();
GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
- ("Track",
+ ("Queued",
r,
- "text", NAME_COLUMN,
+ "active", STATE_COLUMN,
+ "visible", ISFILE_COLUMN,
(char *)0);
gtk_tree_view_column_set_resizable(c, TRUE);
gtk_tree_view_column_set_reorderable(c, TRUE);
- g_object_set(c, "expand", TRUE, (char *)0);
gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
+ g_signal_connect(r, "toggled",
+ G_CALLBACK(choose_state_toggled), 0);
}
{
GtkCellRenderer *r = gtk_cell_renderer_text_new();
gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
}
{
- GtkCellRenderer *r = gtk_cell_renderer_toggle_new();
+ GtkCellRenderer *r = gtk_cell_renderer_text_new();
GtkTreeViewColumn *c = gtk_tree_view_column_new_with_attributes
- ("Queued",
+ ("Track",
r,
- "active", STATE_COLUMN,
- "visible", ISFILE_COLUMN,
+ "text", NAME_COLUMN,
+ "background", BG_COLUMN,
+ "foreground", FG_COLUMN,
(char *)0);
gtk_tree_view_column_set_resizable(c, TRUE);
gtk_tree_view_column_set_reorderable(c, TRUE);
+ g_object_set(c, "expand", TRUE, (char *)0);
gtk_tree_view_append_column(GTK_TREE_VIEW(choose_view), c);
- g_signal_connect(r, "toggled",
- G_CALLBACK(choose_state_toggled), 0);
+ gtk_tree_view_set_expander_column(GTK_TREE_VIEW(choose_view), c);
}
/* The selection should support multiple things being selected */
event_register("queue-list-changed", choose_set_state, 0);
event_register("playing-track-changed", choose_set_state, 0);
-
+ event_register("search-results-changed", choose_set_state, 0);
+ event_register("lookups-completed", choose_set_state, 0);
+
/* Fill the root */
disorder_eclient_files(client, choose_files_completed, "", NULL, NULL);
disorder_eclient_dirs(client, choose_dirs_completed, "", NULL, NULL);
-
+
/* Make the widget scrollable */
GtkWidget *scrolled = scroll_widget(choose_view);
- g_object_set_data(G_OBJECT(scrolled), "type", (void *)&choose_tabtype);
- return scrolled;
+
+ /* Pack vertically with the search widget */
+ GtkWidget *vbox = gtk_vbox_new(FALSE/*homogenous*/, 1/*spacing*/);
+ gtk_box_pack_start(GTK_BOX(vbox), scrolled,
+ TRUE/*expand*/, TRUE/*fill*/, 0/*padding*/);
+ gtk_box_pack_end(GTK_BOX(vbox), choose_search_widget(),
+ FALSE/*expand*/, FALSE/*fill*/, 0/*padding*/);
+
+ g_object_set_data(G_OBJECT(vbox), "type", (void *)&choose_tabtype);
+ return vbox;
}
/*