use super::TreeNode;
use ferroui_base::collections::{CollectionChangedHandler, FerroList, IFerroReadOnlyList};
use ferroui_base::data::model::{CollectionChange, Event, INotifyCollectionChanged, INotifyPropertyChanged};
use ferroui_base::{ferro_markup_type, BoxedValue};
use ferroui_controls::{IItemsList, ItemsChangedHandler};
use ferroui_treedatagrid_core::model_collection::{ModelCollection, ModelsChangedHandler};
use std::any::Any;
use std::cell::OnceCell;
use std::rc::{Rc, Weak};
pub trait TreeNodeCollectionImpl {
fn initialize(&self, this: &TreeNodeCollection, nodes: &FerroList<Rc<TreeNode>>);
fn dispose(&self, this: &TreeNodeCollection) {
this.base_dispose();
}
}
pub struct TreeNodeCollection {
this: Weak<TreeNodeCollection>,
owner: Weak<TreeNode>,
inner: OnceCell<FerroList<Rc<TreeNode>>>,
kind: Box<dyn TreeNodeCollectionImpl>,
}
struct EmptyTreeNodeCollection;
impl TreeNodeCollectionImpl for EmptyTreeNodeCollection {
fn initialize(&self, _this: &TreeNodeCollection, _nodes: &FerroList<Rc<TreeNode>>) {}
}
ferroui_base::ferro_thread_local! {
static EMPTY: Rc<TreeNodeCollection> = TreeNodeCollection::new(Weak::new(), Box::new(EmptyTreeNodeCollection));
}
impl PartialEq for TreeNodeCollection {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
}
}
impl TreeNodeCollection {
pub fn new(owner: Weak<TreeNode>, kind: Box<dyn TreeNodeCollectionImpl>) -> Rc<Self> {
Rc::new_cyclic(|this| Self { this: this.clone(), owner, inner: OnceCell::new(), kind })
}
pub(crate) fn to_rc(&self) -> Rc<TreeNodeCollection> {
self.this.upgrade().expect("the collection is alive while it is used")
}
pub fn empty() -> Rc<TreeNodeCollection> {
EMPTY.with(Rc::clone)
}
pub fn get(&self, index: usize) -> Rc<TreeNode> {
self.ensure_initialized().get(index)
}
pub fn count(&self) -> usize {
self.ensure_initialized().count()
}
pub fn owner(&self) -> Option<Rc<TreeNode>> {
self.owner.upgrade()
}
pub fn dispose(&self) {
self.kind.dispose(self);
}
pub fn base_dispose(&self) {
if let Some(inner) = self.inner.get() {
for node in inner.snapshot().iter() {
node.dispose();
}
}
}
pub fn is_initialized(&self) -> bool {
self.inner.get().is_some()
}
pub fn to_vec(&self) -> Vec<Rc<TreeNode>> {
self.ensure_initialized().to_vec()
}
pub fn contains(&self, node: &Rc<TreeNode>) -> bool {
self.ensure_initialized().contains(node)
}
pub fn index_of(&self, node: &Rc<TreeNode>) -> i32 {
self.ensure_initialized().index_of(node).map_or(-1, |index| index as i32)
}
fn ensure_initialized(&self) -> &FerroList<Rc<TreeNode>> {
if self.inner.get().is_none() {
let nodes = FerroList::new();
let _ = self.inner.set(nodes.clone());
self.kind.initialize(self, &nodes);
}
self.inner.get().expect("the nodes were just created")
}
}
impl INotifyCollectionChanged for TreeNodeCollection {
fn collection_changed(&self) -> &Event<CollectionChange> {
self.ensure_initialized().collection_changed()
}
}
impl INotifyPropertyChanged for TreeNodeCollection {
fn property_changed(&self) -> &Event<str> {
self.ensure_initialized().property_changed()
}
}
impl IFerroReadOnlyList<Rc<TreeNode>> for TreeNodeCollection {
fn count(&self) -> usize {
TreeNodeCollection::count(self)
}
fn get(&self, index: usize) -> Rc<TreeNode> {
TreeNodeCollection::get(self, index)
}
fn snapshot(&self) -> Rc<Vec<Rc<TreeNode>>> {
self.ensure_initialized().snapshot()
}
fn add_collection_changed(&self, handler: Rc<CollectionChangedHandler<Rc<TreeNode>>>) -> u64 {
self.ensure_initialized().add_collection_changed(handler)
}
fn remove_collection_changed(&self, token: u64) -> bool {
self.ensure_initialized().remove_collection_changed(token)
}
}
impl IItemsList for TreeNodeCollection {
fn count(&self) -> usize {
TreeNodeCollection::count(self)
}
fn get_at(&self, index: usize) -> Option<BoxedValue> {
<FerroList<Rc<TreeNode>> as IItemsList>::get_at(self.ensure_initialized(), index)
}
fn index_of(&self, item: &Option<BoxedValue>) -> i32 {
<FerroList<Rc<TreeNode>> as IItemsList>::index_of(self.ensure_initialized(), item)
}
fn is_notifying(&self) -> bool {
true
}
fn add_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> Option<u64> {
<FerroList<Rc<TreeNode>> as IItemsList>::add_collection_changed(self.ensure_initialized(), handler)
}
fn remove_collection_changed(&self, token: u64) {
<FerroList<Rc<TreeNode>> as IItemsList>::remove_collection_changed(self.ensure_initialized(), token);
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ModelCollection<TreeNode> for TreeNodeCollection {
fn count(&self) -> usize {
TreeNodeCollection::count(self)
}
fn get(&self, index: usize) -> Rc<TreeNode> {
TreeNodeCollection::get(self, index)
}
fn index_of(&self, model: &Rc<TreeNode>) -> Option<usize> {
self.ensure_initialized().index_of(model)
}
fn add_collection_changed(&self, handler: Rc<ModelsChangedHandler<TreeNode>>) -> Option<u64> {
Some(self.ensure_initialized().add_collection_changed(handler))
}
fn remove_collection_changed(&self, token: u64) {
self.ensure_initialized().remove_collection_changed(token);
}
fn is_notifying(&self) -> bool {
true
}
fn to_vec(&self) -> Vec<Rc<TreeNode>> {
TreeNodeCollection::to_vec(self)
}
}
ferro_markup_type!(class TreeNodeCollection {
this: Rc<TreeNodeCollection>,
handles: [TreeNodeCollection, Rc<TreeNodeCollection>, Option<Rc<TreeNodeCollection>>],
properties: [
Count: i32 { get: |this: &Rc<TreeNodeCollection>| this.count() as i32 },
],
});