// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections;
using System.Collections.Generic;
using Perspex.Controls.Templates;
namespace Perspex.Controls.Generators
{
///
/// Creates containers for tree items and maintains a list of created containers.
///
/// The type of the container.
public class TreeItemContainerGenerator : ItemContainerGenerator, ITreeItemContainerGenerator
where T : class, IControl, new()
{
private Dictionary _itemToContainer;
private Dictionary _containerToItem;
///
/// Initializes a new instance of the class.
///
/// The owner control.
/// The container's Content property.
/// The container's Items property.
/// The container's IsExpanded property.
///
/// The item container for the root of the tree, or null if this generator is itself the
/// root of the tree.
///
public TreeItemContainerGenerator(
IControl owner,
PerspexProperty contentProperty,
PerspexProperty itemsProperty,
PerspexProperty isExpandedProperty,
ITreeItemContainerGenerator rootGenerator)
: base(owner, contentProperty)
{
ItemsProperty = itemsProperty;
IsExpandedProperty = isExpandedProperty;
RootGenerator = rootGenerator;
if (rootGenerator == null)
{
_itemToContainer = new Dictionary();
_containerToItem = new Dictionary();
}
}
///
/// Gets the item container for the root of the tree, or null if this generator is itself
/// the root of the tree.
///
public ITreeItemContainerGenerator RootGenerator { get; }
///
/// Gets the item container's Items property.
///
protected PerspexProperty ItemsProperty { get; }
///
/// Gets the item container's IsExpanded property.
///
protected PerspexProperty IsExpandedProperty { get; }
///
/// Gets the item container for the specified item, anywhere in the tree.
///
/// The item.
/// The container, or null if not found.
public IControl TreeContainerFromItem(object item)
{
T result;
_itemToContainer.TryGetValue(item, out result);
return result;
}
///
/// Gets the item for the specified item container, anywhere in the tree.
///
/// The container.
/// The item, or null if not found.
public object TreeItemFromContainer(IControl container)
{
object result;
_containerToItem.TryGetValue(container, out result);
return result;
}
///
protected override IControl CreateContainer(object item)
{
var container = item as T;
if (item == null)
{
return null;
}
else if (container != null)
{
return container;
}
else
{
var template = GetTreeDataTemplate(item);
var result = new T();
result.SetValue(ContentProperty, template.Build(item));
result.SetValue(ItemsProperty, template.ItemsSelector(item));
result.SetValue(IsExpandedProperty, template.IsExpanded(item));
if (!(item is IControl))
{
result.DataContext = item;
}
AddToIndex(item, result);
return result;
}
}
public override IList ClearContainers()
{
ClearIndex();
return base.ClearContainers();
}
public override IList RemoveContainers(int startingIndex, int count)
{
RemoveFromIndex(GetContainerRange(startingIndex, count));
return base.RemoveContainers(startingIndex, count);
}
private void AddToIndex(object item, T container)
{
if (RootGenerator != null)
{
((TreeItemContainerGenerator)RootGenerator).AddToIndex(item, container);
}
else
{
_itemToContainer.Add(item, container);
_containerToItem.Add(container, item);
}
}
private void RemoveFromIndex(IEnumerable containers)
{
if (RootGenerator != null)
{
((TreeItemContainerGenerator)RootGenerator).RemoveFromIndex(containers);
}
else
{
foreach (var container in containers)
{
var item = _containerToItem[container];
_containerToItem.Remove(container);
_itemToContainer.Remove(item);
}
}
}
private void ClearIndex()
{
if (RootGenerator != null)
{
((TreeItemContainerGenerator)RootGenerator).ClearIndex();
}
else
{
_containerToItem.Clear();
_itemToContainer.Clear();
}
}
///
/// Gets the data template for the specified item.
///
/// The item.
/// The template.
private ITreeDataTemplate GetTreeDataTemplate(object item)
{
IDataTemplate template = Owner.FindDataTemplate(item);
if (template == null)
{
template = FuncDataTemplate.Default;
}
var treeTemplate = template as ITreeDataTemplate;
if (treeTemplate == null)
{
treeTemplate = new FuncTreeDataTemplate(typeof(object), template.Build, x => null);
}
return treeTemplate;
}
}
}