From bd802f2221c88f0980ceb0d40d99900b4d8b1cc2 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sat, 14 Jun 2008 15:47:10 +0100 Subject: [PATCH] Auto-collapse rows that were only expanded to display search results. If you manually collapse such a row (even if you then expand it before changing the search terms) neither it nor any of its ancestors will be auto-collapsed. See code comments for further discussion. Organization: Straylight/Edgeware From: Richard Kettlewell --- disobedience/choose-search.c | 16 +++++--- disobedience/choose.c | 78 +++++++++++++++++++++++++++++++++++- disobedience/choose.h | 4 ++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/disobedience/choose-search.c b/disobedience/choose-search.c index 96003e3..82a0675 100644 --- a/disobedience/choose-search.c +++ b/disobedience/choose-search.c @@ -22,11 +22,12 @@ * * TODO: * - cleverer focus to implement typeahead find - * - don't steal ^A */ #include "disobedience.h" #include "choose.h" +int choose_auto_expanding; + static GtkWidget *choose_search_entry; static GtkWidget *choose_next; static GtkWidget *choose_prev; @@ -147,14 +148,16 @@ static int choose_make_one_visible(const char *track) { } else { //fprintf(stderr, " requesting expansion of %s\n", dir); /* Track is below a non-expanded directory. So let's expand it. - * choose_make_visible() will arrange a revisit in due course. */ + * choose_make_visible() will arrange a revisit in due course. + * + * We mark the row as auto-expanded. + */ + ++choose_auto_expanding; gtk_tree_view_expand_row(GTK_TREE_VIEW(choose_view), path, FALSE/*open_all*/); gtk_tree_path_free(path); - /* TODO: the old version would remember which rows had been expanded - * just to show search results and collapse them again. We should - * probably do that. */ + --choose_auto_expanding; return 0; } } else @@ -279,6 +282,9 @@ static void choose_search_completed(void attribute((unused)) *v, return; } //fprintf(stderr, "*** %d search results\n", nvec); + /* We're actually going to use these search results. Autocollapse anything + * left over from the old search. */ + choose_auto_collapse(); choose_search_hash = hash_new(1); if(nvec) { for(int n = 0; n < nvec; ++n) diff --git a/disobedience/choose.c b/disobedience/choose.c index 44096d5..8243645 100644 --- a/disobedience/choose.c +++ b/disobedience/choose.c @@ -52,6 +52,9 @@ GtkTreeSelection *choose_selection; /** @brief Count of file listing operations in flight */ static int choose_list_in_flight; +/** @brief If nonzero autocollapse column won't be set */ +static int choose_suppress_set_autocollapse; + static char *choose_get_string(GtkTreeIter *iter, int column) { gchar *gs; gtk_tree_model_get(GTK_TREE_MODEL(choose_store), iter, @@ -97,6 +100,14 @@ int choose_is_placeholder(GtkTreeIter *iter) { return choose_get_string(iter, TRACK_COLUMN)[0] == 0; } +int choose_can_autocollapse(GtkTreeIter *iter) { + gboolean autocollapse; + gtk_tree_model_get(GTK_TREE_MODEL(choose_store), iter, + AUTOCOLLAPSE_COLUMN, &autocollapse, + -1); + return autocollapse; +} + /** @brief Remove node @p it and all its children * @param Iterator, updated to point to next * @return True if iterator remains valid @@ -261,6 +272,7 @@ static void choose_populate(GtkTreeRowReference *parent_ref, ISFILE_COLUMN, isfile, TRACK_COLUMN, td->track, SORT_COLUMN, td->sort, + AUTOCOLLAPSE_COLUMN, FALSE, -1); /* Update length and state; we expect this to kick off length lookups * rather than necessarily get the right value the first time round. */ @@ -302,8 +314,11 @@ static void choose_populate(GtkTreeRowReference *parent_ref, inserted, deleted_placeholder);*/ if(parent_ref) { /* If we deleted a placeholder then we must re-expand the row */ - if(deleted_placeholder) + if(deleted_placeholder) { + ++choose_suppress_set_autocollapse; gtk_tree_view_expand_row(GTK_TREE_VIEW(choose_view), parent_path, FALSE); + --choose_suppress_set_autocollapse; + } gtk_tree_row_reference_free(parent_ref); gtk_tree_path_free(parent_path); } @@ -390,6 +405,64 @@ static void choose_row_expanded(GtkTreeView attribute((unused)) *treeview, /* The row references are destroyed in the _completed handlers. */ choose_list_in_flight += 2; //fprintf(stderr, "choose_list_in_flight -> %d+\n", choose_list_in_flight); + if(!choose_suppress_set_autocollapse) { + if(choose_auto_expanding) { + /* This was an automatic expansion; mark it the row for auto-collapse. */ + gtk_tree_store_set(choose_store, iter, + AUTOCOLLAPSE_COLUMN, TRUE, + -1); + /*fprintf(stderr, "enable auto-collapse for %s\n", + gtk_tree_path_to_string(path));*/ + } else { + /* This was a manual expansion. Inhibit automatic collapse on this row + * and all its ancestors. */ + gboolean itv; + do { + gtk_tree_store_set(choose_store, iter, + AUTOCOLLAPSE_COLUMN, FALSE, + -1); + /*fprintf(stderr, "suppress auto-collapse for %s\n", + gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(choose_store), + iter));*/ + GtkTreeIter child = *iter; + itv = gtk_tree_model_iter_parent(GTK_TREE_MODEL(choose_store), + iter, + &child); + } while(itv); + /* The effect of this is that if you expand a row that's actually a + * sibling of the real target of the auto-expansion, it stays expanded + * when you clear a search. That's find and good, but it _still_ stays + * expanded if you expand it and then collapse it. + * + * An alternative policy would be to only auto-collapse rows that don't + * have any expanded children (apart from ones also subject to + * auto-collapse). I'm not sure what the most usable policy is. + */ + } + } +} + +static void choose_auto_collapse_callback(GtkTreeView *tree_view, + GtkTreePath *path, + gpointer attribute((unused)) user_data) { + GtkTreeIter it[1]; + + gtk_tree_model_get_iter(GTK_TREE_MODEL(choose_store), it, path); + if(choose_can_autocollapse(it)) { + /*fprintf(stderr, "collapse %s\n", + gtk_tree_path_to_string(path));*/ + gtk_tree_store_set(choose_store, it, + AUTOCOLLAPSE_COLUMN, FALSE, + -1); + gtk_tree_view_collapse_row(tree_view, path); + } +} + +/** @brief Perform automatic collapse after a search is cleared */ +void choose_auto_collapse(void) { + gtk_tree_view_map_expanded_rows(GTK_TREE_VIEW(choose_view), + choose_auto_collapse_callback, + 0); } /** @brief Create the choose tab */ @@ -403,7 +476,8 @@ GtkWidget *choose_widget(void) { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING); + G_TYPE_STRING, + G_TYPE_BOOLEAN); /* Create the view */ choose_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(choose_store)); diff --git a/disobedience/choose.h b/disobedience/choose.h index 51c8b81..cd82127 100644 --- a/disobedience/choose.h +++ b/disobedience/choose.h @@ -32,6 +32,7 @@ enum { SORT_COLUMN, /* Sort key */ BG_COLUMN, /* Background color */ FG_COLUMN, /* Foreground color */ + AUTOCOLLAPSE_COLUMN, /* TRUE if row should be auto-collapsed */ CHOOSE_COLUMNS /* column count */ }; @@ -52,6 +53,7 @@ extern GtkTreeStore *choose_store; extern GtkWidget *choose_view; extern GtkTreeSelection *choose_selection; extern const struct tabtype choose_tabtype; +extern int choose_auto_expanding; struct choosedata *choose_iter_to_data(GtkTreeIter *iter); struct choosedata *choose_path_to_data(GtkTreePath *path); @@ -66,8 +68,10 @@ char *choose_get_display(GtkTreeIter *iter); int choose_is_file(GtkTreeIter *iter); int choose_is_dir(GtkTreeIter *iter); int choose_is_placeholder(GtkTreeIter *iter); +int choose_can_autocollapse(GtkTreeIter *iter); GtkWidget *choose_search_widget(void); int choose_is_search_result(const char *track); +void choose_auto_collapse(void); #endif /* CHOOSE_H */ -- [mdw]