i_slint_core/
model.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore vecmodel
5
6//! Model and Repeater
7
8use crate::item_tree::ItemTreeVTable;
9use crate::item_tree::TraversalOrder;
10pub use crate::items::{StandardListViewItem, TableColumn};
11use crate::layout::Orientation;
12use crate::lengths::{LogicalLength, RectLengths};
13use crate::{Coord, Property, SharedString, SharedVector};
14pub use adapters::{FilterModel, MapModel, ReverseModel, SortModel};
15use alloc::boxed::Box;
16use alloc::rc::Rc;
17use alloc::vec::Vec;
18use core::cell::{Cell, RefCell};
19use core::pin::Pin;
20use euclid::num::Zero;
21#[allow(unused)]
22use euclid::num::{Ceil, Floor};
23pub use model_peer::*;
24use once_cell::unsync::OnceCell;
25use pin_project::pin_project;
26
27mod adapters;
28mod model_peer;
29
30type ItemTreeRc<C> = vtable::VRc<crate::item_tree::ItemTreeVTable, C>;
31
32/// This trait defines the interface that users of a model can use to track changes
33/// to a model. It is supplied via [`Model::model_tracker`] and implementation usually
34/// return a reference to its field of [`ModelNotify`].
35pub trait ModelTracker {
36    /// Attach one peer. The peer will be notified when the model changes
37    fn attach_peer(&self, peer: ModelPeer);
38    /// Register the model as a dependency to the current binding being evaluated, so
39    /// that it will be notified when the model changes its size.
40    fn track_row_count_changes(&self);
41    /// Register a row as a dependency to the current binding being evaluated, so that
42    /// it will be notified when the value of that row changes.
43    fn track_row_data_changes(&self, row: usize);
44}
45
46impl ModelTracker for () {
47    fn attach_peer(&self, _peer: ModelPeer) {}
48
49    fn track_row_count_changes(&self) {}
50    fn track_row_data_changes(&self, _row: usize) {}
51}
52
53/// A Model is providing Data for the repeated elements with `for` in the `.slint` language
54///
55/// If the model can be changed, the type implementing the Model trait should holds
56/// a [`ModelNotify`], and is responsible to call functions on it to let the UI know that
57/// something has changed.
58///
59/// Properties of type array will be mapped to a [`ModelRc<T>`], which wraps a `Rc<Model<Data = T>>.`
60/// The [`ModelRc`] documentation has examples on how to set models to array properties.
61///
62/// It is more efficient to operate on the model and send changes through the `ModelNotify` rather than
63/// resetting the property with a different model.
64///
65/// ## Example
66///
67/// As an example, let's see the implementation of [`VecModel`].
68///
69/// ```
70/// # use i_slint_core::model::{Model, ModelNotify, ModelPeer, ModelTracker};
71/// pub struct VecModel<T> {
72///     // the backing data, stored in a `RefCell` as this model can be modified
73///     array: std::cell::RefCell<Vec<T>>,
74///     // the ModelNotify will allow to notify the UI that the model changes
75///     notify: ModelNotify,
76/// }
77///
78/// impl<T: Clone + 'static> Model for VecModel<T> {
79///     type Data = T;
80///
81///     fn row_count(&self) -> usize {
82///         self.array.borrow().len()
83///     }
84///
85///     fn row_data(&self, row: usize) -> Option<Self::Data> {
86///         self.array.borrow().get(row).cloned()
87///     }
88///
89///     fn set_row_data(&self, row: usize, data: Self::Data) {
90///         self.array.borrow_mut()[row] = data;
91///         // don't forget to call row_changed
92///         self.notify.row_changed(row);
93///     }
94///
95///     fn model_tracker(&self) -> &dyn ModelTracker {
96///         &self.notify
97///     }
98///
99///     fn as_any(&self) -> &dyn core::any::Any {
100///         // a typical implementation just return `self`
101///         self
102///     }
103/// }
104///
105/// // when modifying the model, we call the corresponding function in
106/// // the ModelNotify
107/// impl<T> VecModel<T> {
108///     /// Add a row at the end of the model
109///     pub fn push(&self, value: T) {
110///         self.array.borrow_mut().push(value);
111///         self.notify.row_added(self.array.borrow().len() - 1, 1)
112///     }
113///
114///     /// Remove the row at the given index from the model
115///     pub fn remove(&self, index: usize) {
116///         self.array.borrow_mut().remove(index);
117///         self.notify.row_removed(index, 1)
118///     }
119/// }
120/// ```
121pub trait Model {
122    /// The model data: A model is a set of rows and each row has this data
123    type Data;
124    /// The number of rows in the model
125    fn row_count(&self) -> usize;
126    /// Returns the data for a particular row.
127    ///
128    /// This function should normally be called with `row < row_count()` and should return None otherwise.
129    ///
130    /// This function does not register dependencies on the current binding. For an equivalent
131    /// function that tracks dependencies, see [`ModelExt::row_data_tracked`]
132    fn row_data(&self, row: usize) -> Option<Self::Data>;
133    /// Sets the data for a particular row.
134    ///
135    /// This function should be called with `row < row_count()`, otherwise the implementation can panic.
136    ///
137    /// If the model cannot support data changes, then it is ok to do nothing.
138    /// The default implementation will print a warning to stderr.
139    ///
140    /// If the model can update the data, it should also call [`ModelNotify::row_changed`] on its
141    /// internal [`ModelNotify`].
142    fn set_row_data(&self, _row: usize, _data: Self::Data) {
143        #[cfg(feature = "std")]
144        eprintln!(
145            "Model::set_row_data called on a model of type {} which does not re-implement this method. \
146            This happens when trying to modify a read-only model",
147            core::any::type_name::<Self>(),
148        );
149    }
150
151    /// The implementation should return a reference to its [`ModelNotify`] field.
152    ///
153    /// You can return `&()` if you your `Model` is constant and does not have a ModelNotify field.
154    fn model_tracker(&self) -> &dyn ModelTracker;
155
156    /// Returns an iterator visiting all elements of the model.
157    fn iter(&self) -> ModelIterator<Self::Data>
158    where
159        Self: Sized,
160    {
161        ModelIterator::new(self)
162    }
163
164    /// Return something that can be downcast'ed (typically self)
165    ///
166    /// This is useful to get back to the actual model from a [`ModelRc`] stored
167    /// in a ItemTree.
168    ///
169    /// ```
170    /// # use i_slint_core::model::*;
171    /// # use std::rc::Rc;
172    /// let handle = ModelRc::new(VecModel::from(vec![1i32, 2, 3]));
173    /// // later:
174    /// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);
175    /// assert_eq!(handle.row_data(3).unwrap(), 4);
176    /// ```
177    ///
178    /// Note: the default implementation returns nothing interesting. this method should be
179    /// implemented by model implementation to return something useful. For example:
180    /// ```ignore
181    ///     fn as_any(&self) -> &dyn core::any::Any { self }
182    /// ```
183    fn as_any(&self) -> &dyn core::any::Any {
184        &()
185    }
186}
187
188/// Extension trait with extra methods implemented on types that implement [`Model`]
189pub trait ModelExt: Model {
190    /// Convenience function that calls [`ModelTracker::track_row_data_changes`]
191    /// before returning [`Model::row_data`].
192    ///
193    /// Calling [`row_data(row)`](Model::row_data) does not register the row as a dependency when calling it while
194    /// evaluating a property binding. This function calls [`track_row_data_changes(row)`](ModelTracker::track_row_data_changes)
195    /// on the [`self.model_tracker()`](Model::model_tracker) to enable tracking.
196    fn row_data_tracked(&self, row: usize) -> Option<Self::Data> {
197        self.model_tracker().track_row_data_changes(row);
198        self.row_data(row)
199    }
200
201    /// Returns a new Model where all elements are mapped by the function `map_function`.
202    /// This is a shortcut for [`MapModel::new()`].
203    fn map<F, U>(self, map_function: F) -> MapModel<Self, F>
204    where
205        Self: Sized + 'static,
206        F: Fn(Self::Data) -> U + 'static,
207    {
208        MapModel::new(self, map_function)
209    }
210
211    /// Returns a new Model where the elements are filtered by the function `filter_function`.
212    /// This is a shortcut for [`FilterModel::new()`].
213    fn filter<F>(self, filter_function: F) -> FilterModel<Self, F>
214    where
215        Self: Sized + 'static,
216        F: Fn(&Self::Data) -> bool + 'static,
217    {
218        FilterModel::new(self, filter_function)
219    }
220
221    /// Returns a new Model where the elements are sorted ascending.
222    /// This is a shortcut for [`SortModel::new_ascending()`].
223    #[must_use]
224    fn sort(self) -> SortModel<Self, adapters::AscendingSortHelper>
225    where
226        Self: Sized + 'static,
227        Self::Data: core::cmp::Ord,
228    {
229        SortModel::new_ascending(self)
230    }
231
232    /// Returns a new Model where the elements are sorted by the function `sort_function`.
233    /// This is a shortcut for [`SortModel::new()`].
234    fn sort_by<F>(self, sort_function: F) -> SortModel<Self, F>
235    where
236        Self: Sized + 'static,
237        F: FnMut(&Self::Data, &Self::Data) -> core::cmp::Ordering + 'static,
238    {
239        SortModel::new(self, sort_function)
240    }
241
242    /// Returns a new Model where the elements are reversed.
243    /// This is a shortcut for [`ReverseModel::new()`].
244    fn reverse(self) -> ReverseModel<Self>
245    where
246        Self: Sized + 'static,
247    {
248        ReverseModel::new(self)
249    }
250}
251
252impl<T: Model> ModelExt for T {}
253
254/// An iterator over the elements of a model.
255/// This struct is created by the [`Model::iter()`] trait function.
256pub struct ModelIterator<'a, T> {
257    model: &'a dyn Model<Data = T>,
258    row: usize,
259}
260
261impl<'a, T> ModelIterator<'a, T> {
262    /// Creates a new model iterator for a model reference.
263    /// This is the same as calling [`model.iter()`](Model::iter)
264    pub fn new(model: &'a dyn Model<Data = T>) -> Self {
265        Self { model, row: 0 }
266    }
267}
268
269impl<'a, T> Iterator for ModelIterator<'a, T> {
270    type Item = T;
271
272    fn next(&mut self) -> Option<Self::Item> {
273        if self.row >= self.model.row_count() {
274            return None;
275        }
276        let row = self.row;
277        self.row += 1;
278        self.model.row_data(row)
279    }
280
281    fn size_hint(&self) -> (usize, Option<usize>) {
282        let len = self.model.row_count();
283        (len, Some(len))
284    }
285
286    fn nth(&mut self, n: usize) -> Option<Self::Item> {
287        self.row = self.row.checked_add(n)?;
288        self.next()
289    }
290}
291
292impl<'a, T> ExactSizeIterator for ModelIterator<'a, T> {}
293
294impl<M: Model> Model for Rc<M> {
295    type Data = M::Data;
296
297    fn row_count(&self) -> usize {
298        (**self).row_count()
299    }
300
301    fn row_data(&self, row: usize) -> Option<Self::Data> {
302        (**self).row_data(row)
303    }
304
305    fn model_tracker(&self) -> &dyn ModelTracker {
306        (**self).model_tracker()
307    }
308
309    fn as_any(&self) -> &dyn core::any::Any {
310        (**self).as_any()
311    }
312    fn set_row_data(&self, row: usize, data: Self::Data) {
313        (**self).set_row_data(row, data)
314    }
315}
316
317/// A [`Model`] backed by a `Vec<T>`, using interior mutability.
318#[derive(Default)]
319pub struct VecModel<T> {
320    array: RefCell<Vec<T>>,
321    notify: ModelNotify,
322}
323
324impl<T: 'static> VecModel<T> {
325    /// Allocate a new model from a slice
326    pub fn from_slice(slice: &[T]) -> ModelRc<T>
327    where
328        T: Clone,
329    {
330        ModelRc::new(Self::from(slice.to_vec()))
331    }
332
333    /// Add a row at the end of the model
334    pub fn push(&self, value: T) {
335        self.array.borrow_mut().push(value);
336        self.notify.row_added(self.array.borrow().len() - 1, 1)
337    }
338
339    /// Inserts a row at position index. All rows after that are shifted.
340    /// This function panics if index is > row_count().
341    pub fn insert(&self, index: usize, value: T) {
342        self.array.borrow_mut().insert(index, value);
343        self.notify.row_added(index, 1)
344    }
345
346    /// Remove the row at the given index from the model
347    ///
348    /// Returns the removed row
349    pub fn remove(&self, index: usize) -> T {
350        let r = self.array.borrow_mut().remove(index);
351        self.notify.row_removed(index, 1);
352        r
353    }
354
355    /// Replace inner Vec with new data
356    pub fn set_vec(&self, new: impl Into<Vec<T>>) {
357        *self.array.borrow_mut() = new.into();
358        self.notify.reset();
359    }
360
361    /// Extend the model with the content of the iterator
362    ///
363    /// Similar to [`Vec::extend`]
364    pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I) {
365        let mut array = self.array.borrow_mut();
366        let old_idx = array.len();
367        array.extend(iter);
368        let count = array.len() - old_idx;
369        drop(array);
370        self.notify.row_added(old_idx, count);
371    }
372
373    /// Clears the model, removing all values
374    ///
375    /// Similar to [`Vec::clear`]
376    pub fn clear(&self) {
377        self.array.borrow_mut().clear();
378        self.notify.reset();
379    }
380
381    /// Swaps two elements in the model.
382    pub fn swap(&self, a: usize, b: usize) {
383        if a == b {
384            return;
385        }
386
387        self.array.borrow_mut().swap(a, b);
388        self.notify.row_changed(a);
389        self.notify.row_changed(b);
390    }
391}
392
393impl<T: Clone + 'static> VecModel<T> {
394    /// Appends all the elements in the slice to the model
395    ///
396    /// Similar to [`Vec::extend_from_slice`]
397    pub fn extend_from_slice(&self, src: &[T]) {
398        let mut array = self.array.borrow_mut();
399        let old_idx = array.len();
400
401        array.extend_from_slice(src);
402        drop(array);
403        self.notify.row_added(old_idx, src.len());
404    }
405}
406
407impl<T> From<Vec<T>> for VecModel<T> {
408    fn from(array: Vec<T>) -> Self {
409        VecModel { array: RefCell::new(array), notify: Default::default() }
410    }
411}
412
413impl<T> FromIterator<T> for VecModel<T> {
414    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
415        VecModel::from(Vec::from_iter(iter))
416    }
417}
418
419impl<T: Clone + 'static> Model for VecModel<T> {
420    type Data = T;
421
422    fn row_count(&self) -> usize {
423        self.array.borrow().len()
424    }
425
426    fn row_data(&self, row: usize) -> Option<Self::Data> {
427        self.array.borrow().get(row).cloned()
428    }
429
430    fn set_row_data(&self, row: usize, data: Self::Data) {
431        if row < self.row_count() {
432            self.array.borrow_mut()[row] = data;
433            self.notify.row_changed(row);
434        }
435    }
436
437    fn model_tracker(&self) -> &dyn ModelTracker {
438        &self.notify
439    }
440
441    fn as_any(&self) -> &dyn core::any::Any {
442        self
443    }
444}
445
446/// A model backed by a `SharedVector<T>`
447#[derive(Default)]
448pub struct SharedVectorModel<T> {
449    array: RefCell<SharedVector<T>>,
450    notify: ModelNotify,
451}
452
453impl<T: Clone + 'static> SharedVectorModel<T> {
454    /// Add a row at the end of the model
455    pub fn push(&self, value: T) {
456        self.array.borrow_mut().push(value);
457        self.notify.row_added(self.array.borrow().len() - 1, 1)
458    }
459}
460
461impl<T> SharedVectorModel<T> {
462    /// Returns a clone of the model's backing shared vector.
463    pub fn shared_vector(&self) -> SharedVector<T> {
464        self.array.borrow_mut().clone()
465    }
466}
467
468impl<T> From<SharedVector<T>> for SharedVectorModel<T> {
469    fn from(array: SharedVector<T>) -> Self {
470        SharedVectorModel { array: RefCell::new(array), notify: Default::default() }
471    }
472}
473
474impl<T: Clone + 'static> Model for SharedVectorModel<T> {
475    type Data = T;
476
477    fn row_count(&self) -> usize {
478        self.array.borrow().len()
479    }
480
481    fn row_data(&self, row: usize) -> Option<Self::Data> {
482        self.array.borrow().get(row).cloned()
483    }
484
485    fn set_row_data(&self, row: usize, data: Self::Data) {
486        self.array.borrow_mut().make_mut_slice()[row] = data;
487        self.notify.row_changed(row);
488    }
489
490    fn model_tracker(&self) -> &dyn ModelTracker {
491        &self.notify
492    }
493
494    fn as_any(&self) -> &dyn core::any::Any {
495        self
496    }
497}
498
499impl Model for usize {
500    type Data = i32;
501
502    fn row_count(&self) -> usize {
503        *self
504    }
505
506    fn row_data(&self, row: usize) -> Option<Self::Data> {
507        (row < self.row_count()).then_some(row as i32)
508    }
509
510    fn as_any(&self) -> &dyn core::any::Any {
511        self
512    }
513
514    fn model_tracker(&self) -> &dyn ModelTracker {
515        &()
516    }
517}
518
519impl Model for bool {
520    type Data = ();
521
522    fn row_count(&self) -> usize {
523        if *self {
524            1
525        } else {
526            0
527        }
528    }
529
530    fn row_data(&self, row: usize) -> Option<Self::Data> {
531        (row < self.row_count()).then_some(())
532    }
533
534    fn as_any(&self) -> &dyn core::any::Any {
535        self
536    }
537
538    fn model_tracker(&self) -> &dyn ModelTracker {
539        &()
540    }
541}
542
543/// ModelRc is a type wrapper for a reference counted implementation of the [`Model`] trait.
544///
545/// Models are used to represent sequences of the same data type. In `.slint` code those
546/// are represented using the `[T]` array syntax and typically used in `for` expressions,
547/// array properties, and array struct fields.
548///
549/// For example, a `property <[string]> foo` will be of type `ModelRc<SharedString>`
550/// and, behind the scenes, wraps a `Rc<dyn Model<Data = SharedString>>.`
551///
552/// An array struct field will also be of type `ModelRc`:
553///
554/// ```slint,no-preview
555/// export struct AddressBook {
556///     names: [string]
557/// }
558/// ```
559///
560/// When accessing `AddressBook` from Rust, the `names` field will be of type `ModelRc<SharedString>`.
561///
562/// There are several ways of constructing a ModelRc in Rust:
563///
564/// * An empty ModelRc can be constructed with [`ModelRc::default()`].
565/// * A `ModelRc` can be constructed from a slice or an array using the [`From`] trait.
566///   This allocates a [`VecModel`].
567/// * Use [`ModelRc::new()`] to construct a `ModelRc` from a type that implements the
568///   [`Model`] trait, such as [`VecModel`] or your own implementation.
569/// * If you have your model already in an `Rc`, then you can use the [`From`] trait
570///   to convert from `Rc<dyn Model<Data = T>>` to `ModelRc`.
571///
572/// ## Example
573///
574/// ```rust
575/// # i_slint_backend_testing::init_no_event_loop();
576/// use slint::{slint, SharedString, ModelRc, Model, VecModel};
577/// use std::rc::Rc;
578/// slint!{
579///     import { Button } from "std-widgets.slint";
580///     export component Example {
581///         callback add_item <=> btn.clicked;
582///         in property <[string]> the_model;
583///         HorizontalLayout {
584///             for it in the_model : Text { text: it; }
585///             btn := Button { text: "Add"; }
586///         }
587///     }
588/// }
589/// let ui = Example::new().unwrap();
590/// // Create a VecModel and put it in an Rc.
591/// let the_model : Rc<VecModel<SharedString>> =
592///         Rc::new(VecModel::from(vec!["Hello".into(), "World".into()]));
593/// // Convert it to a ModelRc.
594/// let the_model_rc = ModelRc::from(the_model.clone());
595/// // Pass the model to the ui: The generated set_the_model setter from the
596/// // the_model property takes a ModelRc.
597/// ui.set_the_model(the_model_rc);
598///
599/// // We have kept a strong reference to the_model, to modify it in a callback.
600/// ui.on_add_item(move || {
601///     // Use VecModel API: VecModel uses the Model notification mechanism to let Slint
602///     // know it needs to refresh the UI.
603///     the_model.push("SomeValue".into());
604/// });
605///
606/// // Alternative: we can re-use a getter.
607/// let ui_weak = ui.as_weak();
608/// ui.on_add_item(move || {
609///     let ui = ui_weak.unwrap();
610///     let the_model_rc = ui.get_the_model();
611///     let the_model = the_model_rc.as_any().downcast_ref::<VecModel<SharedString>>()
612///         .expect("We know we set a VecModel earlier");
613///     the_model.push("An Item".into());
614/// });
615/// ```
616pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
617
618impl<T> core::fmt::Debug for ModelRc<T> {
619    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
620        write!(f, "ModelRc(dyn Model)")
621    }
622}
623
624impl<T> Clone for ModelRc<T> {
625    fn clone(&self) -> Self {
626        Self(self.0.clone())
627    }
628}
629
630impl<T> Default for ModelRc<T> {
631    /// Construct an empty model
632    fn default() -> Self {
633        Self(None)
634    }
635}
636
637impl<T> core::cmp::PartialEq for ModelRc<T> {
638    fn eq(&self, other: &Self) -> bool {
639        match (&self.0, &other.0) {
640            (None, None) => true,
641            (Some(a), Some(b)) => core::ptr::eq(
642                (&**a) as *const dyn Model<Data = T> as *const u8,
643                (&**b) as *const dyn Model<Data = T> as *const u8,
644            ),
645            _ => false,
646        }
647    }
648}
649
650impl<T> ModelRc<T> {
651    pub fn new(model: impl Model<Data = T> + 'static) -> Self {
652        Self(Some(Rc::new(model)))
653    }
654}
655
656impl<T, M: Model<Data = T> + 'static> From<Rc<M>> for ModelRc<T> {
657    fn from(model: Rc<M>) -> Self {
658        Self(Some(model))
659    }
660}
661
662impl<T> From<Rc<dyn Model<Data = T> + 'static>> for ModelRc<T> {
663    fn from(model: Rc<dyn Model<Data = T> + 'static>) -> Self {
664        Self(Some(model))
665    }
666}
667
668impl<T: Clone + 'static> From<&[T]> for ModelRc<T> {
669    fn from(slice: &[T]) -> Self {
670        VecModel::from_slice(slice)
671    }
672}
673
674impl<T: Clone + 'static, const N: usize> From<[T; N]> for ModelRc<T> {
675    fn from(array: [T; N]) -> Self {
676        VecModel::from_slice(&array)
677    }
678}
679
680impl<T> TryInto<Rc<dyn Model<Data = T>>> for ModelRc<T> {
681    type Error = ();
682
683    fn try_into(self) -> Result<Rc<dyn Model<Data = T>>, Self::Error> {
684        self.0.ok_or(())
685    }
686}
687
688impl<T> Model for ModelRc<T> {
689    type Data = T;
690
691    fn row_count(&self) -> usize {
692        self.0.as_ref().map_or(0, |model| model.row_count())
693    }
694
695    fn row_data(&self, row: usize) -> Option<Self::Data> {
696        self.0.as_ref().and_then(|model| model.row_data(row))
697    }
698
699    fn set_row_data(&self, row: usize, data: Self::Data) {
700        if let Some(model) = self.0.as_ref() {
701            model.set_row_data(row, data);
702        }
703    }
704
705    fn model_tracker(&self) -> &dyn ModelTracker {
706        self.0.as_ref().map_or(&(), |model| model.model_tracker())
707    }
708
709    fn as_any(&self) -> &dyn core::any::Any {
710        self.0.as_ref().map_or(&(), |model| model.as_any())
711    }
712}
713
714/// ItemTree that can be instantiated by a repeater.
715pub trait RepeatedItemTree:
716    crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static
717{
718    /// The data corresponding to the model
719    type Data: 'static;
720
721    /// Update this ItemTree at the given index and the given data
722    fn update(&self, index: usize, data: Self::Data);
723
724    /// Called once after the ItemTree has been instantiated and update()
725    /// was called once.
726    fn init(&self) {}
727
728    /// Layout this item in the listview
729    ///
730    /// offset_y is the `y` position where this item should be placed.
731    /// it should be updated to be to the y position of the next item.
732    fn listview_layout(
733        self: Pin<&Self>,
734        _offset_y: &mut LogicalLength,
735        _viewport_width: Pin<&Property<LogicalLength>>,
736    ) {
737    }
738
739    /// Returns what's needed to perform the layout if this ItemTrees is in a box layout
740    fn box_layout_data(
741        self: Pin<&Self>,
742        _orientation: Orientation,
743    ) -> crate::layout::BoxLayoutCellData {
744        crate::layout::BoxLayoutCellData::default()
745    }
746}
747
748#[derive(Clone, Copy, PartialEq, Debug)]
749enum RepeatedInstanceState {
750    /// The item is in a clean state
751    Clean,
752    /// The model data is stale and needs to be refreshed
753    Dirty,
754}
755struct RepeaterInner<C: RepeatedItemTree> {
756    instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,
757
758    // The remaining properties only make sense for ListView
759    /// The model row (index) of the first ItemTree in the `instances` vector.
760    offset: usize,
761    /// The average visible item height.
762    cached_item_height: LogicalLength,
763    /// The viewport_y last time the layout of the ListView was done
764    previous_viewport_y: LogicalLength,
765    /// the position of the item in the row `offset` (which corresponds to `instances[0]`).
766    /// We will try to keep this constant when re-layouting items
767    anchor_y: LogicalLength,
768}
769
770impl<C: RepeatedItemTree> Default for RepeaterInner<C> {
771    fn default() -> Self {
772        RepeaterInner {
773            instances: Default::default(),
774            offset: 0,
775            cached_item_height: Default::default(),
776            previous_viewport_y: Default::default(),
777            anchor_y: Default::default(),
778        }
779    }
780}
781
782/// This struct is put in a component when using the `for` syntax
783/// It helps instantiating the ItemTree `T`
784#[pin_project]
785pub struct RepeaterTracker<T: RepeatedItemTree> {
786    inner: RefCell<RepeaterInner<T>>,
787    #[pin]
788    model: Property<ModelRc<T::Data>>,
789    #[pin]
790    is_dirty: Property<bool>,
791    /// Only used for the list view to track if the scrollbar has changed and item needs to be laid out again.
792    #[pin]
793    listview_geometry_tracker: crate::properties::PropertyTracker,
794}
795
796impl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {
797    /// Notify the peers that a specific row was changed
798    fn row_changed(self: Pin<&Self>, row: usize) {
799        let mut inner = self.inner.borrow_mut();
800        let inner = &mut *inner;
801        if let Some(c) = inner.instances.get_mut(row.wrapping_sub(inner.offset)) {
802            if !self.model.is_dirty() {
803                if let Some(comp) = c.1.as_ref() {
804                    let model = self.project_ref().model.get_untracked();
805                    if let Some(data) = model.row_data(row) {
806                        comp.update(row, data);
807                    }
808                    c.0 = RepeatedInstanceState::Clean;
809                }
810            } else {
811                c.0 = RepeatedInstanceState::Dirty;
812            }
813        }
814    }
815    /// Notify the peers that rows were added
816    fn row_added(self: Pin<&Self>, mut index: usize, mut count: usize) {
817        let mut inner = self.inner.borrow_mut();
818        if index < inner.offset {
819            if index + count < inner.offset {
820                return;
821            }
822            count -= inner.offset - index;
823            index = 0;
824        } else {
825            index -= inner.offset;
826        }
827        if count == 0 || index > inner.instances.len() {
828            return;
829        }
830        self.is_dirty.set(true);
831        inner.instances.splice(
832            index..index,
833            core::iter::repeat((RepeatedInstanceState::Dirty, None)).take(count),
834        );
835        for c in inner.instances[index + count..].iter_mut() {
836            // Because all the indexes are dirty
837            c.0 = RepeatedInstanceState::Dirty;
838        }
839    }
840    /// Notify the peers that rows were removed
841    fn row_removed(self: Pin<&Self>, mut index: usize, mut count: usize) {
842        let mut inner = self.inner.borrow_mut();
843        if index < inner.offset {
844            if index + count < inner.offset {
845                return;
846            }
847            count -= inner.offset - index;
848            index = 0;
849        } else {
850            index -= inner.offset;
851        }
852        if count == 0 || index >= inner.instances.len() {
853            return;
854        }
855        if (index + count) > inner.instances.len() {
856            count = inner.instances.len() - index;
857        }
858        self.is_dirty.set(true);
859        inner.instances.drain(index..(index + count));
860        for c in inner.instances[index..].iter_mut() {
861            // Because all the indexes are dirty
862            c.0 = RepeatedInstanceState::Dirty;
863        }
864    }
865
866    fn reset(self: Pin<&Self>) {
867        self.is_dirty.set(true);
868        self.inner.borrow_mut().instances.clear();
869    }
870}
871
872impl<C: RepeatedItemTree> Default for RepeaterTracker<C> {
873    fn default() -> Self {
874        Self {
875            inner: Default::default(),
876            model: Property::new_named(ModelRc::default(), "i_slint_core::Repeater::model"),
877            is_dirty: Property::new_named(false, "i_slint_core::Repeater::is_dirty"),
878            listview_geometry_tracker: Default::default(),
879        }
880    }
881}
882
883#[pin_project]
884pub struct Repeater<C: RepeatedItemTree>(#[pin] ModelChangeListenerContainer<RepeaterTracker<C>>);
885
886impl<C: RepeatedItemTree> Default for Repeater<C> {
887    fn default() -> Self {
888        Self(Default::default())
889    }
890}
891
892impl<C: RepeatedItemTree + 'static> Repeater<C> {
893    fn data(self: Pin<&Self>) -> Pin<&RepeaterTracker<C>> {
894        self.project_ref().0.get()
895    }
896
897    fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
898        // Safety: Repeater does not implement drop and never allows access to model as mutable
899        let model = self.data().project_ref().model;
900
901        if model.is_dirty() {
902            *self.data().inner.borrow_mut() = RepeaterInner::default();
903            self.data().is_dirty.set(true);
904            let m = model.get();
905            let peer = self.project_ref().0.model_peer();
906            m.model_tracker().attach_peer(peer);
907            m
908        } else {
909            model.get()
910        }
911    }
912
913    /// Call this function to make sure that the model is updated.
914    /// The init function is the function to create a ItemTree
915    pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
916        let model = self.model();
917        if self.data().project_ref().is_dirty.get() {
918            self.ensure_updated_impl(init, &model, model.row_count());
919        }
920    }
921
922    // returns true if new items were created
923    fn ensure_updated_impl(
924        self: Pin<&Self>,
925        init: impl Fn() -> ItemTreeRc<C>,
926        model: &ModelRc<C::Data>,
927        count: usize,
928    ) -> bool {
929        let mut indices_to_init = Vec::new();
930        let mut inner = self.0.inner.borrow_mut();
931        inner.instances.resize_with(count, || (RepeatedInstanceState::Dirty, None));
932        let offset = inner.offset;
933        let mut any_items_created = false;
934        for (i, c) in inner.instances.iter_mut().enumerate() {
935            if c.0 == RepeatedInstanceState::Dirty {
936                if c.1.is_none() {
937                    any_items_created = true;
938                    c.1 = Some(init());
939                    indices_to_init.push(i);
940                };
941                if let Some(data) = model.row_data(i + offset) {
942                    c.1.as_ref().unwrap().update(i + offset, data);
943                }
944                c.0 = RepeatedInstanceState::Clean;
945            }
946        }
947        self.data().is_dirty.set(false);
948
949        drop(inner);
950        let inner = self.0.inner.borrow();
951        for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
952            item.1.as_ref().unwrap().init();
953        }
954
955        any_items_created
956    }
957
958    /// Same as `Self::ensure_updated` but for a ListView
959    pub fn ensure_updated_listview(
960        self: Pin<&Self>,
961        init: impl Fn() -> ItemTreeRc<C>,
962        viewport_width: Pin<&Property<LogicalLength>>,
963        viewport_height: Pin<&Property<LogicalLength>>,
964        viewport_y: Pin<&Property<LogicalLength>>,
965        listview_width: LogicalLength,
966        listview_height: Pin<&Property<LogicalLength>>,
967    ) {
968        // Query is_dirty to track model changes
969        self.data().project_ref().is_dirty.get();
970        self.data().project_ref().is_dirty.set(false);
971
972        viewport_width.set(listview_width);
973        let model = self.model();
974        let row_count = model.row_count();
975        if row_count == 0 {
976            self.0.inner.borrow_mut().instances.clear();
977            viewport_height.set(LogicalLength::zero());
978            viewport_y.set(LogicalLength::zero());
979
980            return;
981        }
982
983        let listview_height = listview_height.get();
984        let mut vp_y = viewport_y.get().min(LogicalLength::zero());
985
986        // We need some sort of estimation of the element height
987        let cached_item_height = self.data().inner.borrow_mut().cached_item_height;
988        let element_height = if cached_item_height > LogicalLength::zero() {
989            cached_item_height
990        } else {
991            let total_height = Cell::new(LogicalLength::zero());
992            let count = Cell::new(0);
993            let get_height_visitor = |x: &ItemTreeRc<C>| {
994                let height = x.as_pin_ref().item_geometry(0).height_length();
995                count.set(count.get() + 1);
996                total_height.set(total_height.get() + height);
997            };
998            for c in self.data().inner.borrow().instances.iter() {
999                if let Some(x) = c.1.as_ref() {
1000                    get_height_visitor(x);
1001                }
1002            }
1003
1004            if count.get() > 0 {
1005                total_height.get() / (count.get() as Coord)
1006            } else {
1007                // There seems to be currently no items. Just instantiate one item.
1008                {
1009                    let mut inner = self.0.inner.borrow_mut();
1010                    inner.offset = inner.offset.min(row_count - 1);
1011                }
1012
1013                self.ensure_updated_impl(&init, &model, 1);
1014                if let Some(c) = self.data().inner.borrow().instances.first() {
1015                    if let Some(x) = c.1.as_ref() {
1016                        get_height_visitor(x);
1017                    }
1018                } else {
1019                    panic!("Could not determine size of items");
1020                }
1021                total_height.get()
1022            }
1023        };
1024
1025        let data = self.data();
1026        let mut inner = data.inner.borrow_mut();
1027        if inner.offset >= row_count {
1028            inner.offset = row_count - 1;
1029        }
1030
1031        let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;
1032        let first_item_y = inner.anchor_y;
1033        let last_item_bottom = first_item_y + element_height * inner.instances.len() as Coord;
1034
1035        let mut indices_to_init = Vec::new();
1036
1037        let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen
1038            || last_item_bottom + element_height < -vp_y
1039        {
1040            // We are jumping more than 1.5 screens, consider this as a random seek.
1041            inner.instances.clear();
1042            inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);
1043            (inner.offset, -vp_y)
1044        } else if vp_y < inner.previous_viewport_y {
1045            // we scrolled down, try to find out the new offset.
1046            let mut it_y = first_item_y;
1047            let mut new_offset = inner.offset;
1048            debug_assert!(it_y <= -vp_y); // we scrolled down, the anchor should be hidden
1049            for (i, c) in inner.instances.iter_mut().enumerate() {
1050                if c.0 == RepeatedInstanceState::Dirty {
1051                    if c.1.is_none() {
1052                        c.1 = Some(init());
1053                        indices_to_init.push(i);
1054                    }
1055                    if let Some(data) = model.row_data(new_offset) {
1056                        c.1.as_ref().unwrap().update(new_offset, data);
1057                    }
1058                    c.0 = RepeatedInstanceState::Clean;
1059                }
1060                let h = c.1.as_ref().unwrap().as_pin_ref().item_geometry(0).height_length();
1061                if it_y + h >= -vp_y || new_offset + 1 >= row_count {
1062                    break;
1063                }
1064                it_y += h;
1065                new_offset += 1;
1066            }
1067            (new_offset, it_y)
1068        } else {
1069            // We scrolled up, we'll instantiate items before offset in the loop
1070            (inner.offset, first_item_y)
1071        };
1072
1073        loop {
1074            // If there is a gap before the new_offset and the beginning of the visible viewport,
1075            // try to fill it with items. First look at items that are before new_offset in the
1076            // inner.instances, if any.
1077            while new_offset > inner.offset && new_offset_y > -vp_y {
1078                new_offset -= 1;
1079                new_offset_y -= inner.instances[new_offset - inner.offset]
1080                    .1
1081                    .as_ref()
1082                    .unwrap()
1083                    .as_pin_ref()
1084                    .item_geometry(0)
1085                    .height_length();
1086            }
1087            // If there is still a gap, fill it with new instances before
1088            let mut new_instances = Vec::new();
1089            while new_offset > 0 && new_offset_y > -vp_y {
1090                new_offset -= 1;
1091                let new_instance = init();
1092                if let Some(data) = model.row_data(new_offset) {
1093                    new_instance.update(new_offset, data);
1094                }
1095                new_offset_y -= new_instance.as_pin_ref().item_geometry(0).height_length();
1096                new_instances.push(new_instance);
1097            }
1098            if !new_instances.is_empty() {
1099                for x in &mut indices_to_init {
1100                    *x += new_instances.len();
1101                }
1102                indices_to_init.extend(0..new_instances.len());
1103                inner.instances.splice(
1104                    0..0,
1105                    new_instances
1106                        .into_iter()
1107                        .rev()
1108                        .map(|c| (RepeatedInstanceState::Clean, Some(c))),
1109                );
1110                inner.offset = new_offset;
1111            }
1112            assert!(
1113                new_offset >= inner.offset && new_offset <= inner.offset + inner.instances.len()
1114            );
1115
1116            // Now we will layout items until we fit the view, starting with the ones that are already instantiated
1117            let mut y = new_offset_y;
1118            let mut idx = new_offset;
1119            let instances_begin = new_offset - inner.offset;
1120            for c in &mut inner.instances[instances_begin..] {
1121                if idx >= row_count {
1122                    break;
1123                }
1124                if c.0 == RepeatedInstanceState::Dirty {
1125                    if c.1.is_none() {
1126                        c.1 = Some(init());
1127                        indices_to_init.push(instances_begin + idx - new_offset)
1128                    }
1129                    if let Some(data) = model.row_data(idx) {
1130                        c.1.as_ref().unwrap().update(idx, data);
1131                    }
1132                    c.0 = RepeatedInstanceState::Clean;
1133                }
1134                if let Some(x) = c.1.as_ref() {
1135                    x.as_pin_ref().listview_layout(&mut y, viewport_width);
1136                }
1137                idx += 1;
1138                if y >= -vp_y + listview_height {
1139                    break;
1140                }
1141            }
1142
1143            // create more items until there is no more room.
1144            while y < -vp_y + listview_height && idx < row_count {
1145                let new_instance = init();
1146                if let Some(data) = model.row_data(idx) {
1147                    new_instance.update(idx, data);
1148                }
1149                new_instance.as_pin_ref().listview_layout(&mut y, viewport_width);
1150                indices_to_init.push(inner.instances.len());
1151                inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));
1152                idx += 1;
1153            }
1154            if y < -vp_y + listview_height && vp_y < LogicalLength::zero() {
1155                assert!(idx >= row_count);
1156                // we reached the end of the model, and we still have room. scroll a bit up.
1157                vp_y = listview_height - y;
1158                continue;
1159            }
1160
1161            // Let's cleanup the instances that are not shown.
1162            if new_offset != inner.offset {
1163                let instances_begin = new_offset - inner.offset;
1164                inner.instances.splice(0..instances_begin, core::iter::empty());
1165                indices_to_init.retain_mut(|idx| {
1166                    if *idx < instances_begin {
1167                        false
1168                    } else {
1169                        *idx -= instances_begin;
1170                        true
1171                    }
1172                });
1173                inner.offset = new_offset;
1174            }
1175            if inner.instances.len() != idx - new_offset {
1176                inner.instances.splice(idx - new_offset.., core::iter::empty());
1177                indices_to_init.retain(|x| *x < idx - new_offset);
1178            }
1179
1180            if inner.instances.is_empty() {
1181                break;
1182            }
1183
1184            // Now re-compute some coordinate such a way that the scrollbar are adjusted.
1185            inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord;
1186            inner.anchor_y = inner.cached_item_height * inner.offset as Coord;
1187            viewport_height.set(inner.cached_item_height * row_count as Coord);
1188            let new_viewport_y = -inner.anchor_y + vp_y + new_offset_y;
1189            viewport_y.set(new_viewport_y);
1190            inner.previous_viewport_y = new_viewport_y;
1191            break;
1192        }
1193        drop(inner);
1194        let inner = self.0.inner.borrow();
1195        for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1196            item.1.as_ref().unwrap().init();
1197        }
1198    }
1199
1200    /// Sets the data directly in the model
1201    pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
1202        let model = self.model();
1203        model.set_row_data(row, data);
1204    }
1205
1206    /// Set the model binding
1207    pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
1208        self.0.model.set_binding(binding);
1209    }
1210
1211    /// Call the visitor for the root of each instance
1212    pub fn visit(
1213        &self,
1214        order: TraversalOrder,
1215        mut visitor: crate::item_tree::ItemVisitorRefMut,
1216    ) -> crate::item_tree::VisitChildrenResult {
1217        // We can't keep self.inner borrowed because the event might modify the model
1218        let count = self.0.inner.borrow().instances.len() as u32;
1219        for i in 0..count {
1220            let i = if order == TraversalOrder::BackToFront { i } else { count - i - 1 };
1221            let c = self.0.inner.borrow().instances.get(i as usize).and_then(|c| c.1.clone());
1222            if let Some(c) = c {
1223                if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()
1224                {
1225                    return crate::item_tree::VisitChildrenResult::abort(i, 0);
1226                }
1227            }
1228        }
1229        crate::item_tree::VisitChildrenResult::CONTINUE
1230    }
1231
1232    /// Return the amount of instances currently in the repeater
1233    pub fn len(&self) -> usize {
1234        self.0.inner.borrow().instances.len()
1235    }
1236
1237    /// Return the range of indices used by this Repeater.
1238    ///
1239    /// Two values are necessary here since the Repeater can start to insert the data from its
1240    /// model at an offset.
1241    pub fn range(&self) -> core::ops::Range<usize> {
1242        let inner = self.0.inner.borrow();
1243        core::ops::Range { start: inner.offset, end: inner.offset + inner.instances.len() }
1244    }
1245
1246    /// Return the instance for the given model index.
1247    /// The index should be within [`Self::range()`]
1248    pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1249        let inner = self.0.inner.borrow();
1250        inner
1251            .instances
1252            .get(index - inner.offset)
1253            .map(|c| c.1.clone().expect("That was updated before!"))
1254    }
1255
1256    /// Return true if the Repeater as empty
1257    pub fn is_empty(&self) -> bool {
1258        self.len() == 0
1259    }
1260
1261    /// Returns a vector containing all instances
1262    pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1263        self.0.inner.borrow().instances.iter().flat_map(|x| x.1.clone()).collect()
1264    }
1265}
1266
1267impl From<SharedString> for StandardListViewItem {
1268    fn from(value: SharedString) -> Self {
1269        StandardListViewItem { text: value }
1270    }
1271}
1272
1273impl From<&str> for StandardListViewItem {
1274    fn from(value: &str) -> Self {
1275        StandardListViewItem { text: value.into() }
1276    }
1277}
1278
1279#[cfg(test)]
1280mod tests {
1281    use super::*;
1282
1283    #[test]
1284    fn test_tracking_model_handle() {
1285        let model: Rc<VecModel<u8>> = Rc::new(Default::default());
1286        let handle = ModelRc::from(model.clone() as Rc<dyn Model<Data = u8>>);
1287        let tracker = Box::pin(crate::properties::PropertyTracker::default());
1288        assert_eq!(
1289            tracker.as_ref().evaluate(|| {
1290                handle.model_tracker().track_row_count_changes();
1291                handle.row_count()
1292            }),
1293            0
1294        );
1295        assert!(!tracker.is_dirty());
1296        model.push(42);
1297        model.push(100);
1298        assert!(tracker.is_dirty());
1299        assert_eq!(
1300            tracker.as_ref().evaluate(|| {
1301                handle.model_tracker().track_row_count_changes();
1302                handle.row_count()
1303            }),
1304            2
1305        );
1306        assert!(!tracker.is_dirty());
1307        model.set_row_data(0, 41);
1308        assert!(!tracker.is_dirty());
1309        model.remove(0);
1310        assert!(tracker.is_dirty());
1311        assert_eq!(
1312            tracker.as_ref().evaluate(|| {
1313                handle.model_tracker().track_row_count_changes();
1314                handle.row_count()
1315            }),
1316            1
1317        );
1318        assert!(!tracker.is_dirty());
1319        model.set_vec(vec![1, 2, 3]);
1320        assert!(tracker.is_dirty());
1321    }
1322
1323    #[test]
1324    fn test_data_tracking() {
1325        let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
1326        let handle = ModelRc::from(model.clone());
1327        let tracker = Box::pin(crate::properties::PropertyTracker::default());
1328        assert_eq!(
1329            tracker.as_ref().evaluate(|| {
1330                handle.model_tracker().track_row_data_changes(1);
1331                handle.row_data(1).unwrap()
1332            }),
1333            1
1334        );
1335        assert!(!tracker.is_dirty());
1336
1337        model.set_row_data(2, 42);
1338        assert!(!tracker.is_dirty());
1339        model.set_row_data(1, 100);
1340        assert!(tracker.is_dirty());
1341
1342        assert_eq!(
1343            tracker.as_ref().evaluate(|| {
1344                handle.model_tracker().track_row_data_changes(1);
1345                handle.row_data(1).unwrap()
1346            }),
1347            100
1348        );
1349        assert!(!tracker.is_dirty());
1350
1351        // Any changes to rows (even if after tracked rows) for now also marks watched rows as dirty, to
1352        // keep the logic simple.
1353        model.push(200);
1354        assert!(tracker.is_dirty());
1355
1356        assert_eq!(tracker.as_ref().evaluate(|| { handle.row_data_tracked(1).unwrap() }), 100);
1357        assert!(!tracker.is_dirty());
1358
1359        model.insert(0, 255);
1360        assert!(tracker.is_dirty());
1361
1362        model.set_vec(vec![]);
1363        assert!(tracker.is_dirty());
1364    }
1365
1366    #[derive(Default)]
1367    struct TestView {
1368        // Track the parameters reported by the model (row counts, indices, etc.).
1369        // The last field in the tuple is the row size the model reports at the time
1370        // of callback
1371        changed_rows: RefCell<Vec<(usize, usize)>>,
1372        added_rows: RefCell<Vec<(usize, usize, usize)>>,
1373        removed_rows: RefCell<Vec<(usize, usize, usize)>>,
1374        reset: RefCell<usize>,
1375        model: RefCell<Option<std::rc::Weak<dyn Model<Data = i32>>>>,
1376    }
1377    impl TestView {
1378        fn clear(&self) {
1379            self.changed_rows.borrow_mut().clear();
1380            self.added_rows.borrow_mut().clear();
1381            self.removed_rows.borrow_mut().clear();
1382            *self.reset.borrow_mut() = 0;
1383        }
1384        fn row_count(&self) -> usize {
1385            self.model
1386                .borrow()
1387                .as_ref()
1388                .and_then(|model| model.upgrade())
1389                .map_or(0, |model| model.row_count())
1390        }
1391    }
1392    impl ModelChangeListener for TestView {
1393        fn row_changed(self: Pin<&Self>, row: usize) {
1394            self.changed_rows.borrow_mut().push((row, self.row_count()));
1395        }
1396
1397        fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1398            self.added_rows.borrow_mut().push((index, count, self.row_count()));
1399        }
1400
1401        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1402            self.removed_rows.borrow_mut().push((index, count, self.row_count()));
1403        }
1404        fn reset(self: Pin<&Self>) {
1405            *self.reset.borrow_mut() += 1;
1406        }
1407    }
1408
1409    #[test]
1410    fn test_vecmodel_set_vec() {
1411        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1412
1413        let model = Rc::new(VecModel::from(vec![1i32, 2, 3, 4]));
1414        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1415        *view.model.borrow_mut() =
1416            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1417
1418        model.push(5);
1419        assert!(view.changed_rows.borrow().is_empty());
1420        assert_eq!(&*view.added_rows.borrow(), &[(4, 1, 5)]);
1421        assert!(view.removed_rows.borrow().is_empty());
1422        assert_eq!(*view.reset.borrow(), 0);
1423        view.clear();
1424
1425        model.set_vec(vec![6, 7, 8]);
1426        assert!(view.changed_rows.borrow().is_empty());
1427        assert!(view.added_rows.borrow().is_empty());
1428        assert!(view.removed_rows.borrow().is_empty());
1429        assert_eq!(*view.reset.borrow(), 1);
1430        view.clear();
1431
1432        model.extend_from_slice(&[9, 10, 11]);
1433        assert!(view.changed_rows.borrow().is_empty());
1434        assert_eq!(&*view.added_rows.borrow(), &[(3, 3, 6)]);
1435        assert!(view.removed_rows.borrow().is_empty());
1436        assert_eq!(*view.reset.borrow(), 0);
1437        view.clear();
1438
1439        model.extend([12, 13]);
1440        assert!(view.changed_rows.borrow().is_empty());
1441        assert_eq!(&*view.added_rows.borrow(), &[(6, 2, 8)]);
1442        assert!(view.removed_rows.borrow().is_empty());
1443        assert_eq!(*view.reset.borrow(), 0);
1444        view.clear();
1445
1446        assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 7, 8, 9, 10, 11, 12, 13]);
1447
1448        model.swap(1, 1);
1449        assert!(view.changed_rows.borrow().is_empty());
1450        assert!(view.added_rows.borrow().is_empty());
1451        assert!(view.removed_rows.borrow().is_empty());
1452        assert_eq!(*view.reset.borrow(), 0);
1453        view.clear();
1454
1455        model.swap(1, 2);
1456        assert_eq!(&*view.changed_rows.borrow(), &[(1, 8), (2, 8)]);
1457        assert!(view.added_rows.borrow().is_empty());
1458        assert!(view.removed_rows.borrow().is_empty());
1459        assert_eq!(*view.reset.borrow(), 0);
1460        view.clear();
1461
1462        assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 8, 7, 9, 10, 11, 12, 13]);
1463    }
1464
1465    #[test]
1466    fn test_vecmodel_clear() {
1467        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1468
1469        let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1470        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1471        *view.model.borrow_mut() =
1472            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1473
1474        model.clear();
1475        assert_eq!(*view.reset.borrow(), 1);
1476        assert_eq!(model.row_count(), 0);
1477    }
1478
1479    #[test]
1480    fn test_vecmodel_swap() {
1481        let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1482
1483        let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1484        model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1485        *view.model.borrow_mut() =
1486            Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1487
1488        model.swap(1, 1);
1489        assert!(view.changed_rows.borrow().is_empty());
1490        assert!(view.added_rows.borrow().is_empty());
1491        assert!(view.removed_rows.borrow().is_empty());
1492        assert_eq!(*view.reset.borrow(), 0);
1493        view.clear();
1494
1495        model.swap(1, 2);
1496        assert_eq!(&*view.changed_rows.borrow(), &[(1, 4), (2, 4)]);
1497        assert!(view.added_rows.borrow().is_empty());
1498        assert!(view.removed_rows.borrow().is_empty());
1499        assert_eq!(*view.reset.borrow(), 0);
1500        view.clear();
1501    }
1502
1503    #[test]
1504    fn modeliter_in_bounds() {
1505        struct TestModel {
1506            length: usize,
1507            max_requested_row: Cell<usize>,
1508            notify: ModelNotify,
1509        }
1510
1511        impl Model for TestModel {
1512            type Data = usize;
1513
1514            fn row_count(&self) -> usize {
1515                self.length
1516            }
1517
1518            fn row_data(&self, row: usize) -> Option<usize> {
1519                self.max_requested_row.set(self.max_requested_row.get().max(row));
1520                (row < self.length).then(|| row)
1521            }
1522
1523            fn model_tracker(&self) -> &dyn ModelTracker {
1524                &self.notify
1525            }
1526        }
1527
1528        let model = Rc::new(TestModel {
1529            length: 10,
1530            max_requested_row: Cell::new(0),
1531            notify: Default::default(),
1532        });
1533
1534        assert_eq!(model.iter().max().unwrap(), 9);
1535        assert_eq!(model.max_requested_row.get(), 9);
1536    }
1537}