Files
DP44/DataPRO/Modules/ISO/ExtraProperties/ViewModel/ExtraPropertiesListViewModel.cs

556 lines
19 KiB
C#
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading.Tasks;
using DTS.Common.Events;
using DTS.Common.Events.ISO;
using DTS.Common.Interactivity;
using DTS.Common.Interface;
using DTS.Common.Interface.ISO.ExtraProperties;
using ExtraProperties.Model;
using ExtraProperties.Resources;
using Prism.Events;
using Prism.Regions;
using Unity;
namespace ExtraProperties
{
[PartCreationPolicy(CreationPolicy.Shared)]
public class ExtraPropertiesListViewModel : IExtraPropertiesListViewModel
{
public IExtraPropertiesListView View { get; set; }
private IEventAggregator _eventAggregator { get; }
private IUnityContainer UnityContainer { get; }
public InteractionRequest<Notification> NotificationRequest { get; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
#region constructors and initializers
private static bool _bAddListeners = false;
/// <summary>
/// Creates a new instance of the ExtraPropertiesListViewModel
/// </summary>
/// <param name="view"></param>
/// <param name="regionManager">The logical placeholder defined within the application's UI (in the shell or within views) into which views are displayed.</param>
/// <param name="eventAggregator">The EventAggregator which allows different components to publish/subscribe to events without being coupled to each other.</param>
/// <param name="unityContainer">The unityContainer.</param>
public ExtraPropertiesListViewModel(IExtraPropertiesListView view, IRegionManager regionManager,
IEventAggregator eventAggregator, IUnityContainer unityContainer)
{
View = view;
View.DataContext = this;
NotificationRequest = new InteractionRequest<Notification>();
ConfirmationRequest = new InteractionRequest<Confirmation>();
_eventAggregator = eventAggregator;
UnityContainer = unityContainer;
_eventAggregator.GetEvent<RaiseNotification>().Subscribe(OnRaiseNotification);
_eventAggregator.GetEvent<BusyIndicatorChangeNotification>()
.Subscribe(OnBusyIndicatorNotification, ThreadOption.PublisherThread, true);
//this is a hack, the app startup is calling this, then the app itself, we only want the
//app itself to be handling the listeners
if (_bAddListeners)
{
_eventAggregator.GetEvent<TextPastedEvent>().Subscribe(OnTextPasted);
}
_bAddListeners = true;
}
private void OnTextPasted(ITextPastedEventArgs args)
{
if (args.Id != ExtraPropertyModel.PASTE_ID) { return; }
if (!(args.Sender is IExtraProperty iep))
{
return;
}
Paste(iep, args.Text, args.Tag);
var last = ExtraProperties.Last();
if (!string.IsNullOrWhiteSpace(last.Key) || !string.IsNullOrWhiteSpace(last.Value))
{
MarkModified(last);
}
_eventAggregator.GetEvent<PageModifiedEvent>()
.Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page));
}
private void OnBusyIndicatorNotification(bool eventArg)
{
IsBusy = eventArg;
}
private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle)
{
// The NotificationRequest.Raise triggers the Invoke() method of the PopupWindowAction object to show the NotificationWindow window
// Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string.
var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, "",
eventArgsWithTitle.Image, string.Empty);
NotificationRequest.Raise(new Notification
{
Content = eventArgsWithoutTitle,
Title = eventArgsWithTitle.Title
});
}
#endregion
/// <inheritdoc />
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
if ("ExtraProperties" == propertyName)
{
_eventAggregator.GetEvent<ExtraPropertiesChangedEvent>()
.Publish(new ExtraPropertiesChangedEventArgs(AllExtraProperties.Where(exp => !string.IsNullOrEmpty(exp.Key)).ToList(), this, Parent));
}
}
public void SetPage(IDataPROPage page)
{
Page = page;
}
public void SetParent(object parent)
{
Parent = parent;
}
public void Cleanup()
{
}
public Task CleanupAsync()
{
return Task.CompletedTask;
}
public void Initialize()
{
}
public void Initialize(object parameter)
{
}
public void Initialize(object parameter, object model)
{
}
public Task InitializeAsync()
{
return Task.CompletedTask;
}
public Task InitializeAsync(object parameter)
{
return Task.CompletedTask;
}
public void Activated()
{
}
internal void MarkModified(IExtraProperty iep)
{
if (ExtraProperties.ToList().Last() == iep)
{
var newXP = new ExtraPropertyModel();
ExtraProperties.Add(newXP);
AllExtraProperties.Add(newXP);
}
OnPropertyChanged("ExtraProperties");
_eventAggregator.GetEvent<PageModifiedEvent>()
.Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page));
}
public void Filter(object tag, string term)
{
if (!(tag is string s))
{
return;
}
switch (s)
{
case "Key":
_searchTermForField[Fields.Key] = term;
Filter();
break;
case "Value":
_searchTermForField[Fields.Key] = term;
Filter();
break;
}
}
public void Sort(object columnTag, bool columnClick)
{
if (!(columnTag is string s)) { return; }
switch (s)
{
case "Key":
Sort(Fields.Key, true);
Filter();
break;
case "Value":
Sort(Fields.Value, true);
Filter();
break;
}
}
private void Sort(Fields field, bool bColumnClick)
{
if (bColumnClick)
{
if (field != _sortField)
{
_sortField = field;
_sortAscending = true;
}
else
{
_sortAscending = !_sortAscending;
}
}
var comparer = new PropertyComparer();
comparer.SortField = _sortField;
comparer.SortAscending = _sortAscending;
AllExtraProperties.Sort(comparer);
}
public enum Fields
{
Key,
Value
}
private Fields _sortField = Fields.Key;
private bool _sortAscending = true;
private void Filter()
{
ExtraProperties.Clear();
foreach (var extraProperty in AllExtraProperties)
{
if (string.IsNullOrWhiteSpace(extraProperty.Key) && string.IsNullOrWhiteSpace(extraProperty.Value))
{
ExtraProperties.Add(extraProperty);
continue;
}
if (_searchTermForField.ContainsKey(Fields.Value))
{
var term = _searchTermForField[Fields.Value];
if (!string.IsNullOrEmpty(term))
{
if (extraProperty.Value.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0)
{
continue;
}
}
}
if (_searchTermForField.ContainsKey(Fields.Key))
{
var term = _searchTermForField[Fields.Key];
if (!string.IsNullOrWhiteSpace(term))
{
if (extraProperty.Key.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0)
{
continue;
}
}
}
ExtraProperties.Add(extraProperty);
}
}
internal void Validate(ref List<string> errors, ref List<string> warnings)
{
var repeatKeys = AllExtraProperties.GroupBy(exp => exp.Key).Where(grp => grp.Count() > 1).Select(exp => exp.Key).ToArray();
if (repeatKeys.Length > 0)
{
var error = StringResources.RepeatKeyError + Environment.NewLine + string.Join(Environment.NewLine, repeatKeys);
errors.Add(error);
}
var noValueKeys = AllExtraProperties.Where(exp => string.IsNullOrWhiteSpace(exp.Value)).Select(exp => exp.Key).ToArray();
if (noValueKeys.Length > 0)
{
var warning = StringResources.NoValueWarning + Environment.NewLine + string.Join(Environment.NewLine, noValueKeys);
warnings.Add(warning);
}
}
public bool Validate(ref List<string> errors)
{
var before = errors.Count;
var notUsed = new List<string>();
Validate(ref errors, ref notUsed);
return before == errors.Count;
}
private readonly Dictionary<Fields, string> _searchTermForField = new Dictionary<Fields, string>();
private IExtraProperty[] _selectedItems = null;
public IDataPROPage Page { get; private set; }
public object Parent { get; private set; }
public bool IsDirty { get; private set; }
private bool _isBusy = false;
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged("IsBusy");
}
}
private bool _isMenuIncluded;
private void NotifySelectionChanged(int count)
{
_eventAggregator.GetEvent<PageSelectionChanged>().Publish(new PageSelectionChangedArg(count, Page));
}
internal void SetSelection(IExtraProperty[] ieps)
{
_selectedItems = ieps;
NotifySelectionChanged(_selectedItems?.Length ?? 0);
}
public bool IsMenuIncluded
{
get => _isMenuIncluded;
set
{
_isMenuIncluded = value;
OnPropertyChanged("IsMenuIncluded");
}
}
private bool _isNavigationIncluded;
public bool IsNavigationIncluded
{
get => _isNavigationIncluded;
set
{
_isNavigationIncluded = value;
OnPropertyChanged("IsNavigationIncluded");
}
}
//FB14098: Ability to disable editing View if user doesn't have the permissions, but still view current data
private bool _isReadOnly;
public bool IsReadOnly
{
get => _isReadOnly;
set
{
_isReadOnly = value;
OnPropertyChanged("IsReadOnly");
}
}
public List<IExtraProperty> AllExtraProperties { get; set; } = new List<IExtraProperty>();
public ObservableCollection<IExtraProperty> ExtraProperties { get; set; } =
new ObservableCollection<IExtraProperty>();
public IExtraProperty[] SelectedProperties => throw new NotImplementedException();
private void Paste(IExtraProperty extraProperty, string text, object tag)
{
bool bKey = tag.Equals("ExtraProperty");
var extraProperties = ParseText(text, bKey, out var oneColumn);
int index = ExtraProperties.IndexOf(extraProperty);
foreach (var extraproperty in extraProperties)
{
if (index > (ExtraProperties.Count - 1))
{
ExtraProperties.Add(extraProperty);
index++;
}
else
{
var exp = ExtraProperties[index++];
if (oneColumn)
{
exp.Key = bKey ? extraproperty.Key : exp.Key;
exp.Value = bKey ? exp.Value : extraproperty.Value;
}
else
{
exp.Key = extraproperty.Key;
exp.Value = extraproperty.Value;
}
}
}
Sort(_sortField, false);
Filter();
}
private IExtraProperty[] ParseText(string text, bool bKey, out bool oneColumn)
{
oneColumn = false;
var list = new List<IExtraProperty>();
var errors = new List<string>();
var lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
for (var i = 0; i < lines.Length; i++)
{
var line = lines[i];
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var tokens = line.Split(',');
if (tokens.Length != 2)
{
tokens = line.Split('\t');
}
if (tokens.Length != 2)
{
tokens = line.Split(';');
}
var newProperty = new ExtraPropertyModel();
if (tokens.Length == 1)
{
oneColumn = true;
if (bKey)
{
newProperty.Key = tokens[0];
newProperty.Value = "";
}
else
{
newProperty.Value = tokens[0];
newProperty.Key = "";
}
}
else if (tokens.Length == 2)
{
newProperty.Key = tokens[0];
newProperty.Value = tokens[1];
}
else
{
errors.Add(string.Format(Resources.StringResources.InvalidLine, 1 + i));
continue;
}
list.Add(newProperty);
}
return list.ToArray();
}
public void SetExtraProperties(IList<IExtraProperty> properties)
{
AllExtraProperties.Clear();
AllExtraProperties.AddRange(properties.Select(iep => new ExtraPropertyModel(iep)));
AllExtraProperties.Add(new ExtraPropertyModel());
_sortField = Fields.Key;
_sortAscending = true;
Sort(_sortField, false);
Filter();
}
public void CopySelected()
{
if (null == _selectedItems) { return; }
foreach (var item in _selectedItems)
{
AllExtraProperties.Insert(AllExtraProperties.Count - 1, new ExtraPropertyModel(item));
}
Sort(_sortField, false);
Filter();
_eventAggregator.GetEvent<PageModifiedEvent>()
.Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page));
}
public void DeleteSelected()
{
if (null == _selectedItems) { return; }
bool bAddLast = false;
foreach (var exp in _selectedItems)
{
if (ExtraProperties.Last() == exp)
{
bAddLast = true;
}
ExtraProperties.Remove(exp);
AllExtraProperties.Remove(exp);
}
if (bAddLast)
{
var newXP = new ExtraPropertyModel();
ExtraProperties.Add(newXP);
AllExtraProperties.Add(newXP);
}
OnPropertyChanged("ExtraProperties");
_eventAggregator.GetEvent<PageModifiedEvent>()
.Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page));
}
public class PropertyComparer : IComparer<IExtraProperty>
{
public Fields SortField { get; set; }
public bool SortAscending { get; set; }
public int Compare(IExtraProperty left, IExtraProperty right)
{
if (left == right)
{
return 0;
}
var a = left; var b = right;
if (string.IsNullOrWhiteSpace(a.Key) && string.IsNullOrWhiteSpace(a.Value))
{
return 1;
}
if (string.IsNullOrWhiteSpace(b.Key) && string.IsNullOrWhiteSpace(b.Value))
{
return -1;
}
if (!SortAscending) { a = right; b = left; }
if (null == a)
{
return -1;
}
if (null == b)
{
return 1;
}
switch (SortField)
{
case Fields.Key:
return DTS.Common.Utilities.NaturalStringComparer.StaticCompare(a.Key.ToUpper(), b.Key.ToUpper());
case Fields.Value:
return DTS.Common.Utilities.NaturalStringComparer.StaticCompare(a.Value.ToUpper(), b.Value.ToUpper());
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
}