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}