300 lines
10 KiB
C#
300 lines
10 KiB
C#
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using JD.WPF.Models.Menus;
|
|
using JD.WPF.Utils;
|
|
|
|
namespace JD.WPF.Models
|
|
{
|
|
public abstract class HistoryNavigatorDataBase : DataModelBase
|
|
{
|
|
private double _buttonSize;
|
|
private bool _backMenuOpen;
|
|
private bool _forwardMenuOpen;
|
|
|
|
public HistoryNavigatorDataBase()
|
|
{
|
|
_buttonSize = 24.0;
|
|
_backMenuOpen = false;
|
|
_forwardMenuOpen = false;
|
|
BackMenus = new MenuItemDataCollection();
|
|
ForwardMenus = new MenuItemDataCollection();
|
|
}
|
|
|
|
public double ButtonSize
|
|
{
|
|
get { return _buttonSize; }
|
|
set
|
|
{
|
|
if (Math.Abs(_buttonSize - value) > float.Epsilon)
|
|
{
|
|
_buttonSize = value;
|
|
RaisePropertyChanged("ButtonSize");
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool BackMenuOpen
|
|
{
|
|
get { return _backMenuOpen; }
|
|
set
|
|
{
|
|
if (_backMenuOpen != value)
|
|
{
|
|
_backMenuOpen = value;
|
|
RaisePropertyChanged("BackMenuOpen");
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool ForwardMenuOpen
|
|
{
|
|
get { return _forwardMenuOpen; }
|
|
set
|
|
{
|
|
if (_forwardMenuOpen != value)
|
|
{
|
|
_forwardMenuOpen = value;
|
|
RaisePropertyChanged("ForwardMenuOpen");
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract void Back();
|
|
public abstract void Back(object data);
|
|
public abstract void Forward();
|
|
public abstract void Forward(object data);
|
|
|
|
public MenuItemDataCollection BackMenus { get; }
|
|
public MenuItemDataCollection ForwardMenus { get; }
|
|
}
|
|
|
|
public class HistoryNavigatorData<HistoryDataType> : HistoryNavigatorDataBase
|
|
{
|
|
private bool _noPush;
|
|
|
|
private int _maxHistoryLength;
|
|
|
|
public HistoryNavigatorData()
|
|
: this(null, null, null)
|
|
{
|
|
}
|
|
|
|
public HistoryNavigatorData(
|
|
Func<HistoryDataType> getCurrentDataCallback,
|
|
Action<HistoryDataType> selectCurrentDataCallback,
|
|
Func<HistoryDataType, string> getDisplayNameCallback)
|
|
{
|
|
BackwardsCollection = new ObservableCollection<HistoryDataType>();
|
|
ForwardsCollection = new ObservableCollection<HistoryDataType>();
|
|
_noPush = false;
|
|
_maxHistoryLength = 30;
|
|
|
|
GetCurrentDataCallback = getCurrentDataCallback;
|
|
SelectCurrentDataCallback = selectCurrentDataCallback;
|
|
GetDisplayNameCallback = getDisplayNameCallback;
|
|
}
|
|
|
|
internal ObservableCollection<HistoryDataType> BackwardsCollection { get; }
|
|
|
|
internal ObservableCollection<HistoryDataType> ForwardsCollection { get; }
|
|
|
|
public Func<HistoryDataType> GetCurrentDataCallback { get; set; }
|
|
|
|
public Action<HistoryDataType> SelectCurrentDataCallback { get; set; }
|
|
|
|
public Func<HistoryDataType, string> GetDisplayNameCallback { get; set; }
|
|
|
|
public int MaxHistoryLength
|
|
{
|
|
get { return _maxHistoryLength; }
|
|
set
|
|
{
|
|
_maxHistoryLength = value;
|
|
ResizeLists();
|
|
}
|
|
}
|
|
|
|
public bool CanGoBack
|
|
{
|
|
get { return BackwardsCollection.Count > 0; }
|
|
}
|
|
|
|
public bool CanGoForward
|
|
{
|
|
get { return ForwardsCollection.Count > 0; }
|
|
}
|
|
|
|
public void Push(HistoryDataType obj)
|
|
{
|
|
if (_noPush)
|
|
return;
|
|
|
|
BackwardsCollection.Insert(0, obj);
|
|
ForwardsCollection.Clear();
|
|
RaisePropertyChanged("CanGoBack");
|
|
RaisePropertyChanged("CanGoForward");
|
|
ResizeLists();
|
|
UpdateMenus();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
BackwardsCollection.Clear();
|
|
ForwardsCollection.Clear();
|
|
RaisePropertyChanged("CanGoBack");
|
|
RaisePropertyChanged("CanGoForward");
|
|
UpdateMenus();
|
|
}
|
|
|
|
public override void Back()
|
|
{
|
|
if (!CanGoBack)
|
|
throw new InvalidOperationException("The back history is empty");
|
|
if (SelectCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which selects the object is not set. ");
|
|
if (GetCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which gets the currently selected object is not set");
|
|
|
|
HistoryDataType backObj = BackwardsCollection.First();
|
|
BackwardsCollection.RemoveAt(0);
|
|
ForwardsCollection.Insert(0, GetCurrentDataCallback());
|
|
_noPush = true;
|
|
SelectCurrentDataCallback(backObj);
|
|
_noPush = false;
|
|
ResizeLists();
|
|
UpdateMenus();
|
|
}
|
|
|
|
public override void Back(object data)
|
|
{
|
|
if (!(data is HistoryDataType))
|
|
throw new NotSupportedException("The type of the history data is not supported. ");
|
|
Back((HistoryDataType)data);
|
|
}
|
|
|
|
public void Back(HistoryDataType objectToSelect)
|
|
{
|
|
if (!CanGoBack)
|
|
throw new InvalidOperationException("The back history is empty");
|
|
if (SelectCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which selects the object is not set. ");
|
|
if (GetCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which gets the currently selected object is not set");
|
|
if (!BackwardsCollection.Contains(objectToSelect))
|
|
throw new InvalidOperationException("The object to select is not present in the history. ");
|
|
|
|
HistoryDataType backObj = BackwardsCollection.First();
|
|
HistoryDataType selectObj = GetCurrentDataCallback();
|
|
while (backObj != null)
|
|
{
|
|
BackwardsCollection.RemoveAt(0);
|
|
ForwardsCollection.Insert(0, selectObj);
|
|
|
|
if (backObj.Equals(objectToSelect))
|
|
break;
|
|
|
|
selectObj = backObj;
|
|
backObj = BackwardsCollection.First();
|
|
}
|
|
|
|
if (backObj == null)
|
|
throw new InvalidOperationException("An unexpected error occurred : Could not find the element in the history. ");
|
|
_noPush = true;
|
|
SelectCurrentDataCallback(backObj);
|
|
_noPush = false;
|
|
ResizeLists();
|
|
UpdateMenus();
|
|
}
|
|
|
|
public override void Forward()
|
|
{
|
|
if (!CanGoForward)
|
|
throw new InvalidOperationException("The forward history is empty");
|
|
if (SelectCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which selects the object is not set. ");
|
|
if (GetCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which gets the currently selected object is not set");
|
|
|
|
|
|
HistoryDataType forwardObj = ForwardsCollection.First();
|
|
ForwardsCollection.RemoveAt(0);
|
|
BackwardsCollection.Insert(0, GetCurrentDataCallback());
|
|
_noPush = true;
|
|
SelectCurrentDataCallback(forwardObj);
|
|
_noPush = false;
|
|
ResizeLists();
|
|
UpdateMenus();
|
|
}
|
|
|
|
public override void Forward(object data)
|
|
{
|
|
if (!(data is HistoryDataType))
|
|
throw new NotSupportedException("The type of the history data is not supported. ");
|
|
Forward((HistoryDataType)data);
|
|
}
|
|
|
|
public void Forward(HistoryDataType objectToSelect)
|
|
{
|
|
if (!CanGoForward)
|
|
throw new InvalidOperationException("The back history is empty");
|
|
if (SelectCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which selects the object is not set. ");
|
|
if (GetCurrentDataCallback == null)
|
|
throw new InvalidOperationException("The operation which gets the currently selected object is not set");
|
|
if (!ForwardsCollection.Contains(objectToSelect))
|
|
throw new InvalidOperationException("The object to select is not present in the history. ");
|
|
|
|
HistoryDataType forwardObj = ForwardsCollection.First();
|
|
HistoryDataType selectObj = GetCurrentDataCallback();
|
|
while (forwardObj != null)
|
|
{
|
|
ForwardsCollection.RemoveAt(0);
|
|
BackwardsCollection.Insert(0, selectObj);
|
|
|
|
if (forwardObj.Equals(objectToSelect))
|
|
break;
|
|
|
|
selectObj = forwardObj;
|
|
forwardObj = ForwardsCollection.First();
|
|
}
|
|
|
|
if (forwardObj == null)
|
|
throw new InvalidOperationException("An unexpected error occurred : Could not find the element in the history. ");
|
|
_noPush = true;
|
|
SelectCurrentDataCallback(forwardObj);
|
|
_noPush = false;
|
|
ResizeLists();
|
|
UpdateMenus();
|
|
}
|
|
|
|
private void UpdateMenus()
|
|
{
|
|
RaisePropertyChanged("CanGoBack");
|
|
RaisePropertyChanged("CanGoForward");
|
|
|
|
BackMenuOpen = false;
|
|
ForwardMenuOpen = false;
|
|
BackMenus.Clear();
|
|
ForwardMenus.Clear();
|
|
|
|
foreach (HistoryDataType data in BackwardsCollection)
|
|
{
|
|
BackMenus.Add(new MenuItemData(GetDisplayNameCallback(data), null, command: new RelayCommand<HistoryDataType>(Back), data: data));
|
|
}
|
|
|
|
foreach (HistoryDataType data in ForwardsCollection)
|
|
{
|
|
ForwardMenus.Add(new MenuItemData(GetDisplayNameCallback(data), null, command: new RelayCommand<HistoryDataType>(Forward), data: data));
|
|
}
|
|
}
|
|
|
|
private void ResizeLists()
|
|
{
|
|
while (BackwardsCollection.Count > _maxHistoryLength)
|
|
BackwardsCollection.RemoveAt(BackwardsCollection.Count - 1);
|
|
while (ForwardsCollection.Count > _maxHistoryLength)
|
|
ForwardsCollection.RemoveAt(ForwardsCollection.Count - 1);
|
|
}
|
|
}
|
|
}
|