rvlib/tools/
attributes.rs

1use tracing::info;
2
3use super::Manipulate;
4use crate::{
5    annotations_accessor_mut,
6    events::Events,
7    file_util::PathPair,
8    history::History,
9    make_tool_transform,
10    result::trace_ok_err,
11    tools_data::attributes_data::{set_attrmap_val, AttrMap, AttrVal},
12    tools_data_accessors,
13    world::World,
14    world_annotations_accessor,
15};
16use std::mem;
17const MISSING_DATA_MSG: &str = "Missing data for Attributes";
18pub const ACTOR_NAME: &str = "Attributes";
19annotations_accessor_mut!(ACTOR_NAME, attributes_mut, "Attribute didn't work", AttrMap);
20world_annotations_accessor!(ACTOR_NAME, attributes, "Attribute didn't work", AttrMap);
21tools_data_accessors!(
22    ACTOR_NAME,
23    MISSING_DATA_MSG,
24    attributes_data,
25    AttributesToolData,
26    attributes,
27    attributes_mut
28);
29
30fn propagate_annos(
31    mut annos: AttrMap,
32    attr_names: &[String],
33    to_propagate: &[(usize, AttrVal)],
34) -> AttrMap {
35    for (attr_idx, val) in to_propagate {
36        if let Some(attr_val) = annos.get_mut(&attr_names[*attr_idx]) {
37            *attr_val = val.clone();
38        }
39    }
40    annos
41}
42
43fn propagate_buffer(
44    mut attribute_buffer: Vec<String>,
45    to_propagate: &[(usize, AttrVal)],
46) -> Vec<String> {
47    for (attr_idx, val) in to_propagate {
48        attribute_buffer[*attr_idx] = val.to_string();
49    }
50    attribute_buffer
51}
52fn file_change(mut world: World) -> World {
53    let annos = get_annos_mut(&mut world).map(mem::take);
54    let data = get_specific_mut(&mut world);
55
56    if let (Some(data), Some(mut annos)) = (data, annos) {
57        for (attr_name, attr_val) in data.attr_names().iter().zip(data.attr_vals().iter()) {
58            if !annos.contains_key(attr_name) {
59                set_attrmap_val(&mut annos, attr_name, attr_val);
60            }
61        }
62
63        // put string representations of the attribute values into the buffer
64        let attr_buffers: Vec<String> = data
65            .attr_names()
66            .iter()
67            .map(|attr_name| annos.get(attr_name).unwrap().to_string())
68            .collect();
69        let attr_buffers = propagate_buffer(attr_buffers, &data.to_propagate_attr_val);
70        for (i, buffer) in attr_buffers.into_iter().enumerate() {
71            *data.attr_value_buffer_mut(i) = buffer;
72        }
73
74        annos = propagate_annos(annos, data.attr_names(), &data.to_propagate_attr_val);
75
76        if let Some(annos_) = get_annos_mut(&mut world) {
77            *annos_ = annos;
78        }
79    }
80    let current = get_annos(&world).cloned();
81    if let Some(data) = get_specific_mut(&mut world) {
82        data.current_attr_map = current;
83    }
84    world
85}
86#[derive(Clone, Copy, Debug)]
87pub struct Attributes;
88
89impl Manipulate for Attributes {
90    fn new() -> Self
91    where
92        Self: Sized,
93    {
94        Self
95    }
96
97    fn on_activate(&mut self, mut world: World) -> World {
98        let data = get_data_mut(&mut world);
99        if let Some(data) = trace_ok_err(data) {
100            data.menu_active = true;
101        }
102        file_change(world)
103    }
104    fn on_deactivate(&mut self, mut world: World) -> World {
105        let data = get_data_mut(&mut world);
106        if let Some(data) = trace_ok_err(data) {
107            data.menu_active = false;
108        }
109        world
110    }
111    fn on_filechange(&mut self, world: World, history: History) -> (World, History) {
112        (file_change(world), history)
113    }
114    fn events_tf(
115        &mut self,
116        mut world: World,
117        history: History,
118        _event: &Events,
119    ) -> (World, History) {
120        let is_addition_triggered = get_specific(&world).map(|d| d.options.is_addition_triggered);
121        if is_addition_triggered == Some(true) {
122            let attr_map_tmp = get_annos_mut(&mut world).map(mem::take);
123            let data = get_specific_mut(&mut world);
124
125            if let (Some(mut attr_map_tmp), Some(data)) = (attr_map_tmp, data) {
126                let new_attr_name = data.new_attr_name.clone();
127                if data.attr_names().contains(&new_attr_name) {
128                    tracing::error!(
129                        "New attribute {new_attr_name} could not be created, already exists"
130                    );
131                } else {
132                    let new_attr_val = data.new_attr_val.clone();
133                    for (_, (val_map, _)) in data.anno_iter_mut() {
134                        set_attrmap_val(val_map, &new_attr_name, &new_attr_val);
135                    }
136                    set_attrmap_val(&mut attr_map_tmp, &new_attr_name, &new_attr_val);
137                    if let Some(a) = get_annos_mut(&mut world) {
138                        a.clone_from(&attr_map_tmp);
139                    }
140                    if let Some(data) = get_specific_mut(&mut world) {
141                        data.current_attr_map = Some(attr_map_tmp);
142                        data.push(new_attr_name, new_attr_val);
143                    }
144                }
145            }
146            if let Some(is_add_triggered_out) =
147                get_specific_mut(&mut world).map(|d| &mut d.options.is_addition_triggered)
148            {
149                *is_add_triggered_out = false;
150            }
151        }
152        let attr_data = get_specific_mut(&mut world);
153        if let Some(attr_data) = attr_data {
154            if let Some(rename_src_idx) = attr_data.options.rename_src_idx {
155                let from_name = &attr_data.attr_names()[rename_src_idx].clone();
156                let to_name = &attr_data.new_attr_name.clone();
157                tracing::info!("Rename attribute {from_name} to {to_name}");
158                attr_data.rename(from_name, to_name);
159                attr_data.options.rename_src_idx = None;
160            }
161        }
162        let is_update_triggered = get_specific(&world).map(|d| d.options.is_update_triggered);
163        if is_update_triggered == Some(true) {
164            info!("update attr");
165            let current_from_menu_clone =
166                get_specific(&world).and_then(|d| d.current_attr_map.clone());
167            if let (Some(mut cfm), Some(anno)) =
168                (current_from_menu_clone, get_annos_mut(&mut world))
169            {
170                *anno = mem::take(&mut cfm);
171            }
172            if let Some(update_current_attr_map) =
173                get_specific_mut(&mut world).map(|d| &mut d.options.is_update_triggered)
174            {
175                *update_current_attr_map = false;
176            }
177        }
178        if let Some(removal_idx) = get_specific(&world).map(|d| d.options.removal_idx) {
179            let data = get_specific_mut(&mut world);
180            if let (Some(data), Some(removal_idx)) = (data, removal_idx) {
181                data.remove_attr(removal_idx);
182            }
183            if let Some(removal_idx) =
184                get_specific_mut(&mut world).map(|d| &mut d.options.removal_idx)
185            {
186                *removal_idx = None;
187            }
188        }
189        let is_export_triggered = get_specific(&world).map(|d| d.options.is_export_triggered);
190        if is_export_triggered == Some(true) {
191            let ssh_cfg = world.data.meta_data.ssh_cfg.clone();
192            let attr_data = get_specific(&world);
193            let export_only_opened_folder =
194                attr_data.map(|d| d.options.export_only_opened_folder) == Some(true);
195            let key_filter = if export_only_opened_folder {
196                world
197                    .data
198                    .meta_data
199                    .opened_folder
200                    .as_ref()
201                    .map(PathPair::path_relative)
202            } else {
203                None
204            };
205            let annos_str = get_specific(&world)
206                .and_then(|d| trace_ok_err(d.serialize_annotations(key_filter)));
207            if let (Some(annos_str), Some(data)) = (annos_str, get_specific(&world)) {
208                if trace_ok_err(data.export_path.conn.write(
209                    &annos_str,
210                    &data.export_path.path,
211                    ssh_cfg.as_ref(),
212                ))
213                .is_some()
214                {
215                    info!("exported annotations to {:?}", data.export_path.path);
216                }
217            }
218            if let Some(is_export_triggered) =
219                get_specific_mut(&mut world).map(|d| &mut d.options.is_export_triggered)
220            {
221                *is_export_triggered = false;
222            }
223        }
224        make_tool_transform!(self, world, history, event, [])
225    }
226}