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 } }