ferroui_controls/
items_source_view.rs1use crate::items_source::{unbox_item, IItemsList, ItemsChangedEventArgs, ItemsChangedHandler, ItemsSource};
5use crate::utils::{CollectionChangedEventManager, ICollectionChangedListener};
6use ferroui_base::utilities::HandlerList;
7use ferroui_base::{BoxedValue, PropertyValue};
8use std::cell::{Cell, RefCell};
9use std::marker::PhantomData;
10use std::ops::Deref;
11use std::rc::{Rc, Weak};
12
13ferroui_base::ferro_thread_local! {
14 static EMPTY: Rc<ItemsSourceView> = ItemsSourceView::new(ItemsSource::from_items([]));
15 static UNINITIALIZED_SOURCE: ItemsSource = ItemsSource::from_items([]);
17}
18
19pub struct ItemsSourceView {
22 this: Weak<ItemsSourceView>,
23 source: RefCell<ItemsSource>,
24 collection_changed: HandlerList<ItemsChangedHandler>,
25 pre_collection_changed: HandlerList<ItemsChangedHandler>,
26 post_collection_changed: HandlerList<ItemsChangedHandler>,
27 listening: Cell<bool>,
28}
29
30impl PartialEq for ItemsSourceView {
32 fn eq(&self, other: &Self) -> bool {
33 std::ptr::eq(self, other)
34 }
35}
36
37impl ItemsSourceView {
38 pub fn empty() -> Rc<ItemsSourceView> {
40 EMPTY.with(Rc::clone)
41 }
42
43 pub(crate) fn uninitialized_source() -> ItemsSource {
45 UNINITIALIZED_SOURCE.with(Clone::clone)
46 }
47
48 pub fn new(source: ItemsSource) -> Rc<Self> {
52 Rc::new_cyclic(|this| Self {
53 this: this.clone(),
54 source: RefCell::new(source),
55 collection_changed: HandlerList::new(),
56 pre_collection_changed: HandlerList::new(),
57 post_collection_changed: HandlerList::new(),
58 listening: Cell::new(false),
59 })
60 }
61
62 #[inline]
64 pub fn count(&self) -> usize {
65 self.source.borrow().count()
66 }
67
68 pub fn has_key_index_mapping(&self) -> bool {
74 self.source().list().key_index_mapping().is_some()
75 }
76
77 pub fn key_from_index(&self, index: i32) -> String {
85 let source = self.source();
86 assert!(index >= 0 && (index as usize) < source.count(), "Argument index is invalid.");
87 source
88 .list()
89 .key_index_mapping()
90 .expect("The items source does not implement IKeyIndexMapping.")
91 .key_from_index(index)
92 }
93
94 pub fn index_from_key(&self, key: &str) -> i32 {
100 self.source()
101 .list()
102 .key_index_mapping()
103 .expect("The items source does not implement IKeyIndexMapping.")
104 .index_from_key(key)
105 }
106
107 #[inline]
109 pub fn source(&self) -> ItemsSource {
110 self.source.borrow().clone()
111 }
112
113 pub(crate) fn try_get_initialized_source(&self) -> Option<ItemsSource> {
114 let source = self.source();
115 if source.ptr_eq(&Self::uninitialized_source()) {
116 None
117 } else {
118 Some(source)
119 }
120 }
121
122 pub fn add_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
126 self.add_listener_if_necessary();
127 self.collection_changed.add(handler)
128 }
129
130 pub fn remove_collection_changed(&self, token: u64) {
131 self.collection_changed.remove(token);
132 self.remove_listener_if_necessary();
133 }
134
135 pub(crate) fn add_pre_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
138 self.add_listener_if_necessary();
139 self.pre_collection_changed.add(handler)
140 }
141
142 pub(crate) fn remove_pre_collection_changed(&self, token: u64) {
143 self.pre_collection_changed.remove(token);
144 self.remove_listener_if_necessary();
145 }
146
147 pub(crate) fn add_post_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
151 self.add_listener_if_necessary();
152 self.post_collection_changed.add(handler)
153 }
154
155 pub(crate) fn remove_post_collection_changed(&self, token: u64) {
156 self.post_collection_changed.remove(token);
157 self.remove_listener_if_necessary();
158 }
159
160 #[inline]
162 pub fn get_at(&self, index: usize) -> Option<BoxedValue> {
163 let source = self.source.borrow().clone();
164 source.get_at(index)
165 }
166
167 pub fn contains(&self, item: &Option<BoxedValue>) -> bool {
169 self.index_of(item) >= 0
170 }
171
172 pub fn index_of(&self, item: &Option<BoxedValue>) -> i32 {
174 let source = self.source.borrow().clone();
175 source.index_of(item)
176 }
177
178 pub fn get_or_create(items: Option<&ItemsSource>) -> Rc<ItemsSourceView> {
183 match items {
184 None => Self::empty(),
185 Some(items) => items
186 .downcast_ref::<Self>()
187 .and_then(|view| view.this.upgrade())
188 .unwrap_or_else(|| Self::new(items.clone())),
189 }
190 }
191
192 pub fn get_or_create_of<T: PropertyValue>(items: Option<&ItemsSource>) -> ItemsSourceViewOf<T> {
194 match items {
195 None => ItemsSourceViewOf::empty(),
196 Some(items) => ItemsSourceViewOf::new(items.clone()),
197 }
198 }
199
200 pub fn iter(&self) -> impl Iterator<Item = Option<BoxedValue>> {
202 let source = self.source();
203 let mut index = 0;
204 std::iter::from_fn(move || {
205 if index < source.count() {
206 index += 1;
207 Some(source.get_at(index - 1))
208 } else {
209 None
210 }
211 })
212 }
213
214 pub fn to_vec(&self) -> Vec<Option<BoxedValue>> {
216 self.source().to_vec()
217 }
218
219 pub(crate) fn raise_collection_changed(&self, e: &ItemsChangedEventArgs<'_>) {
220 Self::invoke(&self.pre_collection_changed, e);
221 Self::invoke(&self.collection_changed, e);
222 Self::invoke(&self.post_collection_changed, e);
223 }
224
225 pub(crate) fn set_source(&self, source: ItemsSource) {
226 let listener: Weak<dyn ICollectionChangedListener> = self.this.clone();
227
228 if self.listening.get() {
229 let old = self.source();
230 if old.is_notifying() {
231 CollectionChangedEventManager::remove_listener(&old, &listener);
232 }
233 }
234
235 *self.source.borrow_mut() = source.clone();
236
237 if self.listening.get() && source.is_notifying() {
238 CollectionChangedEventManager::add_listener(&source, listener);
239 }
240 }
241
242 fn add_listener_if_necessary(&self) {
243 if !self.listening.get() {
244 let source = self.source();
245 if source.is_notifying() {
246 CollectionChangedEventManager::add_listener(&source, self.this.clone());
247 }
248 self.listening.set(true);
249 }
250 }
251
252 fn remove_listener_if_necessary(&self) {
253 if self.listening.get() && self.collection_changed.is_empty() && self.post_collection_changed.is_empty() {
254 let source = self.source();
255 if source.is_notifying() {
256 let listener: Weak<dyn ICollectionChangedListener> = self.this.clone();
257 CollectionChangedEventManager::remove_listener(&source, &listener);
258 }
259 self.listening.set(false);
260 }
261 }
262
263 #[inline]
264 fn invoke(handlers: &HandlerList<ItemsChangedHandler>, e: &ItemsChangedEventArgs<'_>) {
265 if !handlers.is_empty() {
266 for (_, handler) in handlers.snapshot().iter() {
267 handler(e);
268 }
269 }
270 }
271}
272
273impl IItemsList for ItemsSourceView {
278 fn key_index_mapping(&self) -> Option<&dyn crate::IKeyIndexMapping> {
279 self.has_key_index_mapping().then_some(self as &dyn crate::IKeyIndexMapping)
280 }
281
282 fn count(&self) -> usize {
283 ItemsSourceView::count(self)
284 }
285
286 fn get_at(&self, index: usize) -> Option<BoxedValue> {
287 ItemsSourceView::get_at(self, index)
288 }
289
290 fn index_of(&self, item: &Option<BoxedValue>) -> i32 {
291 ItemsSourceView::index_of(self, item)
292 }
293
294 fn is_notifying(&self) -> bool {
295 self.source().is_notifying()
296 }
297
298 fn add_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> Option<u64> {
299 self.is_notifying().then(|| ItemsSourceView::add_collection_changed(self, handler))
300 }
301
302 fn remove_collection_changed(&self, token: u64) {
303 ItemsSourceView::remove_collection_changed(self, token);
304 }
305
306 fn as_any(&self) -> &dyn std::any::Any {
307 self
308 }
309}
310
311impl crate::IKeyIndexMapping for ItemsSourceView {
312 fn key_from_index(&self, index: i32) -> String {
313 ItemsSourceView::key_from_index(self, index)
314 }
315
316 fn index_from_key(&self, key: &str) -> i32 {
317 ItemsSourceView::index_from_key(self, key)
318 }
319}
320
321impl ICollectionChangedListener for ItemsSourceView {
322 fn pre_changed(&self, e: &ItemsChangedEventArgs<'_>) {
323 Self::invoke(&self.pre_collection_changed, e);
324 }
325
326 fn changed(&self, e: &ItemsChangedEventArgs<'_>) {
327 Self::invoke(&self.collection_changed, e);
328 }
329
330 fn post_changed(&self, e: &ItemsChangedEventArgs<'_>) {
331 Self::invoke(&self.post_collection_changed, e);
332 }
333}
334
335pub struct ItemsSourceViewOf<T: PropertyValue> {
339 view: Rc<ItemsSourceView>,
340 marker: PhantomData<fn() -> T>,
341}
342
343impl<T: PropertyValue> Clone for ItemsSourceViewOf<T> {
344 fn clone(&self) -> Self {
345 Self { view: self.view.clone(), marker: PhantomData }
346 }
347}
348
349impl<T: PropertyValue> Deref for ItemsSourceViewOf<T> {
350 type Target = ItemsSourceView;
351
352 fn deref(&self) -> &ItemsSourceView {
353 &self.view
354 }
355}
356
357impl<T: PropertyValue> ItemsSourceViewOf<T> {
358 pub fn empty() -> Self {
360 Self { view: ItemsSourceView::empty(), marker: PhantomData }
361 }
362
363 pub fn new(source: ItemsSource) -> Self {
365 Self { view: ItemsSourceView::new(source), marker: PhantomData }
366 }
367
368 pub fn from_view(view: &ItemsSourceView) -> Self {
370 Self::new(view.source())
371 }
372
373 pub fn view(&self) -> &Rc<ItemsSourceView> {
375 &self.view
376 }
377
378 pub fn get_at(&self, index: usize) -> Option<T> {
381 let item = self.view.get_at(index);
382 if item.is_none() {
383 return None;
384 }
385 match unbox_item::<T>(&item) {
386 Some(value) => Some(value),
387 None => panic!("Unable to cast the item to type '{}'.", std::any::type_name::<T>()),
388 }
389 }
390
391 pub fn iter(&self) -> impl Iterator<Item = Option<T>> + '_ {
393 let mut index = 0;
394 std::iter::from_fn(move || {
395 if index < self.view.count() {
396 index += 1;
397 Some(self.get_at(index - 1))
398 } else {
399 None
400 }
401 })
402 }
403}