using System;
using System.Collections.Generic;
using JD.Application.View.TrackItems;
using JD.Audio.Annotations;
using JD.Collections;
using JD.Collections.Extensions;
using JD.Sequencers.Controls;
using TeaBox;
namespace JD.Application.View.Tracks
{
///
/// Responsible of creating a track item corresponding to each item (model) in the provided collection.
///
public class TrackItemSynchronizer
where TModel : EditableAnnotation
where TView : AnnotationTrackItem
{
#region Variables
private readonly Dictionary _modelToViewDictionary = new Dictionary();
private readonly Converter _createViewFromModel;
private readonly Predicate _includeModel;
private readonly Track _view;
private readonly IAnnotationList _annotationCollection;
#endregion
#region Constructor
///
/// Constructor
///
public TrackItemSynchronizer(Track view, IAnnotationList annotationCollection, Converter createViewFromModel, Predicate includeModel)
{
_view = view;
_createViewFromModel = createViewFromModel;
_includeModel = includeModel ?? (model => true);
_annotationCollection = annotationCollection;
_annotationCollection.CollectionChanged += model_CollectionChanged;
_annotationCollection.ForEach(model => Register(model));
}
#endregion
#region Methods
private TView Register(TModel model)
{
TView view = null;
if (_includeModel(model))
{
view = _createViewFromModel(model);
view.ParentCollection = _annotationCollection;
_modelToViewDictionary.Add(model, view);
_view.Children.Add(view);
_view.Invalidate();
}
return view;
}
private void Unregister(TModel model)
{
TView view;
if (_modelToViewDictionary.TryGetValue(model, out view) && view != null)
{
if (view.Selected)
{
_view.TrackView.Selection.Remove(view);
}
_modelToViewDictionary.Remove(model);
_view.Children.Remove(view);
_view.Invalidate();
}
}
///
/// Each time the source collection is modified, the corresponding items are added and removed.
///
private void model_CollectionChanged(object sender, CollectionChangedEventArgs e)
{
if (e.Action == CollectionChangeAction.ItemChanged)
{
TView view;
bool contains = _modelToViewDictionary.TryGetValue(e.Item, out view);
if (contains)
{
view.Time = e.Item.Time;
}
// Happens when a comment change its type for example
if (contains != _includeModel(e.Item))
{
Unregister(e.Item);
view = Register(e.Item);
if (view != null)
{
// We assume that changing the type of the event implies that it was selected in the view
// so we restore it.
// For example, when using the arrow keys to change the track of annotations,
// this makes sure that the annotations are selected after chaning tracks.
_view.TrackView?.Selection.Add(view);
}
}
}
e.Synchronize(_annotationCollection, model => Register(model), Unregister);
if (e.Action == CollectionChangeAction.ItemAdded && _includeModel(e.Item))
{
// On the adding of a new item, we select it.
_view.TrackView?.Selection.Select(_modelToViewDictionary[e.Item]);
}
}
#endregion
}
}