chiark / gitweb /
Replace rather bizarre 'select all' in choose tab with 'select
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 7 Dec 2008 20:20:51 +0000 (20:20 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 7 Dec 2008 20:20:51 +0000 (20:20 +0000)
children' which (after jumping through some hoops) selects just the
file children of the selected directory.

Updated the Disobedience documentation a bit.

CHANGES.html
disobedience/choose-menu.c
disobedience/choose.c
disobedience/choose.h
doc/disobedience.1.in

index 495d8984ae7d17f187bbeff03b4e09d6d6164645..e8436a4860419a6bd7767e0f1984a2618a085f27 100644 (file)
@@ -58,7 +58,7 @@ span.command {
 <p>This file documents recent user-visible changes to <a
  href="http://www.greenend.org.uk/rjk/disorder/">DisOrder</a>.</p>
 
 <p>This file documents recent user-visible changes to <a
  href="http://www.greenend.org.uk/rjk/disorder/">DisOrder</a>.</p>
 
-<h2>Changes up to version XXX</h2>
+<h2>Changes up to version 4.3</h2>
 
   <div class=section>
 
 
   <div class=section>
 
@@ -73,6 +73,10 @@ span.command {
         <p>Disobedience's icons have been changed to larger, more colorful
         ones.  The SVG source is included if you want to fiddle with them.</p>
 
         <p>Disobedience's icons have been changed to larger, more colorful
         ones.  The SVG source is included if you want to fiddle with them.</p>
 
+        <p>&ldquo;Select all&rdquo; is now no longer available in the choose
+        tab.  Instead there is a new &ldquo;Select children&rdquo; option which
+        selects the file children of a single subdirectory.</p>
+
       </div>
 
     <h3>Server</h3>
       </div>
 
     <h3>Server</h3>
index 37167e7810f602fc26e43e24702f9e547839faf3..16aa593da7f6a805241e7010181260650886ce37 100644 (file)
@@ -25,6 +25,9 @@
 /** @brief Popup menu */
 static GtkWidget *choose_menu;
 
 /** @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
 /** @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;
 }
 
   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) {
 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) {
 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
 }
 
 /** @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));
 }
 
     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) {
   
 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);
 }
 
   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[] = {
   {
 /** @brief Pop-up menu for choose */
 static struct menuitem choose_menuitems[] = {
   {
@@ -212,9 +273,9 @@ static struct menuitem choose_menuitems[] = {
     0
   },
   {
     0
   },
   {
-    "Select all tracks",
-    choose_selectall_activate,
-    choose_selectall_sensitive,
+    "Select children",
+    choose_selectchildren_activate,
+    choose_selectchildren_sensitive,
     0,
     0
   },
     0,
     0
   },
index d1e951571ff04c5888ea64d9c11151d766a9981f..b9a9e7e647b71698872505752034e6f12692e4c3 100644 (file)
@@ -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("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. */
 
   /* After a rescan we update the choose tree.  We get a rescan-complete
    * automatically at startup and upon connection too. */
index 97f70957663fc43e6a7f0f20d3effd3a9f9c45ae..521333211ec45ee328cfcd9c409bf84749cd68b1 100644 (file)
@@ -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_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 */
 
 
 #endif /* CHOOSE_H */
 
index 3e3d38608c992ffbb554560c414da0dff542a709..b17482498c85522a573639a9218ea2f4f503af45 100644 (file)
@@ -38,8 +38,11 @@ Terminates the program.
 .SS "Edit Menu"
 This has the following options:
 .TP
 .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.
 .TP
 .B Properties
 Edit the details of the selected tracks.
@@ -134,9 +137,12 @@ See
 .B "Properties Window"
 below.
 .TP
 .B "Properties Window"
 below.
 .TP
-.B "Select All"
+.B "Select All Tracks"
 Select all tracks.
 .TP
 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
 .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 "Properties Window"
 below.
 .TP
-.B "Select All"
+.B "Play track"
+Play the select track(s);
+.TP
+.B "Select All Tracks"
 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
 .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 "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).
 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.
 .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 "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.
 .SS "Login Details Window"
 The login details window allows you to edit the connection details and
 authorization information used by Disobedience.