hydrate_model/editor/
location_tree.rs

1use crate::{AssetId, AssetLocation, AssetPathCache, DataSet, EditorModel};
2use std::cmp::Ordering;
3use std::collections::BTreeMap;
4
5#[derive(Debug, PartialEq, Eq)]
6pub struct LocationTreeNodeKey {
7    name: String,
8    location: AssetLocation,
9}
10
11impl LocationTreeNodeKey {
12    pub fn name(&self) -> &str {
13        &self.name
14    }
15
16    pub fn location(&self) -> &AssetLocation {
17        &self.location
18    }
19}
20
21impl PartialOrd<Self> for LocationTreeNodeKey {
22    fn partial_cmp(
23        &self,
24        other: &Self,
25    ) -> Option<Ordering> {
26        Some(self.cmp(other))
27    }
28}
29
30impl Ord for LocationTreeNodeKey {
31    fn cmp(
32        &self,
33        other: &Self,
34    ) -> Ordering {
35        match self.name.cmp(&other.name) {
36            Ordering::Less => Ordering::Less,
37            Ordering::Equal => self.location.cmp(&other.location),
38            Ordering::Greater => Ordering::Greater,
39        }
40    }
41}
42
43#[derive(Debug)]
44pub struct LocationTreeNode {
45    //pub path: AssetPath,
46    pub location: AssetLocation,
47    pub location_root: AssetLocation,
48    pub children: BTreeMap<LocationTreeNodeKey, LocationTreeNode>,
49    pub has_changes: bool,
50}
51
52#[derive(Debug)]
53pub struct LocationTree {
54    pub root_nodes: BTreeMap<LocationTreeNodeKey, LocationTreeNode>,
55}
56
57impl Default for LocationTree {
58    fn default() -> Self {
59        LocationTree {
60            root_nodes: Default::default(),
61        }
62    }
63}
64
65impl LocationTree {
66    pub fn create_node(
67        &mut self,
68        data_set: &DataSet,
69        tree_node_id: AssetId,
70    ) {
71        let mut path_asset_stack = vec![AssetLocation::new(tree_node_id)];
72        path_asset_stack.append(
73            &mut data_set
74                .asset_location_chain(tree_node_id)
75                .unwrap_or_default(),
76        );
77
78        //
79        // Get the node key for the first element of the path. It should already exist because we create
80        // nodes for the data sources.
81        //
82        let root_location = path_asset_stack.last().cloned().unwrap(); //.unwrap_or(AssetLocation::new(tree_node_id));
83        let root_location_path_node_id = root_location.path_node_id();
84
85        let root_tree_node_key = LocationTreeNodeKey {
86            location: root_location.clone(),
87            name: data_set
88                .asset_name(root_location_path_node_id)
89                .unwrap()
90                .as_string()
91                .cloned()
92                .unwrap_or_default(),
93        };
94
95        path_asset_stack.pop();
96
97        if let Some(mut tree_node) = self.root_nodes.get_mut(&root_tree_node_key) {
98            while let Some(node_object) = path_asset_stack.pop() {
99                // Unnamed assets can't be paths
100                //let node_location = AssetLocation::new(node_asset);
101                //let location_chain = data_set.asset_location_chain(node_asset.path_node_id());
102
103                let node_name = data_set
104                    .asset_name(node_object.path_node_id())
105                    .unwrap()
106                    .as_string()
107                    .cloned()
108                    .unwrap(); //.unwrap_or_else(|| node_asset.as_uuid().to_string());
109
110                let node_key = LocationTreeNodeKey {
111                    name: node_name,
112                    location: node_object.clone(),
113                };
114
115                tree_node = tree_node.children.entry(node_key).or_insert_with(|| {
116                    //let path = paths.get(&node_asset).unwrap().clone();
117                    //let node_location = AssetLocation::new(source, location.parent_tree_node());
118                    //let location = AssetLocation::new(nod)
119                    let has_changes = false; //unsaved_paths.contains(&node_location);
120                    LocationTreeNode {
121                        //path,
122                        //source: node_location.source(),
123                        location: node_object,
124                        location_root: root_location.clone(),
125                        children: Default::default(),
126                        has_changes,
127                    }
128                });
129            }
130        } else {
131            //TODO: Handle this
132        }
133    }
134
135    pub fn build(
136        editor_model: &EditorModel,
137        asset_path_cache: &AssetPathCache,
138    ) -> Self {
139        let data_sources = editor_model.data_sources();
140        let root_data_set = editor_model.root_edit_context().data_set();
141
142        // Create root nodes for all the data sources
143        let mut root_nodes: BTreeMap<LocationTreeNodeKey, LocationTreeNode> = Default::default();
144        for (source_id, _) in data_sources {
145            let location = AssetLocation::new(AssetId::from_uuid(*source_id.uuid()));
146            let name = root_data_set.asset_name(location.path_node_id()).unwrap();
147            root_nodes.insert(
148                LocationTreeNodeKey {
149                    location: location.clone(),
150                    name: name.as_string().cloned().unwrap_or_default(),
151                },
152                LocationTreeNode {
153                    location,
154                    location_root: AssetLocation::null(),
155                    children: Default::default(),
156                    has_changes: false,
157                },
158            );
159        }
160
161        let mut tree = LocationTree { root_nodes };
162
163        // Iterate all known paths and ensure a node exists in the tree for each segment of each path
164        for (tree_node_id, _path) in asset_path_cache.path_to_id_lookup() {
165            // Skip the root component since it is our root node
166            tree.create_node(root_data_set, *tree_node_id);
167        }
168
169        tree
170    }
171}