ferroui_dynamic_data/binding/
observable_collection_extended.rs1use super::{IObservableCollection, INotifyCollectionChangedSuspender};
4use crate::list::{IExtendedList, IList};
5use ferroui_reactive::disposables::Disposable;
6use ferroui_system::collections::object_model::{CollectionChangedHandler, ObservableCollection};
7use ferroui_system::collections::specialized::{CollectionChange, INotifyCollectionChanged, NotifyCollectionChangedAction};
8use ferroui_system::component_model::INotifyPropertyChanged;
9use ferroui_system::events::Event;
10use ferroui_system::IDisposable;
11use std::cell::{Cell, Ref};
12use std::fmt;
13use std::rc::Rc;
14
15const COUNT_NAME: &str = "Count";
17const INDEXER_NAME: &str = "Item[]";
19
20struct SuspendState {
21 suspend_count: Cell<bool>,
23 suspend_notifications: Cell<bool>,
25}
26
27pub struct ObservableCollectionExtended<T> {
39 collection: ObservableCollection<T>,
40 state: Rc<SuspendState>,
41}
42
43impl<T> Clone for ObservableCollectionExtended<T> {
44 fn clone(&self) -> Self {
45 Self { collection: self.collection.clone(), state: self.state.clone() }
46 }
47}
48
49impl<T> PartialEq for ObservableCollectionExtended<T> {
50 fn eq(&self, other: &Self) -> bool {
52 Rc::ptr_eq(&self.state, &other.state)
53 }
54}
55
56impl<T: Clone + PartialEq + 'static> Default for ObservableCollectionExtended<T> {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl<T: Clone + PartialEq + fmt::Debug + 'static> fmt::Debug for ObservableCollectionExtended<T> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_list().entries(self.collection.items().iter()).finish()
65 }
66}
67
68impl<T: Clone + PartialEq + 'static> ObservableCollectionExtended<T> {
69 pub fn new() -> Self {
71 Self::from_items(Vec::new())
72 }
73
74 pub fn with_capacity(capacity: usize) -> Self {
77 Self::from_items(Vec::with_capacity(capacity))
78 }
79
80 pub fn from_items(items: Vec<T>) -> Self {
83 Self {
84 collection: ObservableCollection::from_items(items),
85 state: Rc::new(SuspendState { suspend_count: Cell::new(false), suspend_notifications: Cell::new(false) }),
86 }
87 }
88
89 pub fn collection(&self) -> &ObservableCollection<T> {
91 &self.collection
92 }
93
94 pub fn ptr_eq(&self, other: &Self) -> bool {
96 Rc::ptr_eq(&self.state, &other.state)
97 }
98
99 pub fn add_collection_changed(&self, handler: Rc<CollectionChangedHandler<T>>) -> u64 {
102 self.collection.add_collection_changed(handler)
103 }
104
105 pub fn remove_collection_changed(&self, token: u64) -> bool {
107 self.collection.remove_collection_changed(token)
108 }
109
110 pub fn count(&self) -> usize {
112 self.collection.count()
113 }
114
115 pub fn is_empty(&self) -> bool {
116 self.collection.is_empty()
117 }
118
119 pub fn get(&self, index: usize) -> T {
121 self.collection.get(index)
122 }
123
124 pub fn items(&self) -> Ref<'_, Vec<T>> {
126 self.collection.items()
127 }
128
129 pub fn to_vec(&self) -> Vec<T> {
131 self.collection.to_vec()
132 }
133
134 pub fn contains(&self, item: &T) -> bool {
136 self.collection.contains(item)
137 }
138
139 pub fn index_of(&self, item: &T) -> Option<usize> {
141 self.collection.index_of(item)
142 }
143
144 pub fn add(&self, item: T) {
146 let index = self.count();
147 self.insert(index, item);
148 }
149
150 pub fn insert(&self, index: usize, item: T) {
152 self.collection.check_reentrancy();
153 self.collection.items_mut_silent().insert(index, item.clone());
154 self.on_property_changed(COUNT_NAME);
155 self.on_property_changed(INDEXER_NAME);
156 self.on_collection_changed(NotifyCollectionChangedAction::Add, std::slice::from_ref(&item), &[], index as i32, -1);
157 }
158
159 pub fn set(&self, index: usize, item: T) {
161 self.collection.check_reentrancy();
162 let original = std::mem::replace(&mut self.collection.items_mut_silent()[index], item.clone());
163 self.on_property_changed(INDEXER_NAME);
164 self.on_collection_changed(NotifyCollectionChangedAction::Replace, std::slice::from_ref(&item), std::slice::from_ref(&original), index as i32, index as i32);
165 }
166
167 pub fn remove_at(&self, index: usize) {
169 self.collection.check_reentrancy();
170 let removed = self.collection.items_mut_silent().remove(index);
171 self.on_property_changed(COUNT_NAME);
172 self.on_property_changed(INDEXER_NAME);
173 self.on_collection_changed(NotifyCollectionChangedAction::Remove, &[], std::slice::from_ref(&removed), -1, index as i32);
174 }
175
176 pub fn remove(&self, item: &T) -> bool {
178 match self.index_of(item) {
179 Some(index) => {
180 self.remove_at(index);
181 true
182 }
183 None => false,
184 }
185 }
186
187 pub fn move_item(&self, old_index: usize, new_index: usize) {
189 self.collection.check_reentrancy();
190 let item = {
191 let mut items = self.collection.items_mut_silent();
192 let item = items.remove(old_index);
193 items.insert(new_index, item.clone());
194 item
195 };
196 self.on_property_changed(INDEXER_NAME);
197 self.on_collection_changed(NotifyCollectionChangedAction::Move, std::slice::from_ref(&item), std::slice::from_ref(&item), new_index as i32, old_index as i32);
198 }
199
200 pub fn clear(&self) {
202 self.collection.check_reentrancy();
203 self.collection.items_mut_silent().clear();
204 self.on_property_changed(COUNT_NAME);
205 self.on_property_changed(INDEXER_NAME);
206 self.on_collection_changed(NotifyCollectionChangedAction::Reset, &[], &[], -1, -1);
207 }
208
209 pub fn add_range(&self, items: impl IntoIterator<Item = T>) {
211 for item in items {
212 self.add(item);
213 }
214 }
215
216 pub fn insert_range(&self, items: impl IntoIterator<Item = T>, index: usize) {
218 for (offset, item) in items.into_iter().enumerate() {
219 self.insert(index + offset, item);
220 }
221 }
222
223 pub fn load(&self, items: impl IntoIterator<Item = T>) {
225 self.collection.check_reentrancy();
226 self.clear();
227 for item in items {
228 self.add(item);
229 }
230 }
231
232 pub fn remove_range(&self, index: usize, count: usize) {
234 for _ in 0..count {
235 self.remove_at(index);
236 }
237 }
238
239 pub fn suspend_count(&self) -> Rc<dyn IDisposable> {
242 let count = self.count();
243 self.state.suspend_count.set(true);
244 let this = self.clone();
245 Disposable::create(move || {
246 this.state.suspend_count.set(false);
247 if this.count() != count {
248 this.on_property_changed(COUNT_NAME);
249 }
250 })
251 }
252
253 pub fn suspend_notifications(&self) -> Rc<dyn IDisposable> {
256 self.state.suspend_count.set(true);
257 self.state.suspend_notifications.set(true);
258 let this = self.clone();
259 Disposable::create(move || {
260 this.state.suspend_count.set(false);
261 this.state.suspend_notifications.set(false);
262 this.on_property_changed(COUNT_NAME);
263 this.on_collection_changed(NotifyCollectionChangedAction::Reset, &[], &[], -1, -1);
264 })
265 }
266
267 pub fn on_property_changed(&self, name: &str) {
270 if self.state.suspend_count.get() && name == COUNT_NAME {
271 return;
272 }
273 self.collection.on_property_changed(name);
274 }
275
276 pub fn on_collection_changed(&self, action: NotifyCollectionChangedAction, new_items: &[T], old_items: &[T], new_starting_index: i32, old_starting_index: i32) {
278 if self.state.suspend_notifications.get() {
279 return;
280 }
281 self.collection.on_collection_changed(action, new_items, old_items, new_starting_index, old_starting_index);
282 }
283}
284
285impl<T> INotifyCollectionChanged for ObservableCollectionExtended<T> {
286 fn collection_changed(&self) -> &Event<CollectionChange> {
287 self.collection.collection_changed()
288 }
289}
290
291impl<T> INotifyPropertyChanged for ObservableCollectionExtended<T> {
292 fn property_changed(&self) -> &Event<str> {
293 self.collection.property_changed()
294 }
295}
296
297impl<T: Clone + PartialEq + 'static> INotifyCollectionChangedSuspender for ObservableCollectionExtended<T> {
298 fn suspend_count(&self) -> Rc<dyn IDisposable> {
299 ObservableCollectionExtended::suspend_count(self)
300 }
301
302 fn suspend_notifications(&self) -> Rc<dyn IDisposable> {
303 ObservableCollectionExtended::suspend_notifications(self)
304 }
305}
306
307impl<T: Clone + PartialEq + 'static> IObservableCollection<T> for ObservableCollectionExtended<T> {
308 fn count(&self) -> usize {
309 ObservableCollectionExtended::count(self)
310 }
311
312 fn get(&self, index: usize) -> T {
313 ObservableCollectionExtended::get(self, index)
314 }
315
316 fn set(&self, index: usize, item: T) {
317 ObservableCollectionExtended::set(self, index, item);
318 }
319
320 fn insert(&self, index: usize, item: T) {
321 ObservableCollectionExtended::insert(self, index, item);
322 }
323
324 fn remove_at(&self, index: usize) {
325 ObservableCollectionExtended::remove_at(self, index);
326 }
327
328 fn clear(&self) {
329 ObservableCollectionExtended::clear(self);
330 }
331
332 fn to_vec(&self) -> Vec<T> {
333 ObservableCollectionExtended::to_vec(self)
334 }
335
336 fn add(&self, item: T) {
337 ObservableCollectionExtended::add(self, item);
338 }
339
340 fn index_of(&self, item: &T) -> Option<usize> {
341 ObservableCollectionExtended::index_of(self, item)
342 }
343
344 fn remove(&self, item: &T) -> bool {
345 ObservableCollectionExtended::remove(self, item)
346 }
347
348 fn load(&self, items: Vec<T>) {
349 ObservableCollectionExtended::load(self, items);
350 }
351
352 fn move_item(&self, old_index: usize, new_index: usize) {
353 ObservableCollectionExtended::move_item(self, old_index, new_index);
354 }
355
356 fn clone_changes(&self, changes: &crate::list::ChangeSet<T>) {
358 crate::list::clone_changes(&mut self.clone(), changes);
359 }
360}
361
362impl<T: Clone + PartialEq + 'static> IList<T> for ObservableCollectionExtended<T> {
365 fn count(&self) -> usize {
366 ObservableCollectionExtended::count(self)
367 }
368
369 fn get(&self, index: usize) -> T {
370 ObservableCollectionExtended::get(self, index)
371 }
372
373 fn set(&mut self, index: usize, item: T) {
374 ObservableCollectionExtended::set(self, index, item);
375 }
376
377 fn insert(&mut self, index: usize, item: T) {
378 ObservableCollectionExtended::insert(self, index, item);
379 }
380
381 fn remove_at(&mut self, index: usize) {
382 ObservableCollectionExtended::remove_at(self, index);
383 }
384
385 fn clear(&mut self) {
386 ObservableCollectionExtended::clear(self);
387 }
388
389 fn add(&mut self, item: T) {
390 ObservableCollectionExtended::add(self, item);
391 }
392
393 fn index_of(&self, item: &T) -> Option<usize> {
394 ObservableCollectionExtended::index_of(self, item)
395 }
396
397 fn remove(&mut self, item: &T) -> bool {
398 ObservableCollectionExtended::remove(self, item)
399 }
400
401 fn add_range(&mut self, items: Vec<T>) {
402 ObservableCollectionExtended::add_range(self, items);
403 }
404
405 fn add_or_insert_range(&mut self, items: Vec<T>, index: Option<usize>) {
406 match index {
407 Some(index) => ObservableCollectionExtended::insert_range(self, items, index),
408 None => ObservableCollectionExtended::add_range(self, items),
409 }
410 }
411
412 fn remove_range(&mut self, index: usize, count: usize) {
413 ObservableCollectionExtended::remove_range(self, index, count);
414 }
415
416 fn supports_ranges(&self) -> bool {
417 true
418 }
419
420 fn move_item(&mut self, original: usize, destination: usize) {
421 ObservableCollectionExtended::move_item(self, original, destination);
422 }
423}
424
425impl<T: Clone + PartialEq + 'static> IExtendedList<T> for ObservableCollectionExtended<T> {
426 fn insert_range(&mut self, items: Vec<T>, index: usize) {
427 ObservableCollectionExtended::insert_range(self, items, index);
428 }
429
430 fn move_index(&mut self, original: usize, destination: usize) {
431 ObservableCollectionExtended::move_item(self, original, destination);
432 }
433}