From a0e78d9698411f5edc54f6aec0040cecfb3f9f65 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sun, 7 Dec 2008 20:20:51 +0000 Subject: [PATCH] Replace rather bizarre 'select all' in choose tab with 'select children' which (after jumping through some hoops) selects just the file children of the selected directory. Organization: Straylight/Edgeware From: Richard Kettlewell Updated the Disobedience documentation a bit. --- CHANGES.html | 6 +- disobedience/choose-menu.c | 149 ++++++++++++++++++++++++++----------- disobedience/choose.c | 1 + disobedience/choose.h | 3 + doc/disobedience.1.in | 31 ++++++-- 5 files changed, 137 insertions(+), 53 deletions(-) diff --git a/CHANGES.html b/CHANGES.html index 495d898..e8436a4 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -58,7 +58,7 @@ span.command {

This file documents recent user-visible changes to DisOrder.

-

Changes up to version XXX

+

Changes up to version 4.3

@@ -73,6 +73,10 @@ span.command {

Disobedience's icons have been changed to larger, more colorful ones. The SVG source is included if you want to fiddle with them.

+

“Select all” is now no longer available in the choose + tab. Instead there is a new “Select children” option which + selects the file children of a single subdirectory.

+

Server

diff --git a/disobedience/choose-menu.c b/disobedience/choose-menu.c index 37167e7..16aa593 100644 --- a/disobedience/choose-menu.c +++ b/disobedience/choose-menu.c @@ -25,6 +25,9 @@ /** @brief Popup menu */ static GtkWidget *choose_menu; +/** @brief Path to directory pending a "select children" operation */ +static GtkTreePath *choose_eventually_select_children; + /** @brief Recursion step for choose_get_visible() * @param parent A visible node, or NULL for the root * @param callback Called for each visible node @@ -71,52 +74,14 @@ static int choose_visible_recurse(GtkTreeIter *parent, return 0; } -static void choose_visible_visit(int (*callback)(GtkTreeIter *it, - int isfile, - void *userdata), - void *userdata) { - choose_visible_recurse(NULL, callback, userdata); -} - -static int choose_selectall_sensitive_callback - (GtkTreeIter attribute((unused)) *it, - int isfile, - void *userdata) { - if(isfile) { - *(int *)userdata = 1; - return 1; - } - return 0; -} - -/** @brief Should 'select all' be sensitive? - * - * Yes if there are visible files. - */ +/** @brief Should edit->select all be sensitive? No, for the choose tab. */ static int choose_selectall_sensitive(void attribute((unused)) *extra) { - int files = 0; - choose_visible_visit(choose_selectall_sensitive_callback, &files); - return files > 0; -} - -static int choose_selectall_activate_callback - (GtkTreeIter *it, - int isfile, - void attribute((unused)) *userdata) { - if(isfile) - gtk_tree_selection_select_iter(choose_selection, it); - else - gtk_tree_selection_unselect_iter(choose_selection, it); - return 0; + return FALSE; } -/** @brief Activate select all - * - * Selects all files and deselects everything else. - */ +/** @brief Activate edit->select all (which should do nothing) */ static void choose_selectall_activate(GtkMenuItem attribute((unused)) *item, gpointer attribute((unused)) userdata) { - choose_visible_visit(choose_selectall_activate_callback, 0); } /** @brief Should 'select none' be sensitive @@ -169,6 +134,16 @@ static void choose_gather_selected_files_callback(GtkTreeModel attribute((unused vector_append(v, choose_get_track(iter)); } +static void choose_gather_selected_dirs_callback(GtkTreeModel attribute((unused)) *model, + GtkTreePath attribute((unused)) *path, + GtkTreeIter *iter, + gpointer data) { + struct vector *v = data; + + if(choose_is_dir(iter)) + vector_append(v, choose_get_track(iter)); +} + static void choose_play_activate(GtkMenuItem attribute((unused)) *item, gpointer attribute((unused)) userdata) { @@ -195,6 +170,92 @@ static void choose_properties_activate(GtkMenuItem attribute((unused)) *item, properties(v->nvec, (const char **)v->vec); } +/** @brief Set sensitivity for select children + * + * Sensitive if we've selected exactly one directory. + */ +static int choose_selectchildren_sensitive(void attribute((unused)) *extra) { + struct vector v[1]; + /* Only one thing should be selected */ + if(gtk_tree_selection_count_selected_rows(choose_selection) != 1) + return FALSE; + /* The selected thing should be a directory */ + vector_init(v); + gtk_tree_selection_selected_foreach(choose_selection, + choose_gather_selected_dirs_callback, + v); + return v->nvec == 1; +} + +/** @brief Actually select the children of path + * + * We deselect everything else, too. + */ +static void choose_select_children(GtkTreePath *path) { + GtkTreeIter iter[1], child[1]; + + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(choose_store), iter, path)) { + gtk_tree_selection_unselect_all(choose_selection); + for(int n = 0; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(choose_store), child, + iter, n); + ++n) { + if(choose_is_file(child)) + gtk_tree_selection_select_iter(choose_selection, child); + } + } +} + +/** @brief Called to expand the children of path/iter */ +static void choose_selectchildren_callback(GtkTreeModel attribute((unused)) *model, + GtkTreePath *path, + GtkTreeIter attribute((unused)) *iter, + gpointer attribute((unused)) data) { + if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(choose_view), path)) { + /* Directory is already expanded */ + choose_select_children(path); + } else { + /* Directory is not expanded, so expand it */ + gtk_tree_view_expand_row(GTK_TREE_VIEW(choose_view), path, FALSE/*!expand_all*/); + /* Select its children when it's done */ + if(choose_eventually_select_children) + gtk_tree_path_free(choose_eventually_select_children); + choose_eventually_select_children = gtk_tree_path_copy(path); + } +} + +/** @brief Called when all pending track fetches are finished + * + * If there's a pending select-children operation, it can now be actioned + * (or might have gone stale). + */ +void choose_menu_moretracks(const char attribute((unused)) *event, + void attribute((unused)) *eventdata, + void attribute((unused)) *callbackdata) { + if(choose_eventually_select_children) { + choose_select_children(choose_eventually_select_children); + gtk_tree_path_free(choose_eventually_select_children); + choose_eventually_select_children = 0; + } +} + +/** @brief Select all children + * + * Easy enough if the directory is already expanded, we can just select its + * children. However if it is not then we must expand it and _when this has + * completed_ select its children. + * + * The way this is implented could cope with multiple directories but + * choose_selectchildren_sensitive() should stop this. + */ +static void choose_selectchildren_activate + (GtkMenuItem attribute((unused)) *item, + gpointer attribute((unused)) userdata) { + gtk_tree_selection_selected_foreach(choose_selection, + choose_selectchildren_callback, + 0); +} + /** @brief Pop-up menu for choose */ static struct menuitem choose_menuitems[] = { { @@ -212,9 +273,9 @@ static struct menuitem choose_menuitems[] = { 0 }, { - "Select all tracks", - choose_selectall_activate, - choose_selectall_sensitive, + "Select children", + choose_selectchildren_activate, + choose_selectchildren_sensitive, 0, 0 }, diff --git a/disobedience/choose.c b/disobedience/choose.c index d1e9515..b9a9e7e 100644 --- a/disobedience/choose.c +++ b/disobedience/choose.c @@ -619,6 +619,7 @@ GtkWidget *choose_widget(void) { 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); + event_register("choose-more-tracks", choose_menu_moretracks, 0); /* After a rescan we update the choose tree. We get a rescan-complete * automatically at startup and upon connection too. */ diff --git a/disobedience/choose.h b/disobedience/choose.h index 97f7095..5213332 100644 --- a/disobedience/choose.h +++ b/disobedience/choose.h @@ -79,6 +79,9 @@ void choose_next_clicked(GtkButton *button, void choose_prev_clicked(GtkButton *button, gpointer userdata); void choose_search_new(void); +void choose_menu_moretracks(const char *event, + void *eventdata, + void *callbackdata); #endif /* CHOOSE_H */ diff --git a/doc/disobedience.1.in b/doc/disobedience.1.in index 3e3d386..b174824 100644 --- a/doc/disobedience.1.in +++ b/doc/disobedience.1.in @@ -38,8 +38,11 @@ Terminates the program. .SS "Edit Menu" This has the following options: .TP -.B "Select All" -Select all tracks in whichever of the Queue or Recent tabs are showing. +.B "Select All Tracks" +Select all tracks. +.TP +.B "Deselect All Tracks" +Deselect all tracks. .TP .B Properties Edit the details of the selected tracks. @@ -134,9 +137,12 @@ See .B "Properties Window" below. .TP -.B "Select All" +.B "Select All Tracks" Select all tracks. .TP +.B "Deselect All Tracks" +Deselect all tracks. +.TP .B Scratch Interrupt the currently playing track. (Note that this appears even if you right click over a queued track rather @@ -157,8 +163,14 @@ See .B "Properties Window" below. .TP -.B "Select All" +.B "Play track" +Play the select track(s); +.TP +.B "Select All Tracks" Select all tracks. +.TP +.B "Deselect All Tracks" +Deselect all tracks. .SS "Choose Tab" This displays all the tracks known to the server in a tree structure. .PP @@ -204,11 +216,11 @@ Play all the tracks in the directory, in the order they appear on screen. .B "Track properties" Edit properties of all tracks in the directory. .TP -.B "Select all tracks" +.B "Select children" Select all the tracks in the directory (and deselect everything else). -.PP -Note that these options do not apply recursively - only the tracks in the -relevant directory are affected, not those in its subdirectories. +.TP +.B "Deselect all tracks" +Deselect everything. .SS "Added Tab" This displays a list of tracks recently added to the server's database. The most recently added track is at the top. @@ -229,6 +241,9 @@ Play selected tracks. .TP .B "Select All Tracks" Select all tracks. +.TP +.B "Deselect All Tracks" +Deselect all tracks. .SS "Login Details Window" The login details window allows you to edit the connection details and authorization information used by Disobedience. -- [mdw]