// -----------------------------------------------------------------------
//
// Copyright 2015 MIT Licence. See licence.md for more information.
//
// -----------------------------------------------------------------------
namespace Perspex.Controls.Generators
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Subjects;
using Perspex.Controls.Templates;
///
/// Creates containers for tree items and maintains a list of created containers.
///
/// The type of the container.
public class TreeItemContainerGenerator : ITreeItemContainerGenerator where T : TreeViewItem, new()
{
private Dictionary containers = new Dictionary();
private Subject containersInitialized = new Subject();
///
/// Initializes a new instance of the class.
///
/// The owner control.
public TreeItemContainerGenerator(IControl owner)
{
this.Owner = owner;
}
///
/// Signalled whenever new containers are initialized.
///
public IObservable ContainersInitialized => this.containersInitialized;
///
/// Gets the owner control.
///
public IControl Owner { get; }
///
/// Creates container controls for a collection of items.
///
///
/// The index of the first item of the data in the containing collection.
///
/// The items.
/// An optional item template.
/// The created container controls.
public IList CreateContainers(int startingIndex, IEnumerable items, IDataTemplate itemTemplate)
{
Contract.Requires(items != null);
int index = startingIndex;
var result = new List();
foreach (var item in items)
{
var container = this.CreateContainer(item, itemTemplate);
this.containers.Add(item, container);
result.Add(container);
}
this.containersInitialized.OnNext(new ItemContainers(startingIndex, result));
return result.Where(x => x != null).ToList();
}
///
/// Removes a set of created containers from the index and returns the removed controls.
///
///
/// The index of the first item of the data in the containing collection.
///
/// The items.
/// The removed controls.
public IList RemoveContainers(int startingIndex, IEnumerable items)
{
var result = new List();
foreach (var item in items)
{
T container;
if (this.containers.TryGetValue(item, out container))
{
this.Remove(container, result);
}
}
return result;
}
///
/// Clears the created containers from the index and returns the removed controls.
///
/// The removed controls.
public IList ClearContainers()
{
throw new NotImplementedException();
}
///
/// Gets the container control representing the item with the specified index.
///
/// The index.
/// The container or null if no container created.
public IControl ContainerFromIndex(int index)
{
throw new NotImplementedException();
}
///
/// Gets the index of the specified container control.
///
/// The container.
/// The index of the container or -1 if not found.
public int IndexFromContainer(IControl container)
{
throw new NotImplementedException();
}
///
/// Gets all of the generated container controls.
///
/// The containers.
public IEnumerable GetAllContainers()
{
return this.containers.Values;
}
///
/// Gets the item that is contained by the specified container.
///
/// The container.
/// The item.
public object ItemFromContainer(IControl container)
{
return container.DataContext;
}
///
/// Gets the container for the specified item
///
/// The item.
/// The container.
public IControl ContainerFromItem(object item)
{
T result;
this.containers.TryGetValue(item, out result);
return result;
}
///
/// Creates the container for an item.
///
/// The item.
/// An optional item template.
/// The created container control.
protected virtual T CreateContainer(object item, IDataTemplate itemTemplate)
{
T result = item as T;
if (result == null)
{
var template = this.GetTreeDataTemplate(item);
result = new T
{
Header = template.Build(item),
Items = template.ItemsSelector(item),
IsExpanded = template.IsExpanded(item),
DataContext = item,
};
}
return result;
}
///
/// Gets the data template for the specified item.
///
/// The item.
/// The template.
private ITreeDataTemplate GetTreeDataTemplate(object item)
{
IDataTemplate template = this.Owner.FindDataTemplate(item);
if (template == null)
{
template = DataTemplate.Default;
}
var treeTemplate = template as ITreeDataTemplate;
if (treeTemplate == null)
{
treeTemplate = new TreeDataTemplate(typeof(object), template.Build, x => null);
}
return treeTemplate;
}
private void Remove(T container, IList removed)
{
if (container.Items != null)
{
foreach (var childItem in container.Items)
{
T childContainer;
if (this.containers.TryGetValue(childItem, out childContainer))
{
this.Remove(childContainer, removed);
}
}
}
// TODO: Dual index.
var i = this.containers.FirstOrDefault(x => x.Value == container);
if (i.Key != null)
{
this.containers.Remove(i.Key);
}
}
}
}