Skip to main content

tree_table/api/
insert.rs

1use alloc::string::ToString;
2use alloc::{rc::Rc, string::String, vec, vec::Vec};
3use core::cell::RefCell;
4use hashbrown::HashSet;
5
6use crate::args::{InsertArgs, InsertRow};
7use crate::utils::consecutive_ranges::consecutive_ranges_owned;
8use crate::utils::utils_fns::binary_search_ins_pos;
9use crate::{CellProps, Change, EventData, IndexCell, NO_END, Table, Val, str_err};
10
11impl Table {
12    /// Insert multiple new rows into the table.
13    /// If using tree mode then they can only be inserted under a single
14    /// existing parent.
15    pub fn insert(
16        &mut self,
17        kwargs: Option<InsertArgs>,
18    ) -> Result<Option<Rc<RefCell<EventData>>>, String> {
19        let kwargs = kwargs.unwrap_or_default();
20        let rows = kwargs.rows.unwrap_or(vec![InsertRow {
21            iid: None,
22            val: None,
23            vals: None,
24            open: false,
25            dim: None,
26        }]);
27
28        if rows.is_empty() {
29            return Ok(None);
30        }
31        let empty_val: Val = self.opts.empty_val.clone();
32        let empty_index_val: Val = self.opts.empty_index_val.clone();
33        let tree_mode = self.opts.tree_mode;
34
35        let mut event_data: EventData = self.cr_new_event(false);
36        let mut new_iids: HashSet<Rc<str>> = HashSet::new();
37        let dim = self.cr_get_default_row_dim();
38        let ncols = Self::acr_total_cols(&self.grid.header.cells);
39        // If parent is None set to root level
40        let par = kwargs.par.unwrap_or_default();
41
42        let pos = match kwargs.pos {
43            Some(pos) => Some(pos as usize),
44            None => None,
45        };
46        // Determine data insert row number, Also checks if par exists
47        let start_rn = self.cr_tree_get_iid_insert_row(pos, &par)?;
48
49        // Determine which row to inherit cell props from
50        let opt_inherit_row = self.cr_get_inherit_row(
51            &self.grid.index.iid_to_row,
52            start_rn,
53            kwargs.inherit.as_str(),
54        )?;
55        let do_inherit = opt_inherit_row.is_some();
56        let inherit_row = opt_inherit_row.unwrap_or(0);
57
58        let chn_splice_pos: Option<usize> = if !par.is_empty() {
59            let chn =
60                Self::acr_tree_iid_chn(&self.grid.index.cells, &self.grid.index.iid_to_row, &par)?;
61            let pos = binary_search_ins_pos(&chn, &self.grid.index.iid_to_row, start_rn)?;
62            Some(pos)
63        } else {
64            None
65        };
66        // variable set up
67        // let splice_chn: bool = chn_splice_pos.is_some();
68        let mut chn_to_splice: Vec<Rc<str>> = Vec::with_capacity(rows.len());
69        let sorted_seq: Vec<usize> = (start_rn..start_rn + rows.len()).collect();
70
71        // push existing hashmap row numbers
72        self.grid.push_rows(&sorted_seq);
73        self.grid.index.add_rows_just_push_hm(&sorted_seq);
74
75        // get parent and determine new rows visibility
76        let (vis, par_rc) = match (|| -> Result<(bool, Rc<str>), String> {
77            if tree_mode {
78                if par.is_empty() {
79                    Ok((true, self.grid.index.empty_par.clone()))
80                } else {
81                    let par_row = Self::acr_pos(&self.grid.index.iid_to_row, par.as_str())?;
82                    let par_cell = Self::acr_icell(&self.grid.index.cells, par_row)?;
83                    Ok((par_cell.vis && par_cell.open, par_cell.iid.clone()))
84                }
85            } else {
86                Ok((true, self.grid.index.empty_par.clone()))
87            }
88        })() {
89            Ok(tup) => tup,
90            Err(e) => {
91                // ← rollback the forward adjustments we just made
92                self.grid.pull_rows(&sorted_seq);
93                self.grid.index.del_rows_just_pull_hm(&sorted_seq);
94                return Err(e);
95            }
96        };
97
98        let mut rn = start_rn;
99
100        // Assess and create rows, index
101        let build_result = (|| -> Result<(), String> {
102            for (i, row_spec) in rows.into_iter().enumerate() {
103                // Row number for new row
104                rn = start_rn + i;
105
106                // If iid is None generate a new one
107                let iid: Rc<str> = if let Some(iid) = row_spec.iid {
108                    // Check if the provided iid already exists
109                    if self.grid.index.iid_to_row.contains_key(iid.as_str()) {
110                        return Err(str_err!("iid already exists: {}", iid));
111                    }
112                    Rc::from(iid)
113                } else {
114                    Rc::from(self.grid.index.new_iid()?)
115                };
116                // Check for repetitions of iids
117                if !new_iids.insert(iid.clone()) {
118                    return Err(str_err!("Repeated iid in rows: {}", iid));
119                };
120
121                // Index
122                // If val is None use the iid
123                let val = if let Some(val) = row_spec.val {
124                    val
125                } else if tree_mode {
126                    Val::Str(iid.to_string())
127                } else {
128                    empty_index_val.clone()
129                };
130                let index_props: Option<CellProps> = if do_inherit {
131                    self.grid.index.clone_props(&inherit_row)
132                } else {
133                    None
134                };
135
136                // Table
137                let new_icell = IndexCell {
138                    iid: iid.clone(),
139                    val,
140                    vals: Self::build_row_cells(
141                        &self.grid.index.cells,
142                        &self.grid.header,
143                        row_spec.vals,
144                        inherit_row,
145                        do_inherit,
146                        &empty_val,
147                        ncols,
148                    )?,
149                    dim: row_spec.dim.unwrap_or(dim),
150                    vis,
151                    par: par_rc.clone(),
152                    chn: Vec::new(),
153                    open: row_spec.open,
154                    props: index_props,
155                };
156
157                // Not optional - also used if roll back occurs
158                chn_to_splice.push(iid.clone());
159
160                // Inserts to cells, inserts to iid_to_row hashmap
161                self.grid.index.add_row(rn, iid, new_icell);
162            }
163
164            // We don't need to record a tree change because undo -> del_rows() removes the spliced chn
165            if let Some(chn_splice_pos) = chn_splice_pos {
166                let chn = Self::acr_tree_iid_chn_mut(
167                    &mut self.grid.index.cells,
168                    &self.grid.index.iid_to_row,
169                    &par,
170                )?;
171                chn.splice(
172                    chn_splice_pos..chn_splice_pos,
173                    core::mem::take(&mut chn_to_splice),
174                );
175            }
176            Ok(())
177        })();
178
179        match build_result {
180            Ok(_) => {}
181            Err(e) => {
182                // Roll back any changes made
183                for iid in chn_to_splice.iter() {
184                    self.grid.index.iid_to_row.remove(iid);
185                }
186                let added_count = chn_to_splice.len();
187                if added_count > 0 {
188                    self.grid
189                        .index
190                        .cells
191                        .drain(start_rn..start_rn + added_count);
192                }
193                self.grid.pull_rows(&sorted_seq);
194                self.grid.index.del_rows_just_pull_hm(&sorted_seq);
195                return Err(e);
196            }
197        };
198
199        // Done before remaking disp rows
200        let num_visible_added = if vis { sorted_seq.len() } else { 0 };
201        let disp_insert_pos = Self::acr_compute_disp_insert_pos(&self.grid.disp_rows, start_rn);
202
203        // remake canvas relevant vars
204        Self::acr_remake_rows(
205            &mut self.grid.canvas_rows,
206            &mut self.grid.disp_rows,
207            &self.grid.index.cells,
208            self.opts.horizontal_grid_line_width.clone(),
209        );
210        self.acr_adjust_selections_after_row_insert(disp_insert_pos, num_visible_added);
211
212        // Select the added rows
213        if kwargs.select {
214            Self::acr_deselect_all(
215                &mut self.sel,
216                if kwargs.save_selection {
217                    Some(&mut event_data)
218                } else {
219                    None
220                },
221            );
222            for (start, end) in consecutive_ranges_owned(
223                sorted_seq
224                    .iter()
225                    .filter_map(|n| Self::acr_data_to_disp_opt(&self.grid.disp_rows, *n)),
226            ) {
227                Self::acr_add_selection_box(&mut self.sel, &self.grid, start, end, 0, NO_END, true);
228            }
229            if kwargs.save_selection {
230                event_data.changes.push(Change::add_selection_boxes(
231                    self.sel.selection_boxes.len(),
232                    None,
233                ));
234            }
235        }
236
237        // Add changes to event data and deal with undo
238        event_data.changes.push(Change::AddRows(sorted_seq));
239        self.cr_finalize_event(event_data, kwargs.undo, kwargs.emit)
240    }
241}