Expand description
TreeRowFilter — sort + tree-aware filter over a TreeRow stream.
The composable sort/filter stage for the TreeDataSlice
pipeline. Where SortFilterTreeModel is a full
projection over an in-memory TreeModel (it owns its own expand state), an
external tree already has its expand/flatten projection — the
TreeDataSlice. Stacking a second projection on top would mean two expand
states. So for external trees, sort/filter belongs below the slice, as a
transform of its raw indent-ordered input:
rows::load() → TreeRowFilter::apply → TreeDataSlice::set_source → TreeView
\___ Vec<TreeRow> → Vec<TreeRow> ___/ \___ the one projection ___/It uses the same three TreeFilterMode strategies and sorts siblings per
parent, then re-emits a valid indent-ordered stream (surviving nodes’ depths
are compacted onto their nearest surviving ancestor, which TreeDataSlice
re-derives into a clean tree):
KeepAncestors— a node stays if it matches or any descendant matches (the outline-search behaviour; equivalent toSortFilterTreeModel).HideNonMatching— a node stays only if it and every ancestor match (children of a hidden parent stay hidden; equivalent toSortFilterTreeModel).KeepDescendants— a match keeps its whole subtree, surfaced even when the match’s own ancestors don’t match (the subtree compacts onto a root). This deliberately differs fromSortFilterTreeModel, whose flatten drops a match unless its full ancestor path is visible — which defeats the mode’s “keep the match and its subtree” intent.
§Revealing the matches
TreeRowFilter reshapes the rows; it does not touch the slice’s per-view
expand state. So KeepAncestors keeps the ancestor rows, but a
freshly-collapsed TreeDataSlice still hides the matches under them. While a
filter is active, flip the slice’s reveal override so the whole narrowed
result shows; turn it off when the filter clears (the user’s real collapse
state is preserved underneath):
let filtered = !query.is_empty();
slice.set_source(move || if filtered { sieve.apply(load()) } else { load() });
slice.reload();
slice.set_all_expanded(filtered); // reveal while searching, restore after§Example
use teksilo_data::{TreeRowFilter, TreeRow, TreeFilterMode};
let rows = vec![
TreeRow::new(1u64, "Book One", 0),
TreeRow::new(2, "Opening", 1),
TreeRow::new(3, "The Dawn Raid", 1),
TreeRow::new(4, "Notes", 0),
];
// Outline search: keep matches and the folders that lead to them.
let sieve = TreeRowFilter::new()
.filter_mode(TreeFilterMode::KeepAncestors)
.filter(|title: &&str| title.contains("Dawn"));
let out = sieve.apply(rows);
// "Book One" (ancestor of the match) + "The Dawn Raid".
assert_eq!(out.iter().map(|r| r.item).collect::<Vec<_>>(), vec!["Book One", "The Dawn Raid"]);Structs§
- Tree
RowFilter - A reusable sort + tree-aware filter over a
Vec<TreeRow<K, T>>. Build it once,applyit to each freshly-sourced row stream (e.g. inside aTreeDataSlice::set_sourceclosure). See the module docs.