libsurfer/
displayed_item_tree.rs

1use itertools::Itertools;
2use serde::{Deserialize, Serialize};
3use std::ops::Range;
4
5use crate::displayed_item::DisplayedItemRef;
6use crate::MoveDir;
7
8#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
9pub struct Node {
10    pub item_ref: DisplayedItemRef,
11    /// Nesting level of the node.
12    pub level: u8,
13    /// Whether a subtree of this node (if it exists) is shown
14    pub unfolded: bool,
15    pub selected: bool,
16}
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19pub enum MoveError {
20    InvalidIndex,
21    InvalidLevel,
22    CircularMove,
23    LevelTooDeep,
24}
25
26/// N-th visible item, becomes invalid after any add/remove/move/fold/unfold operation
27#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
28pub struct VisibleItemIndex(pub usize);
29
30/// N-th item, may currently be invisible, becomes invalid after any add/remove/move operation
31#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize)]
32pub struct ItemIndex(pub usize);
33
34#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
35pub struct TargetPosition {
36    /// before which index to insert, may be in a range of 0..=tree.len() to allow for appending
37    pub before: ItemIndex,
38    /// at which level to insert, if None the level is derived from the item before
39    pub level: u8, // TODO go back to Option and implement
40}
41
42pub struct VisibleItemIterator<'a> {
43    items: &'a Vec<Node>,
44    next_idx: usize,
45}
46
47impl<'a> Iterator for VisibleItemIterator<'a> {
48    type Item = &'a Node;
49
50    fn next(&mut self) -> Option<Self::Item> {
51        let this_idx = self.next_idx;
52
53        let this_item = self.items.get(this_idx);
54        if this_item.is_some() {
55            self.next_idx = next_visible_item(self.items, this_idx);
56        };
57        this_item
58    }
59}
60
61#[must_use = "iterators are lazy and do nothing unless consumed"]
62pub struct VisibleItemIteratorMut<'a> {
63    items: &'a mut Vec<Node>,
64    /// Index of the next element to return, not guaranteed to be in-bounds
65    next_idx: usize,
66}
67
68impl<'a> Iterator for VisibleItemIteratorMut<'a> {
69    type Item = &'a mut Node;
70
71    fn next(&mut self) -> Option<Self::Item> {
72        let this_idx = self.next_idx;
73
74        if this_idx < self.items.len() {
75            self.next_idx = next_visible_item(self.items, this_idx);
76
77            let ptr = self.items.as_mut_ptr();
78            // access is safe since we
79            // - do access within bounds
80            // - know that we won't generate two equal references (next call, next item)
81            // - know that no second iterator or other access can happen while the references/iterator exist
82            Some(unsafe { &mut *ptr.add(this_idx) })
83        } else {
84            None
85        }
86    }
87}
88
89pub struct Info<'a> {
90    pub node: &'a Node,
91    pub idx: ItemIndex,
92    pub vidx: VisibleItemIndex,
93    pub has_children: bool,
94    pub last: bool,
95}
96
97pub struct VisibleItemIteratorExtraInfo<'a> {
98    items: &'a Vec<Node>,
99    /// Index of the next element to return, not guaranteed to be in-bounds
100    next_idx: usize,
101    next_vidx: usize,
102}
103
104impl<'a> Iterator for VisibleItemIteratorExtraInfo<'a> {
105    type Item = Info<'a>;
106
107    fn next(&mut self) -> Option<Self::Item> {
108        let this_idx = self.next_idx;
109        let this_vidx = self.next_vidx;
110        if this_idx < self.items.len() {
111            self.next_idx = next_visible_item(self.items, this_idx);
112            self.next_vidx += 1;
113
114            let this_level = self.items[this_idx].level;
115            let has_child = self
116                .items
117                .get(this_idx + 1)
118                .map(|item| item.level > this_level)
119                .unwrap_or(false);
120            Some(Info {
121                node: &self.items[this_idx],
122                idx: ItemIndex(this_idx),
123                vidx: VisibleItemIndex(this_vidx),
124                has_children: has_child,
125                last: self.next_idx >= self.items.len(),
126            })
127        } else {
128            None
129        }
130    }
131}
132
133/// Tree if items to be displayed
134///
135/// Items are stored in a flat list, with the level property indicating the nesting level
136/// of the item. The items are stored in-order.
137/// For documentation on the properties of a node, see the [Node] struct.
138///
139/// Note also infos on the [VisibleItemIndex] and [ItemIndex] types w.r.t. stability of these
140/// index types.
141///
142/// Invariants:
143/// - The nesting levels of the tree must monotonically increase (but may jump levels going down)
144#[derive(Default, Serialize, Deserialize, Debug, Clone)]
145pub struct DisplayedItemTree {
146    items: Vec<Node>,
147}
148
149impl DisplayedItemTree {
150    pub fn new() -> Self {
151        DisplayedItemTree { items: vec![] }
152    }
153
154    pub fn len(&self) -> usize {
155        self.items.len()
156    }
157
158    pub fn is_empty(&self) -> bool {
159        self.items.is_empty()
160    }
161
162    pub fn iter(&self) -> impl Iterator<Item = &Node> + use<'_> {
163        self.items.iter()
164    }
165
166    /// Iterate through all visible items
167    pub fn iter_visible(&self) -> VisibleItemIterator {
168        VisibleItemIterator {
169            items: &self.items,
170            next_idx: 0,
171        }
172    }
173
174    pub fn iter_visible_mut(&mut self) -> VisibleItemIteratorMut {
175        VisibleItemIteratorMut {
176            items: &mut self.items,
177            next_idx: 0,
178        }
179    }
180
181    pub fn iter_visible_extra(&self) -> VisibleItemIteratorExtraInfo {
182        VisibleItemIteratorExtraInfo {
183            items: &self.items,
184            next_idx: 0,
185            next_vidx: 0,
186        }
187    }
188
189    pub fn iter_visible_selected(&self) -> impl Iterator<Item = &Node> + use<'_> {
190        self.iter_visible().filter(|i| i.selected)
191    }
192
193    /// Iterate through items, skipping invisible items, return index of n-th visible item
194    pub fn get_visible(&self, index: VisibleItemIndex) -> Option<&Node> {
195        self.iter_visible().nth(index.0)
196    }
197
198    pub fn get_visible_extra(&self, index: VisibleItemIndex) -> Option<Info<'_>> {
199        self.iter_visible_extra().nth(index.0)
200    }
201
202    pub fn get(&self, index: ItemIndex) -> Option<&Node> {
203        self.items.get(index.0)
204    }
205
206    pub fn get_mut(&mut self, index: ItemIndex) -> Option<&mut Node> {
207        self.items.get_mut(index.0)
208    }
209
210    pub fn to_displayed(&self, index: VisibleItemIndex) -> Option<ItemIndex> {
211        self.get_visible_extra(index)?.idx.into()
212    }
213
214    /// insert item after offset visible items (either in root or in unfolded parent)
215    pub fn insert_item(
216        &mut self,
217        item: DisplayedItemRef,
218        position: TargetPosition,
219    ) -> Result<ItemIndex, MoveError> {
220        check_location(&self.items, position)?;
221
222        self.items.insert(
223            position.before.0,
224            Node {
225                item_ref: item,
226                level: position.level,
227                unfolded: true,
228                selected: false,
229            },
230        );
231
232        Ok(position.before)
233    }
234
235    /// Return the index past the end of the subtree started by `idx`
236    pub fn subtree_end(&self, start_idx: usize) -> usize {
237        let level = self.items[start_idx].level;
238        self.items
239            .iter()
240            .skip(start_idx + 1)
241            .enumerate()
242            .filter_map(|(idx, x)| (x.level <= level).then_some(idx + start_idx + 1))
243            .next()
244            .unwrap_or(self.items.len())
245    }
246
247    pub fn remove_recursive(&mut self, ItemIndex(item): ItemIndex) -> Vec<DisplayedItemRef> {
248        let end = self.subtree_end(item);
249        self.items
250            .drain(item..end)
251            .map(|x| x.item_ref)
252            .collect_vec()
253    }
254
255    pub fn remove_dissolve(&mut self, ItemIndex(item): ItemIndex) -> DisplayedItemRef {
256        let end = self.subtree_end(item);
257        self.items[item + 1..end]
258            .iter_mut()
259            .for_each(|x| x.level -= 1);
260        self.items.remove(item).item_ref
261    }
262
263    pub fn drain_recursive_if<F>(&mut self, f: F) -> Vec<DisplayedItemRef>
264    where
265        F: Fn(&Node) -> bool,
266    {
267        let mut removed = vec![];
268
269        let mut idx = 0;
270        while idx < self.items.len() {
271            if f(self.items.get(idx).unwrap()) {
272                let end = self.subtree_end(idx);
273                removed.extend(self.items.drain(idx..end).map(|x| x.item_ref));
274            } else {
275                idx += 1;
276            }
277        }
278
279        removed
280    }
281
282    /// Find the item before `idx` that is visible, independent of level
283    fn visible_predecessor(&self, mut idx: usize) -> Option<usize> {
284        if idx == 0 || idx > self.items.len() {
285            return None;
286        }
287
288        let start_level = self.items[idx].level;
289        let mut candidate = idx - 1;
290        let mut limit_level = self.items[candidate].level;
291
292        loop {
293            idx -= 1;
294            let looking_item = &self.items[idx];
295            // ignore subtrees deeper than what we found already
296            if looking_item.level < limit_level {
297                limit_level = looking_item.level;
298                // the whole subtree we have been looking at is not visible,
299                // assume for now the current node is
300                if !looking_item.unfolded {
301                    candidate = idx;
302                }
303            }
304            if self.items[idx].level <= start_level || idx == 0 {
305                return Some(candidate);
306            }
307        }
308    }
309
310    /// Move a visible item (and it's subtree) up/down by one visible item
311    ///
312    /// When moving up we move into all visible deeper trees first before skipping up.
313    /// Moving down we move out until we are on the level of the next element.
314    /// This way all indentations possible due to opened subtrees are reachable.
315    ///
316    /// Folded subtrees are skipped.
317    ///
318    /// `f` will be called with a node that might become the parent after move.
319    /// It must return true iff that node is allowed to have child nodes.
320    pub fn move_item<F>(
321        &mut self,
322        vidx: VisibleItemIndex,
323        direction: MoveDir,
324        f: F,
325    ) -> Result<VisibleItemIndex, MoveError>
326    where
327        F: Fn(&Node) -> bool,
328    {
329        let Some(ItemIndex(idx)) = self.to_displayed(vidx) else {
330            return Err(MoveError::InvalidIndex);
331        };
332
333        let this_level = self.items[idx].level;
334        let end = self.subtree_end(idx);
335        let new_index = match direction {
336            MoveDir::Down => match self.items.get(end) {
337                // we are at the end, but maybe still down in the hierarchy -> shift out
338                None => {
339                    shift_subtree_to_level(
340                        &mut self.items[idx..end],
341                        this_level.saturating_sub(1),
342                    )?;
343                    vidx
344                }
345                // the next node is less indented -> shift out, don't move yet
346                Some(Node { level, .. }) if *level < this_level => {
347                    shift_subtree_to_level(&mut self.items[idx..end], this_level - 1)?;
348                    vidx
349                }
350                // the next node must be a sibling, it's unfolded and can have children so move into it
351                Some(
352                    node @ Node {
353                        unfolded: true,
354                        level,
355                        ..
356                    },
357                ) if f(node) => {
358                    self.move_items(
359                        vec![ItemIndex(idx)],
360                        TargetPosition {
361                            before: ItemIndex(end + 1),
362                            level: *level + 1,
363                        },
364                    )?;
365                    VisibleItemIndex(vidx.0 + 1)
366                }
367                // remaining: the next node is either a folded sibling or can't have children, jump over
368                _ => {
369                    self.move_items(
370                        vec![ItemIndex(idx)],
371                        TargetPosition {
372                            before: ItemIndex(self.subtree_end(end)),
373                            level: this_level,
374                        },
375                    )?;
376                    VisibleItemIndex(vidx.0 + 1)
377                }
378            },
379            MoveDir::Up => {
380                match self.visible_predecessor(idx).map(|i| (i, &self.items[i])) {
381                    None => vidx,
382                    // empty, unfolded node deeper/equal in, possibly to move into
383                    // ... or node deeper in, but don't move into
384                    Some((_node_idx, node))
385                        if (node.level >= this_level && f(node) && node.unfolded)
386                            | (node.level > this_level) =>
387                    {
388                        shift_subtree_to_level(&mut self.items[idx..end], this_level + 1)?;
389                        vidx
390                    }
391                    Some((node_idx, node)) => {
392                        self.move_items(
393                            vec![ItemIndex(idx)],
394                            TargetPosition {
395                                before: ItemIndex(node_idx),
396                                level: node.level,
397                            },
398                        )?;
399                        VisibleItemIndex(vidx.0 - 1)
400                    }
401                }
402            }
403        };
404        Ok(new_index)
405    }
406
407    /// Move multiple items to a specified location
408    ///
409    /// Indices may be unsorted and contain duplicates, but must be valid.
410    /// Visibility is ignored for this function.
411    ///
412    /// Deals with any combination of items to move, except the error
413    /// cases below. Rules that are followed:
414    /// - The relative order of element should be the same, before and after the move
415    /// - If the root of a subtree is moved, the whole subtree is moved
416    /// - If a node inside a subtree is moved, then it's moved out of that subtree
417    /// - If both the root and a node of a subtree are moved, the node is moved out
418    ///   of the subtree and ends up after the root node
419    ///
420    /// Possible errors:
421    /// - trying to move an element into itself
422    /// - trying to move an element into another moved element
423    /// - invalid indices
424    /// - level too deep for subtree, level is clipped to level 255
425    pub fn move_items(
426        &mut self,
427        indices: Vec<ItemIndex>,
428        target: TargetPosition,
429    ) -> Result<(), MoveError> {
430        if let Some(idx) = indices.last() {
431            if idx.0 >= self.items.len() {
432                return Err(MoveError::InvalidIndex);
433            }
434        }
435
436        // sort from back to front
437        // that makes removal easier since we don't have to check whether we have to move some
438        // subtree out, and the indices don't have to be updated - but moving them to the temp
439        // vector needs some shuffling
440        let indices = indices
441            .into_iter()
442            .sorted_by_key(|ii| usize::MAX - ii.0)
443            .dedup()
444            .collect_vec();
445
446        let mut result = self.items.clone();
447        let mut extracted = vec![];
448
449        let mut shifted_target = target.before.0;
450        for ItemIndex(start) in indices {
451            let end = self.subtree_end(start);
452            if ((start + 1)..end).contains(&shifted_target) {
453                return Err(MoveError::CircularMove);
454            }
455
456            // if we remove elements before the target, adapt the index accordingly
457            if start < shifted_target {
458                shifted_target -= end - start;
459            }
460
461            shift_subtree_to_level(&mut result[start..end], target.level)?;
462            extracted.splice(0..0, result.drain(start..end));
463        }
464
465        check_location(
466            &result,
467            TargetPosition {
468                before: ItemIndex(shifted_target),
469                level: target.level,
470            },
471        )?;
472
473        result.splice(shifted_target..shifted_target, extracted);
474
475        assert_eq!(self.items.len(), result.len());
476        self.items = result;
477        Ok(())
478    }
479
480    /// Return the range of valid levels for inserting above `item`, given the visible nodes
481    ///
482    /// `f` will be called with what will become the in-order predecessor node
483    /// after insert. It must return true iff that node is allowed to have child nodes.
484    pub fn valid_levels_visible<F>(&self, item: VisibleItemIndex, f: F) -> Range<u8>
485    where
486        F: Fn(&Node) -> bool,
487    {
488        let Some(split) = item.0.checked_sub(1) else {
489            return 0..1;
490        };
491        match self
492            .iter_visible()
493            .skip(split)
494            .take(2)
495            .collect_vec()
496            .as_slice()
497        {
498            [] => 0..1, // only happens for indices > self.items.len()
499            [last] => {
500                0..last
501                    .level
502                    .saturating_add(1 + (f(last) && last.unfolded) as u8)
503            }
504            [pre, post, ..] => {
505                post.level..pre.level.saturating_add(1 + (f(pre) && pre.unfolded) as u8)
506            }
507        }
508    }
509
510    pub fn xfold(&mut self, ItemIndex(item): ItemIndex, unfolded: bool) {
511        self.items[item].unfolded = unfolded;
512        if !unfolded {
513            let end = self.subtree_end(item);
514            for x in &mut self.items[item..end] {
515                x.selected = false;
516            }
517        }
518    }
519
520    pub fn xfold_all(&mut self, unfolded: bool) {
521        for x in &mut self.items {
522            x.unfolded = unfolded;
523            if !unfolded && x.level > 0 {
524                x.selected = false;
525            }
526        }
527    }
528
529    pub fn xfold_recursive(&mut self, ItemIndex(item): ItemIndex, unfolded: bool) {
530        let end = self.subtree_end(item);
531        self.items[item].unfolded = unfolded;
532        for x in &mut self.items[item + 1..end] {
533            x.unfolded = unfolded;
534            if !unfolded {
535                x.selected = false;
536            }
537        }
538    }
539
540    pub fn xselect(&mut self, vidx: VisibleItemIndex, selected: bool) {
541        if let Some(idx) = self.to_displayed(vidx) {
542            self.items[idx.0].selected = selected;
543        }
544    }
545
546    /// Select/Deselect all visible items
547    pub fn xselect_all_visible(&mut self, selected: bool) {
548        for x in &mut self.iter_visible_mut() {
549            x.selected = selected;
550        }
551    }
552
553    /// Change selection for visible items, in inclusive range
554    pub fn xselect_visible_range(
555        &mut self,
556        VisibleItemIndex(from): VisibleItemIndex,
557        VisibleItemIndex(to): VisibleItemIndex,
558        selected: bool,
559    ) {
560        let (from, to) = if from < to {
561            (from, to + 1)
562        } else {
563            (to, from + 1)
564        };
565        for node in self.iter_visible_mut().skip(from).take(to - from) {
566            node.selected = selected
567        }
568    }
569
570    pub fn subtree_contains(
571        &self,
572        ItemIndex(root): ItemIndex,
573        ItemIndex(candidate): ItemIndex,
574    ) -> bool {
575        let end = self.subtree_end(candidate);
576        (root..end).contains(&candidate)
577    }
578}
579
580/// Find the index of the next visible item, or return items.len()
581///
582/// Precondition: `this_idx` must be a valid `items` index
583fn next_visible_item(items: &[Node], this_idx: usize) -> usize {
584    let this_level = items[this_idx].level;
585    let mut next_idx = this_idx + 1;
586    if !items[this_idx].unfolded {
587        while next_idx < items.len() && items[next_idx].level > this_level {
588            next_idx += 1;
589        }
590    }
591    next_idx
592}
593
594/// Check whether `target_position` is a valid location for insertion
595///
596/// This means we have to check if the requested indentation level is correct.
597fn check_location(items: &[Node], target_position: TargetPosition) -> Result<(), MoveError> {
598    if target_position.before.0 > items.len() {
599        return Err(MoveError::InvalidIndex);
600    }
601    let before = target_position
602        .before
603        .0
604        .checked_sub(1)
605        .and_then(|i| items.get(i));
606    let after = items.get(target_position.before.0);
607    let valid_range = match (before.map(|n| n.level), after.map(|n| n.level)) {
608        // If we want to be the first element, no indent possible
609        (None, _) => 0..=0,
610        // If we want to be the last element it's allowed to be completely unindent, indent into
611        // the last element, and everything in between
612        (Some(before), None) => 0..=before.saturating_add(1),
613        // if the latter element is indented further then the one before, we must indent
614        // otherwise we'd change the parent of the after subtree
615        (Some(before), Some(after)) if after > before => after..=after,
616        // if before and after are at the same level, we can insert on the same level,
617        // or we may indent one level
618        (Some(before), Some(after)) if after == before => before..=after.saturating_add(1),
619        // if before is the last element of a subtree and after is unindented
620        // then we can insert anywhere between the after element (not further out bec.
621        // that would change parents of the elements after), indent into the before element
622        // or anything in between
623        (Some(before), Some(after)) => after..=before.saturating_add(1),
624    };
625
626    if !valid_range.contains(&target_position.level) {
627        Err(MoveError::InvalidLevel)
628    } else {
629        Ok(())
630    }
631}
632
633fn shift_subtree_to_level(nodes: &mut [Node], target_level: u8) -> Result<(), MoveError> {
634    let Some(from_level) = nodes.first().map(|node| node.level) else {
635        return Ok(());
636    };
637    let level_corr = (target_level as i16) - (from_level as i16);
638    for elem in nodes.iter_mut() {
639        elem.level = (elem.level as i16 + level_corr)
640            .try_into()
641            .map_err(|_| MoveError::InvalidLevel)?;
642    }
643    Ok(())
644}
645
646#[cfg(test)]
647mod tests {
648    use super::*;
649    use itertools::Itertools;
650
651    fn build_tree(nodes: &[(usize, u8, bool, bool)]) -> DisplayedItemTree {
652        let mut tree = DisplayedItemTree::new();
653        for &(item, level, unfolded, selected) in nodes {
654            tree.items.push(Node {
655                item_ref: DisplayedItemRef(item),
656                level,
657                unfolded,
658                selected,
659            })
660        }
661        tree
662    }
663
664    /// common test tree
665    /// ```text
666    ///    0  1  2
667    /// 0: 0
668    /// 1: 1
669    /// 2: 2       < folded
670    /// 3:   20
671    /// 4:     200
672    /// 5: 3
673    /// 6:   30
674    /// 7:   31
675    /// 8: 4
676    /// 9: 5
677    /// ```
678    fn test_tree() -> DisplayedItemTree {
679        build_tree(&[
680            (0, 0, true, false),
681            (1, 0, false, false),
682            (2, 0, false, false),
683            (20, 1, true, false),
684            (200, 2, true, false),
685            (3, 0, true, false),
686            (30, 1, true, false),
687            (31, 1, true, false),
688            (4, 0, true, false),
689            (5, 0, true, false),
690        ])
691    }
692
693    #[test]
694    fn test_iter_visible() {
695        let tree = test_tree();
696        assert_eq!(
697            tree.iter_visible().map(|x| x.item_ref.0).collect_vec(),
698            vec![0, 1, 2, 3, 30, 31, 4, 5]
699        );
700    }
701
702    #[test]
703    fn test_iter_visible_extra() {
704        let tree = test_tree();
705        assert_eq!(
706            tree.iter_visible_extra()
707                .map(|info| (
708                    info.node.item_ref.0,
709                    info.idx.0,
710                    info.vidx.0,
711                    info.has_children,
712                    info.last
713                ))
714                .collect_vec(),
715            vec![
716                (0, 0, 0, false, false),
717                (1, 1, 1, false, false),
718                (2, 2, 2, true, false),
719                (3, 5, 3, true, false),
720                (30, 6, 4, false, false),
721                (31, 7, 5, false, false),
722                (4, 8, 6, false, false),
723                (5, 9, 7, false, true),
724            ]
725        )
726    }
727
728    #[test]
729    fn test_insert_item_before_first() {
730        let mut tree = test_tree();
731        tree.insert_item(
732            DisplayedItemRef(0xff),
733            TargetPosition {
734                before: ItemIndex(0),
735                level: 0,
736            },
737        )
738        .expect("insert_item must succeed");
739        assert_eq!(
740            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
741            vec![0xff, 0, 1, 2, 20, 200, 3, 30, 31, 4, 5]
742        );
743        assert_eq!(tree.items[0].level, 0);
744        assert_eq!(tree.items[0].selected, false);
745        assert_eq!(tree.items[0].unfolded, true);
746    }
747
748    #[test]
749    /// Test that inserting an element "after" the last element of a subtree
750    /// does insert into the subtree, after said element
751    fn test_insert_item_after_into_subtree() {
752        let mut tree = test_tree();
753        tree.insert_item(
754            DisplayedItemRef(0xff),
755            TargetPosition {
756                before: ItemIndex(8),
757                level: 1,
758            },
759        )
760        .expect("insert_item must succeed");
761        assert_eq!(
762            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
763            vec![0, 1, 2, 20, 200, 3, 30, 31, 0xff, 4, 5]
764        );
765        assert_eq!(tree.items[7].level, 1);
766        assert_eq!(tree.items[7].selected, false);
767        assert_eq!(tree.items[7].unfolded, true);
768    }
769
770    #[test]
771    fn test_insert_item_into() {
772        let mut tree = test_tree();
773        tree.insert_item(
774            DisplayedItemRef(0xff),
775            TargetPosition {
776                before: ItemIndex(7),
777                level: 2,
778            },
779        )
780        .expect("insert_item must succeed");
781        assert_eq!(
782            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
783            vec![0, 1, 2, 20, 200, 3, 30, 0xff, 31, 4, 5]
784        );
785        assert_eq!(tree.items[7].level, 2);
786        assert_eq!(tree.items[7].selected, false);
787        assert_eq!(tree.items[7].unfolded, true);
788    }
789
790    #[test]
791    fn test_insert_item_end() {
792        let mut tree = test_tree();
793        tree.insert_item(
794            DisplayedItemRef(0xff),
795            TargetPosition {
796                before: ItemIndex(10),
797                level: 0,
798            },
799        )
800        .expect("insert_item must succeed");
801        assert_eq!(
802            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
803            vec![0, 1, 2, 20, 200, 3, 30, 31, 4, 5, 0xff]
804        );
805        assert_eq!(tree.items[10].level, 0);
806    }
807
808    #[test]
809    fn test_remove_recursive_no_children() {
810        let mut tree = test_tree();
811        let removed = tree.remove_recursive(ItemIndex(0));
812        assert_eq!(removed, vec![DisplayedItemRef(0)]);
813        assert_eq!(
814            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
815            vec![1, 2, 20, 200, 3, 30, 31, 4, 5]
816        );
817    }
818
819    #[test]
820    fn test_remove_recursive_with_children() {
821        let mut tree = test_tree();
822        let removed = tree.remove_recursive(ItemIndex(2));
823        assert_eq!(
824            removed,
825            vec![
826                DisplayedItemRef(2),
827                DisplayedItemRef(20),
828                DisplayedItemRef(200)
829            ]
830        );
831        assert_eq!(
832            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
833            vec![0, 1, 3, 30, 31, 4, 5]
834        );
835    }
836
837    #[test]
838    fn test_remove_dissolve_with_children() {
839        let mut tree = test_tree();
840        let removed = tree.remove_dissolve(ItemIndex(5));
841        assert_eq!(removed, DisplayedItemRef(3));
842        assert_eq!(
843            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
844            vec![0, 1, 2, 20, 200, 30, 31, 4, 5]
845        );
846        assert_eq!(tree.items[5].level, 0);
847        assert_eq!(tree.items[6].level, 0);
848    }
849
850    #[test]
851    fn test_move_item_up_unfolded_group() {
852        let mut tree = build_tree(&[
853            (0, 0, true, false),
854            (1, 0, true, false),
855            (10, 1, true, false),
856            (2, 0, true, false),
857            (3, 0, true, false),
858        ]);
859        let new_idx = tree
860            .move_item(VisibleItemIndex(3), MoveDir::Up, |node| {
861                node.item_ref.0 == 1
862            })
863            .expect("move must succeed");
864        assert_eq!(new_idx.0, 3);
865        assert_eq!(tree.items[3].level, 1);
866        assert_eq!(
867            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
868            vec![0, 1, 10, 2, 3]
869        );
870
871        let new_idx = tree
872            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
873            .expect("move must succeed");
874        assert_eq!(new_idx.0, 2);
875        assert_eq!(tree.items[2].level, 1);
876        assert_eq!(
877            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
878            vec![0, 1, 2, 10, 3]
879        );
880
881        let new_idx = tree
882            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
883            .expect("move must succeed");
884        assert_eq!(new_idx.0, 1);
885        assert_eq!(tree.items[1].level, 0);
886        assert_eq!(
887            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
888            vec![0, 2, 1, 10, 3]
889        );
890
891        let new_idx = tree
892            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
893            .expect("move must succeed");
894        assert_eq!(new_idx.0, 0);
895        assert_eq!(tree.items[0].level, 0);
896        assert_eq!(
897            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
898            vec![2, 0, 1, 10, 3]
899        );
900
901        let new_idx = tree
902            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
903            .expect("move must succeed");
904        assert_eq!(new_idx.0, 0);
905        assert_eq!(tree.items[0].level, 0);
906        assert_eq!(
907            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
908            vec![2, 0, 1, 10, 3]
909        );
910    }
911
912    #[test]
913    fn test_move_item_up_folded_group() {
914        let mut tree = build_tree(&[
915            (0, 0, true, false),
916            (1, 0, false, false),
917            (10, 1, true, false),
918            (11, 1, true, false),
919            (2, 0, true, false),
920            (3, 0, true, false),
921        ]);
922        let new_idx = tree
923            .move_item(VisibleItemIndex(2), MoveDir::Up, |node| {
924                node.item_ref.0 == 1
925            })
926            .expect("move must succeed");
927        assert_eq!(new_idx.0, 1);
928        assert_eq!(tree.items[1].level, 0);
929        assert_eq!(
930            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
931            vec![0, 2, 1, 10, 11, 3]
932        );
933
934        let new_idx = tree
935            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
936            .expect("move must succeed");
937        assert_eq!(new_idx.0, 0);
938        assert_eq!(tree.items[0].level, 0);
939        assert_eq!(
940            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
941            vec![2, 0, 1, 10, 11, 3]
942        );
943    }
944
945    #[test]
946    fn test_move_item_down_unfolded_group() {
947        let mut tree = build_tree(&[
948            (0, 0, true, false),
949            (1, 0, true, false),
950            (2, 0, true, false),
951            (20, 1, true, false),
952            (3, 0, true, false),
953        ]);
954        let new_idx = tree
955            .move_item(VisibleItemIndex(1), MoveDir::Down, |node| {
956                node.item_ref.0 == 2
957            })
958            .expect("move must succeed");
959        println!("{:?}", tree.items);
960        assert_eq!(new_idx.0, 2);
961        assert_eq!(tree.items[3].level, 1);
962        assert_eq!(
963            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
964            vec![0, 2, 1, 20, 3]
965        );
966
967        let new_idx = tree
968            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
969            .expect("move must succeed");
970        println!("{:?}", tree.items);
971        assert_eq!(new_idx.0, 3);
972        assert_eq!(tree.items[3].level, 1);
973        assert_eq!(
974            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
975            vec![0, 2, 20, 1, 3]
976        );
977
978        let new_idx = tree
979            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
980            .expect("move must succeed");
981        println!("{:?}", tree.items);
982        assert_eq!(new_idx.0, 3);
983        assert_eq!(tree.items[3].level, 0);
984        assert_eq!(
985            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
986            vec![0, 2, 20, 1, 3]
987        );
988
989        let new_idx = tree
990            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
991            .expect("move must succeed");
992        println!("{:?}", tree.items);
993        assert_eq!(new_idx.0, 4);
994        assert_eq!(tree.items[3].level, 0);
995        assert_eq!(
996            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
997            vec![0, 2, 20, 3, 1]
998        );
999
1000        let new_idx = tree
1001            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
1002            .expect("move must succeed");
1003        println!("{:?}", tree.items);
1004        assert_eq!(new_idx.0, 4);
1005        assert_eq!(tree.items[3].level, 0);
1006        assert_eq!(
1007            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1008            vec![0, 2, 20, 3, 1]
1009        );
1010    }
1011
1012    #[test]
1013    fn test_move_item_down_folded_group() {
1014        let mut tree = build_tree(&[
1015            (0, 0, true, false),
1016            (1, 0, true, false),
1017            (2, 0, false, false),
1018            (20, 1, true, false),
1019            (3, 0, true, false),
1020        ]);
1021        let new_idx = tree
1022            .move_item(VisibleItemIndex(1), MoveDir::Down, |node| {
1023                node.item_ref.0 == 2
1024            })
1025            .expect("move must succeed");
1026        println!("{:?}", tree.items);
1027        assert_eq!(new_idx.0, 2);
1028        assert_eq!(tree.items[3].level, 0);
1029        assert_eq!(
1030            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1031            vec![0, 2, 20, 1, 3]
1032        );
1033
1034        let new_idx = tree
1035            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
1036            .expect("move must succeed");
1037        println!("{:?}", tree.items);
1038        assert_eq!(new_idx.0, 3);
1039        assert_eq!(tree.items[3].level, 0);
1040        assert_eq!(
1041            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1042            vec![0, 2, 20, 3, 1]
1043        );
1044    }
1045
1046    #[test]
1047    fn test_move_items_single_to_start() {
1048        let mut tree = test_tree();
1049        tree.move_items(
1050            vec![ItemIndex(8)],
1051            TargetPosition {
1052                before: ItemIndex(0),
1053                level: 0,
1054            },
1055        )
1056        .expect("move_items must succeed");
1057        assert_eq!(
1058            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1059            vec![4, 0, 1, 2, 20, 200, 3, 30, 31, 5]
1060        );
1061        assert_eq!(tree.items[0].level, 0);
1062    }
1063
1064    #[test]
1065    fn test_move_items_single_to_end() {
1066        let mut tree = test_tree();
1067        tree.move_items(
1068            vec![ItemIndex(4)],
1069            TargetPosition {
1070                before: ItemIndex(10),
1071                level: 0,
1072            },
1073        )
1074        .expect("move_items must succeed");
1075        assert_eq!(
1076            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1077            vec![0, 1, 2, 20, 3, 30, 31, 4, 5, 200]
1078        );
1079        assert_eq!(tree.items[9].level, 0);
1080    }
1081
1082    #[test]
1083    fn test_move_items_multiple_connected() {
1084        let mut tree = test_tree();
1085        tree.move_items(
1086            vec![ItemIndex(8), ItemIndex(9)],
1087            TargetPosition {
1088                before: ItemIndex(1),
1089                level: 0,
1090            },
1091        )
1092        .expect("move_items must succeed");
1093        assert_eq!(
1094            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1095            vec![0, 4, 5, 1, 2, 20, 200, 3, 30, 31]
1096        );
1097        assert_eq!(tree.items[1].level, 0);
1098        assert_eq!(tree.items[2].level, 0);
1099    }
1100
1101    #[test]
1102    fn test_move_items_multiple_different_levels() {
1103        let mut tree = test_tree();
1104        tree.move_items(
1105            vec![ItemIndex(7), ItemIndex(8)],
1106            TargetPosition {
1107                before: ItemIndex(1),
1108                level: 0,
1109            },
1110        )
1111        .expect("move_items must succeed");
1112        assert_eq!(
1113            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1114            vec![0, 31, 4, 1, 2, 20, 200, 3, 30, 5]
1115        );
1116        assert_eq!(tree.items[1].level, 0);
1117        assert_eq!(tree.items[2].level, 0);
1118    }
1119
1120    #[test]
1121    fn test_move_items_multiple_unconnected() {
1122        let mut tree = test_tree();
1123        tree.move_items(
1124            vec![ItemIndex(1), ItemIndex(8)],
1125            TargetPosition {
1126                before: ItemIndex(5),
1127                level: 1,
1128            },
1129        )
1130        .expect("move_items must succeed");
1131        assert_eq!(
1132            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1133            vec![0, 2, 20, 200, 1, 4, 3, 30, 31, 5]
1134        );
1135        assert_eq!(tree.items[4].level, 1);
1136        assert_eq!(tree.items[5].level, 1);
1137    }
1138
1139    #[test]
1140    fn test_move_items_multiple_into() {
1141        let mut tree = test_tree();
1142        tree.move_items(
1143            vec![ItemIndex(1), ItemIndex(8)],
1144            TargetPosition {
1145                before: ItemIndex(4),
1146                level: 2,
1147            },
1148        )
1149        .expect("move_items must succeed");
1150        assert_eq!(
1151            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1152            vec![0, 2, 20, 1, 4, 200, 3, 30, 31, 5]
1153        );
1154        assert_eq!(tree.items[4].level, 2);
1155        assert_eq!(tree.items[5].level, 2);
1156    }
1157
1158    #[test]
1159    fn test_move_single_to_end() {
1160        let mut tree = build_tree(&[
1161            (0, 0, false, false),
1162            (1, 0, false, false),
1163            (2, 0, false, false),
1164        ]);
1165        tree.move_items(
1166            vec![ItemIndex(1)],
1167            TargetPosition {
1168                before: ItemIndex(3),
1169                level: 0,
1170            },
1171        )
1172        .expect("move_items must succeed");
1173        assert_eq!(
1174            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1175            vec![0, 2, 1]
1176        )
1177    }
1178
1179    #[test]
1180    fn test_move_items_before_self_same_depth_single() {
1181        let ref_tree = build_tree(&[
1182            (0, 0, false, false),
1183            (1, 0, false, false),
1184            (2, 0, false, false),
1185        ]);
1186        let mut tree = ref_tree.clone();
1187        tree.move_items(
1188            vec![ItemIndex(1)],
1189            TargetPosition {
1190                before: ItemIndex(1),
1191                level: 0,
1192            },
1193        )
1194        .expect("move_items must succeed");
1195        assert_eq!(tree.items, ref_tree.items);
1196    }
1197
1198    #[test]
1199    fn test_move_items_after_self_same_depth_single() {
1200        let ref_tree = build_tree(&[
1201            (0, 0, false, false),
1202            (1, 0, false, false),
1203            (2, 0, false, false),
1204        ]);
1205        let mut tree = ref_tree.clone();
1206        tree.move_items(
1207            vec![ItemIndex(1)],
1208            TargetPosition {
1209                before: ItemIndex(2),
1210                level: 0,
1211            },
1212        )
1213        .expect("move_items must succeed");
1214        assert_eq!(tree.items, ref_tree.items);
1215    }
1216    #[test]
1217    fn test_move_items_in_between_selected_same_depth() {
1218        let ref_tree = build_tree(&[
1219            (0, 0, false, false),
1220            (1, 0, false, false),
1221            (2, 0, false, false),
1222            (3, 0, false, false),
1223            (4, 0, false, false),
1224        ]);
1225        let mut tree = ref_tree.clone();
1226        tree.move_items(
1227            vec![ItemIndex(1), ItemIndex(2)],
1228            TargetPosition {
1229                before: ItemIndex(2),
1230                level: 0,
1231            },
1232        )
1233        .expect("move_items must succeed");
1234        assert_eq!(tree.items, ref_tree.items);
1235    }
1236
1237    #[test]
1238    /// Moving "after" a node w/o children moves nodes to the same level,
1239    /// so it's fine and natural that the node itself can be included in the selection
1240    fn test_move_items_before_self_same_depth() {
1241        let mut tree = test_tree();
1242        tree.move_items(
1243            vec![ItemIndex(0), ItemIndex(4), ItemIndex(9)],
1244            TargetPosition {
1245                before: ItemIndex(4),
1246                level: 2,
1247            },
1248        )
1249        .expect("move_items must succeed");
1250        assert_eq!(
1251            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1252            vec![1, 2, 20, 0, 200, 5, 3, 30, 31, 4]
1253        );
1254        assert_eq!(tree.items[3].level, 2);
1255        assert_eq!(tree.items[4].level, 2);
1256        assert_eq!(tree.items[5].level, 2);
1257    }
1258
1259    #[test]
1260    /// Moving "after" a node w/o children moves nodes to the same level,
1261    /// so it's fine and natural that the node itself can be included in the selection
1262    fn test_move_items_before_self_shallower() {
1263        let mut tree = test_tree();
1264        tree.move_items(
1265            vec![ItemIndex(0), ItemIndex(4), ItemIndex(9)],
1266            TargetPosition {
1267                before: ItemIndex(4),
1268                level: 1,
1269            },
1270        )
1271        .expect("move_items must succeed");
1272        assert_eq!(
1273            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1274            vec![1, 2, 20, 0, 200, 5, 3, 30, 31, 4]
1275        );
1276        assert_eq!(tree.items[3].level, 1);
1277        assert_eq!(tree.items[4].level, 1);
1278        assert_eq!(tree.items[5].level, 1);
1279    }
1280
1281    #[test]
1282    fn test_move_items_empty_list() {
1283        let mut tree = test_tree();
1284        tree.move_items(
1285            vec![],
1286            TargetPosition {
1287                before: ItemIndex(5),
1288                level: 0,
1289            },
1290        )
1291        .expect("move_items must succeed");
1292        assert_eq!(
1293            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1294            vec![0, 1, 2, 20, 200, 3, 30, 31, 4, 5]
1295        );
1296        assert_eq!(tree.items, test_tree().items);
1297    }
1298
1299    #[test]
1300    fn test_move_items_shared_subtree_no_overlap() {
1301        let mut tree = build_tree(&[
1302            (0, 0, true, false),
1303            (10, 1, false, false),
1304            (11, 1, false, false),
1305            (12, 1, false, false),
1306            (13, 1, false, false),
1307        ]);
1308        tree.move_items(
1309            vec![ItemIndex(2), ItemIndex(4)],
1310            TargetPosition {
1311                before: ItemIndex(4),
1312                level: 2,
1313            },
1314        )
1315        .expect("move_items must succeed");
1316        assert_eq!(
1317            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1318            vec![0, 10, 12, 11, 13]
1319        );
1320    }
1321
1322    #[test]
1323    /// An element can't be the sub-element of itself, so we must catch that
1324    fn test_move_items_reject_into_self() {
1325        let mut tree = test_tree();
1326        let result = tree.move_items(
1327            vec![ItemIndex(2)],
1328            TargetPosition {
1329                before: ItemIndex(3),
1330                level: 1,
1331            },
1332        );
1333        assert_eq!(result, Err(MoveError::CircularMove));
1334        assert_eq!(tree.items, test_tree().items);
1335    }
1336
1337    #[test]
1338    /// An element can't be the sub-element of itself, even not as the
1339    /// last element
1340    fn test_move_items_reject_after_self_into_subtree() {
1341        let mut tree = test_tree();
1342        let result = tree.move_items(
1343            vec![ItemIndex(0), ItemIndex(3), ItemIndex(9)],
1344            TargetPosition {
1345                before: ItemIndex(4),
1346                level: 2,
1347            },
1348        );
1349        assert_eq!(result, Err(MoveError::CircularMove));
1350        assert_eq!(tree.items, test_tree().items);
1351    }
1352
1353    #[test]
1354    /// Test that the subtree check before moving is done correctly.
1355    /// The valid subtree element 100 also being moved prevents simpler
1356    /// checks (like checking only the first pre-index) from passing incorrectly.
1357    fn test_move_items_reject_into_subtree_distant() {
1358        let reference = build_tree(&[
1359            (1, 0, true, false),
1360            (10, 1, true, false),
1361            (100, 2, true, false),
1362            (11, 3, true, false),
1363        ]);
1364        let mut tree = reference.clone();
1365        let result = tree.move_items(
1366            vec![ItemIndex(1), ItemIndex(2)],
1367            TargetPosition {
1368                before: ItemIndex(4),
1369                level: 2,
1370            },
1371        );
1372        assert_eq!(result, Err(MoveError::CircularMove));
1373        assert_eq!(tree.items, reference.items);
1374    }
1375
1376    #[test]
1377    fn test_valid_levels() {
1378        let tree = build_tree(&[
1379            /* vidx */
1380            /* 0 */ (0, 0, true, false),
1381            /* 1 */ (1, 0, true, false),
1382            /* 2 */ (2, 0, false, false),
1383            /* - */ (20, 1, true, false),
1384            /* 3 */ (3, 0, true, false),
1385            /* 4 */ (30, 1, true, false),
1386            /* 5 */ (300, 2, true, false),
1387            /* 6 */ (4, 0, true, false),
1388            /* 7 */ (40, 1, true, false),
1389            /* 8 */ (400, 2, true, false),
1390            /* 9 */ (41, 1, true, false),
1391            /* 10 */ (410, 2, true, false),
1392        ]);
1393
1394        // To insert before the first element we can't indent,
1395        // regardless of what comes after
1396        assert_eq!(
1397            tree.valid_levels_visible(VisibleItemIndex(0), |_| false),
1398            0..1
1399        );
1400        assert_eq!(
1401            tree.valid_levels_visible(VisibleItemIndex(0), |_| true),
1402            0..1
1403        );
1404
1405        // if flat we don't allow indent, except if the app logic allows it
1406        assert_eq!(
1407            tree.valid_levels_visible(VisibleItemIndex(1), |_| false),
1408            0..1
1409        );
1410        assert_eq!(
1411            tree.valid_levels_visible(VisibleItemIndex(1), |_| true),
1412            0..2
1413        );
1414
1415        // invisible item must be ignored, do not move into (and not "loose" signal)
1416        assert_eq!(
1417            tree.valid_levels_visible(VisibleItemIndex(3), |_| false),
1418            0..1
1419        );
1420        assert_eq!(
1421            tree.valid_levels_visible(VisibleItemIndex(3), |_| true),
1422            0..1
1423        );
1424
1425        // if we are past a full "cliff" allow to insert all along to the root
1426        assert_eq!(
1427            tree.valid_levels_visible(VisibleItemIndex(6), |_| false),
1428            0..3
1429        );
1430        assert_eq!(
1431            tree.valid_levels_visible(VisibleItemIndex(6), |_| true),
1432            0..4
1433        );
1434
1435        // if the next item is indented then we don't allow to go to the root
1436        // otherwise the moved element would become the new root of some subtree
1437        assert_eq!(
1438            tree.valid_levels_visible(VisibleItemIndex(9), |_| false),
1439            1..3
1440        );
1441        assert_eq!(
1442            tree.valid_levels_visible(VisibleItemIndex(9), |_| true),
1443            1..4
1444        );
1445
1446        // past the end we can go back to the root
1447        assert_eq!(
1448            tree.valid_levels_visible(VisibleItemIndex(11), |_| false),
1449            0..3
1450        );
1451        assert_eq!(
1452            tree.valid_levels_visible(VisibleItemIndex(11), |_| true),
1453            0..4
1454        );
1455    }
1456}