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