Skip to main content

cursive_tree/backend/
backend.rs

1use super::super::{model::*, view::*};
2
3use cursive::*;
4
5/// Default leaf symbol.
6const DEFAULT_LEAF_SYMBOL: &str = "⦁";
7
8/// Default branch expanded symbol.
9const DEFAULT_BRANCH_EXPANDED_SYMBOL: &str = "▾";
10
11/// Default branch collapsed symbol.
12const DEFAULT_BRANCH_COLLAPSED_SYMBOL: &str = "▸";
13
14//
15// TreeBackend
16//
17
18/// Tree view backend.
19///
20/// A `ContextT` is provided to some of the trait functions. It is intended to be used to access
21/// node data. For example, it can be a database connection or a work directory. The context is
22/// stored in the model and a clone of it will be produced for every call. Thus, cloning should be
23/// cheap. Consider wrapping it in an [Arc](std::sync::Arc). If you don't need it, it can be set to
24/// `()`.
25///
26/// `ErrorT` is returned as the [Err] for some of the trait functions. You can implement
27/// [handle_error](TreeBackend::handle_error) to display an error message to the user, log it, etc.
28/// If you don't need special error handling, it can be set to `()`.
29///
30/// Each node has an `IdT` field. It can be used by the backend to identify the node in order to
31/// retrieve its data, e.g. in [populate](TreeBackend::populate)] and [data](TreeBackend::data)].
32/// It is not otherwise used by the model and does *not* have to be unique. If you don't need it,
33/// it can be set to `()`.
34///
35/// Finally, each node has an optional `DataT` field for custom data. If you don't need it, it can
36/// be set to `()`.
37///
38/// Also see [SimpleTreeBackend](super::SimpleTreeBackend).
39pub trait TreeBackend<ContextT, ErrorT, IdT, DataT>: Sized {
40    /// Create a tree view with this backend.
41    fn tree_view(context: ContextT) -> TreeView<Self, ContextT, ErrorT, IdT, DataT> {
42        Self::tree_model(context).into()
43    }
44
45    /// Create a tree model with this backend.
46    fn tree_model(context: ContextT) -> TreeModel<Self, ContextT, ErrorT, IdT, DataT> {
47        TreeModel::new(context)
48    }
49
50    /// Get a node's symbol.
51    ///
52    /// Note that its char count *must be 1*.
53    ///
54    /// The default implementation uses the node kind and branch state.
55    #[allow(unused)]
56    fn symbol(node: &Node<Self, ContextT, ErrorT, IdT, DataT>, context: ContextT) -> Symbol<'_> {
57        Symbol::String(match (node.kind, node.branch_state) {
58            (NodeKind::Leaf, _) => DEFAULT_LEAF_SYMBOL,
59            (NodeKind::Branch, BranchState::Expanded) => DEFAULT_BRANCH_EXPANDED_SYMBOL,
60            (NodeKind::Branch, BranchState::Collapsed) => DEFAULT_BRANCH_COLLAPSED_SYMBOL,
61        })
62    }
63
64    /// Get the root nodes.
65    ///
66    /// The root nodes must be depth 0 but otherwise can be as pre-populated as you wish. For
67    /// example, you can provide them with children and optional data.
68    ///
69    /// The default implementation returns an empty list.
70    #[allow(unused)]
71    fn roots(context: ContextT) -> Result<NodeList<Self, ContextT, ErrorT, IdT, DataT>, ErrorT> {
72        Ok(Default::default())
73    }
74
75    /// Populate a node's children.
76    ///
77    /// The children *must* have a depth of +1 of the node.
78    ///
79    /// This is called when expanding the node *only* if it's children field is [None]. Setting
80    /// children to [Some], even to an empty list, will ensure that this function won't be called
81    /// again for the node until it is set to [None].
82    ///
83    /// The default implementation does nothing.
84    #[allow(unused)]
85    fn populate(node: &mut Node<Self, ContextT, ErrorT, IdT, DataT>, context: ContextT) -> Result<(), ErrorT> {
86        Ok(())
87    }
88
89    /// Get a node's data.
90    ///
91    /// This is called when data is accessed *only* if the field is [None]. Returning (data, true)
92    /// will store it in the field as [Some]. Returning (data, false) will cause this function to
93    /// be called every time data is accessed.
94    ///
95    /// The default implementation returns [None].
96    #[allow(unused)]
97    fn data(
98        node: &mut Node<Self, ContextT, ErrorT, IdT, DataT>,
99        context: ContextT,
100    ) -> Result<Option<(DataT, bool)>, ErrorT> {
101        Ok(None)
102    }
103
104    /// Called when the selected node changes, including when the selection is set to [None].
105    ///
106    /// Accessing the currently selected node must be done via the tree view, e.g.
107    /// [TreeView::selected_node](super::super::view::TreeView::selected_node). Thus, you may
108    /// want to wrap the tree view in a [NamedView](cursive::views::NamedView). You can then
109    /// access it here like so:
110    ///
111    /// ```rust
112    /// match cursive.call_on_name("MyTree", |tree: &mut TreeView<MyBackend, MyContext, MyError, MyId, MyData>| {
113    ///     Ok(match tree.selected_node_mut() {
114    ///         Some(node) => node.data(context)?.map(|data| data.something.clone()),
115    ///         None => None,
116    ///     })
117    /// }) {
118    ///     Some(Ok(Some(something))) => do_something_with(something),
119    ///     Some(Err(error)) => BackendT::handle_error(cursive, error),
120    ///     _ => {},
121    /// }
122    /// ```
123    #[allow(unused)]
124    fn handle_selection_changed(cursive: &mut Cursive) {}
125
126    /// Called when other backend functions return [Err].
127    #[allow(unused)]
128    fn handle_error(cursive: &mut Cursive, error: ErrorT) {}
129}