Files
DP44/DataPRO/Modules/TestSetups/Imports/TTS/ViewModel/SummaryViewModel.cs
2026-04-17 14:55:32 -04:00

752 lines
27 KiB
C#

using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using System.Windows;
using DTS.Common.Events;
using DTS.Common.Interface;
using DTS.Common.Interface.TestSetups.Imports.TTS.ReadFile;
using Prism.Events;
using Unity;
using DTS.Common.Interactivity;
using Prism.Regions;
using Prism.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using DTS.Common;
using DTS.Common.Interface.DataRecorders;
using DTS.Common.Base;
using DTS.Common.Classes;
using DTS.Common.Enums;
using DTS.Common.Events.TTSImport;
using TTSImport.Model;
using TTSImport.Resources;
// ReSharper disable CheckNamespace
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable InconsistentNaming
namespace TTSImport
{
/// <summary>
/// this class handles Summary functionality
/// </summary>
[PartCreationPolicy(CreationPolicy.Shared)]
public class SummaryViewModel : ISummaryViewModel
{
/// <summary>
/// The Status and Progress bars
/// </summary>
public IStatusAndProgressBarView StatusAndProgressBarView { get; private set; }
/// <summary>
/// The Summary view
/// </summary>
public ISummaryView View { get; set; }
private IEventAggregator _eventAggregator { get; set; }
private IRegionManager _regionManager;
private IUnityContainer UnityContainer { get; set; }
public InteractionRequest<Notification> NotificationRequest { get; private set; }
public InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }
/// <summary>
/// Creates a new instance of the TechnologyDomainEditViewModel.
/// </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 SummaryViewModel(ISummaryView view, IRegionManager regionManager, IEventAggregator eventAggregator,
IUnityContainer unityContainer)
{
View = view;
View.DataContext = this;
NotificationRequest = new InteractionRequest<Notification>();
ConfirmationRequest = new InteractionRequest<Confirmation>();
_eventAggregator = eventAggregator;
UnityContainer = unityContainer;
_regionManager = regionManager;
_eventAggregator.GetEvent<RaiseNotification>().Subscribe(OnRaiseNotification);
_eventAggregator.GetEvent<BusyIndicatorChangeNotification>().Subscribe(OnBusyIndicatorNotification, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportReadFileStatusEvent>().Subscribe(OnReadFileFinished, ThreadOption.PublisherThread, true);
_eventAggregator.GetEvent<TTSImportTestSetupChangedEvent>().Subscribe(OnTestSetupChanged, ThreadOption.PublisherThread, true);
}
#region Methods
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()
{
StatusAndProgressBarView = GetStatusAndProgressBarView(this);
return Task.CompletedTask;
}
public Task InitializeAsync(object parameter)
{
return Task.CompletedTask;
}
public void Activated()
{
}
/// <summary>
/// Private Event handler for RaiseNotification event.
/// </summary>
private void OnBusyIndicatorNotification(bool eventArg)
{
IsBusy = eventArg;
}
/// <summary>
/// Private Event handler for RaiseNotification event.
/// </summary>
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
});
}
public string GetTestId()
{
return null == View ? "" : View.GetTestId();
}
private void OnReadFileFinished(ReadFileStatusArg statusArg)
{
TestSetupImported = false;
if (!statusArg.Status) return;
_setup = statusArg.TTSSetup;
View?.SetTestName(_setup.TestId);
OnPropertyChanged(PropertyNames.ImportFileName.ToString());
OnPropertyChanged(PropertyNames.TestSetupName.ToString());
OnPropertyChanged(PropertyNames.SampleRate.ToString());
OnPropertyChanged(PropertyNames.RecordingMode.ToString());
OnPropertyChanged(PropertyNames.TestLength.ToString());
OnPropertyChanged(PropertyNames.PreTrigger.ToString());
OnPropertyChanged(PropertyNames.PostTrigger.ToString());
OnPropertyChanged(PropertyNames.ROIStart.ToString());
OnPropertyChanged(PropertyNames.ROIEnd.ToString());
OnPropertyChanged(PropertyNames.AAF_TDAS.ToString());
OnPropertyChanged(PropertyNames.AAF_SLICE.ToString());
}
private void OnTestSetupChanged(ITTSSetup setup)
{
TestSetupImported = false;
}
public void UpdateUI()
{
SampleRate = _setup.SampleRate;
SetAvailableRecordingModes();
RecordingMode = _setup.Mode;
SetChannelList();
TestSetupComplete = !SummaryChannelList.Exists(channelType => (channelType.Unassigned != "0") && (channelType.Unassigned != Resources.StringResources.Table_NA));
if (!TestSetupComplete || Array.Exists(_setup.Channels, channel => channel.IsModified) || Array.Exists(_setup.LevelTriggers, levelTrigger => levelTrigger.IsModified))
{
TestSetupImported = false;
}
}
private List<double> _availableSampleRates = new List<double>();
public List<double> AvailableSampleRates
{
get => _availableSampleRates;
set
{
_availableSampleRates = value;
OnPropertyChanged("AvailableSampleRates");
}
}
public void SetAvailableSampleRates(int[] values)
{
AvailableSampleRates.Clear();
var minSampleRate = (double)values.Min();
var maxSampleRate = (double)values.Max();
foreach (var channel in _setup.Channels)
{
if (channel.HardwareChannel == null) continue;
minSampleRate = Math.Max(channel.HardwareChannel.GetParentDAS().GetMinSampleRateDouble(), minSampleRate);
maxSampleRate = Math.Min(channel.HardwareChannel.GetParentDAS().GetMaxSampleRateDouble(), maxSampleRate);
}
foreach (var sampleRate in values)
{
if (sampleRate >= minSampleRate && sampleRate <= maxSampleRate)
{
AvailableSampleRates.Add(sampleRate);
}
}
}
public string AAF_TDAS => string.Format(StringResources.AAF_TDAS, !_aafExceptions.ContainsKey(SampleRate) ? (SampleRate / 5) : _aafExceptions[SampleRate][0]);
public string AAF_SLICE => string.Format(StringResources.AAF_SLICE, !_aafExceptions.ContainsKey(SampleRate) ? (SampleRate / 5) : _aafExceptions[SampleRate][1]);
private Dictionary<double, List<double>> _aafExceptions = new Dictionary<double, List<double>>();
public void SetAAFExceptions(Dictionary<double, List<double>> values)
{
_aafExceptions.Clear();
_aafExceptions = values;
}
public List<RecordingModes> AvailableRecordingModes { get; } = new List<RecordingModes>();
private void SetAvailableRecordingModes()
{
AvailableRecordingModes.Clear();
AvailableRecordingModes.Add(RecordingModes.CircularBuffer);
AvailableRecordingModes.Add(RecordingModes.Recorder);
if (_setup.AllowAdvancedRecordingModes)
{
AvailableRecordingModes.Add(RecordingModes.HybridRecorder);
}
}
public void SetSerializedTestIdValues(string[] values)
{
View?.UpdateTestIds(values);
}
/// <summary>
/// Fill in the table of channels, including those added after the file was read
/// </summary>
public void SetChannelList()
{
const int Assigned = 0;
const int Unassigned = 1;
var analogChannels = new[] { 0, 0 };
var tomChannels = new[] { 0, 0 };
var digitalInChannels = new[] { 0, 0 };
var levelTriggers = new[] { 0, 0 };
foreach (var channelRecord in _setup.Channels)
{
if (string.Equals(channelRecord.ChannelCode, TTSChannelRecord.NONE, StringComparison.CurrentCultureIgnoreCase) || channelRecord.Disabled) continue;
if (channelRecord.IsSquib)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsSquib)
{
tomChannels[Assigned] += 1;
}
else
{
tomChannels[Unassigned] += 1;
}
}
else if (channelRecord.IsDigitalInput)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsDigitalIn)
{
digitalInChannels[Assigned] += 1;
}
else
{
digitalInChannels[Unassigned] += 1;
}
}
else if (!channelRecord.IsDigitalOutput)
{
if (channelRecord.HardwareChannel != null && channelRecord.HardwareChannel.IsAnalog)
{
analogChannels[Assigned] += 1;
}
else
{
analogChannels[Unassigned] += 1;
}
}
}
foreach (var levelTrigger in _setup.LevelTriggers)
{
if (!string.IsNullOrWhiteSpace(levelTrigger.Code))
{
levelTriggers[Assigned] += 1;
}
}
var temp = new List<SummaryChannel>();
var channel = new SummaryChannel
{
ChannelType = "Analog", //internationalize these
Assigned = analogChannels[Assigned],
Unassigned = analogChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "TOM",
Assigned = tomChannels[Assigned],
Unassigned = tomChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "Digital In",
Assigned = digitalInChannels[Assigned],
Unassigned = digitalInChannels[Unassigned].ToString()
};
temp.Add(channel);
channel = new SummaryChannel
{
ChannelType = "Level Trigger",
Assigned = levelTriggers[Assigned],
Unassigned = Resources.StringResources.Table_NA
};
temp.Add(channel);
SummaryChannelList = temp;
}
private readonly StatusAndProgressBarEventArgs statusAndProgressBarEventArgs = new StatusAndProgressBarEventArgs();
/// <summary>
/// Sets the text, background color, progress value, and/or progress visibility
/// </summary>
/// <param name="status"></param>
/// <param name="error"></param>
public void SetStatus(string status, string error = default(string)) //default(string) is null
{
switch (status)
{
case "Waiting": //change this to string resources but use the same one in DataPRO and here???
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Waiting.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Working":
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Busy.Color;
statusAndProgressBarEventArgs.ProgressValue = 0;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Visible;
break;
case "Failed":
TestSetupImported = false;
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Failed.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
case "Done":
TestSetupImported = true;
foreach (var ch in _setup.Channels)
{
ch.IsModified = false;
}
foreach (var lt in _setup.LevelTriggers)
{
lt.IsModified = false;
}
statusAndProgressBarEventArgs.StatusColor = BrushesAndColors.Brush_ApplicationStatus_Complete.Color;
statusAndProgressBarEventArgs.ProgressBarVisibility = Visibility.Collapsed;
break;
}
if (!string.IsNullOrEmpty(error))
{
statusAndProgressBarEventArgs.StatusText = status + " - " + error;
}
else
{
statusAndProgressBarEventArgs.StatusText = status;
}
statusAndProgressBarEventArgs.Requester = this;
_eventAggregator.GetEvent<StatusAndProgressBarEvent>().Publish(statusAndProgressBarEventArgs);
}
/// <summary>
/// Sets the progress value on the Status and Progress bar
/// </summary>
/// <param name="progress"></param>
public void SetProgress(double progress)
{
statusAndProgressBarEventArgs.ProgressValue = (int)progress;
statusAndProgressBarEventArgs.Requester = this;
_eventAggregator.GetEvent<StatusAndProgressBarEvent>().Publish(statusAndProgressBarEventArgs);
}
private IStatusAndProgressBarView GetStatusAndProgressBarView(IBaseViewModel parent)
{
var view = UnityContainer.Resolve<IStatusAndProgressBarView>();
var viewModel = UnityContainer.Resolve<IStatusAndProgressBarViewModel>();
view.DataContext = viewModel;
viewModel.Initialize(parent);
return view;
}
#endregion
#region Properties
private ITTSSetup _setup;
public bool IsDirty { get; private set; }
private bool _isBusy = false;
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged("IsBusy");
}
}
private bool _isMenuIncluded = false;
public bool IsMenuIncluded
{
get => _isMenuIncluded;
set
{
_isMenuIncluded = value;
OnPropertyChanged("IsMenuIncluded");
}
}
private bool _isNavigationIncluded = false;
public bool IsNavigationIncluded
{
get => _isNavigationIncluded;
set
{
_isNavigationIncluded = value;
OnPropertyChanged("IsNavigationIncluded");
}
}
private List<SummaryChannel> _summaryChannelList = new List<SummaryChannel>();
public List<SummaryChannel> SummaryChannelList
{
get => _summaryChannelList;
set
{
_summaryChannelList = value;
OnPropertyChanged("SummaryChannelList");
}
}
private bool _testSetupComplete;
public bool TestSetupComplete
{
get => _testSetupComplete;
set
{
_testSetupComplete = value;
OnPropertyChanged("ImportEnabled");
}
}
private bool _testSetupImported;
public bool TestSetupImported
{
get => _testSetupImported;
set
{
_testSetupImported = value;
OnPropertyChanged("RunTestVisible");
}
}
public bool ImportEnabled => TestSetupComplete & IsROIValid;
public Visibility RunTestVisible => TestSetupImported ? Visibility.Visible : Visibility.Hidden;
public Visibility SummaryPreTriggerVisibility => RecordingMode == RecordingModes.CircularBuffer ? Visibility.Visible : Visibility.Collapsed;
public string PostTriggerOrTestLength => RecordingMode == RecordingModes.CircularBuffer ? StringResources.PostTrigger : StringResources.TestLength;
private bool _isROIStartValid = true;
public bool IsROIStartValid
{
get => _isROIStartValid;
set
{
_isROIStartValid = value;
OnPropertyChanged("IsROIStartValid");
}
}
private bool _isROIEndValid = true;
public bool IsROIEndValid
{
get => _isROIEndValid;
set
{
_isROIEndValid = value;
OnPropertyChanged("IsROIEndValid");
}
}
private void CalculateROIValid()
{
if (null == _setup)
{
IsROIEndValid = true;
IsROIStartValid = true;
return;
}
if (_setup.ROIEnd < _setup.ROIStart)
{
IsROIStartValid = false;
IsROIEndValid = false;
return;
}
if (RecordingMode == RecordingModes.Recorder)
{
IsROIStartValid = true;
IsROIEndValid = !(_setup.ROIEnd - _setup.ROIStart > _setup.PostTrigger);
}
else
{
IsROIEndValid = !(_setup.ROIEnd > _setup.PostTrigger);
IsROIStartValid = !(Math.Abs(_setup.ROIStart) > _setup.PreTrigger);
}
}
public bool IsROIValid
{
get
{
CalculateROIValid();
return IsROIStartValid && IsROIEndValid;
}
}
//=> RecordingMode != RecordingModes.Recorder || !(_setup.ROIEnd - _setup.ROIStart > _setup.PostTrigger);
#endregion Properties
#region Commands
/// <summary>
/// browse to a file to import, should be xml, maybe needs a few other criteria
/// </summary>
private DelegateCommand _importCommand;
public DelegateCommand ImportClicked => _importCommand ?? (_importCommand = new DelegateCommand(ImportMethod));
private void ImportMethod()
{
_eventAggregator.GetEvent<TTSImportSummaryImportEvent>().Publish(_setup);
}
/// <summary>
/// Run the test since the Run Test button was clicked
/// </summary>
private DelegateCommand _runTestCommand;
public DelegateCommand RunTestClicked =>
_runTestCommand ?? (_runTestCommand = new DelegateCommand(RunTestMethod));
private void RunTestMethod()
{
SetStatus(Resources.StringResources.ImportTestSetup_PossibleStatus_Working); //use string resource (same both here and where passed)
ThreadPool.QueueUserWorkItem(RunTestWorkThread, null);
}
void RunTestWorkThread(object obj)
{
_eventAggregator.GetEvent<TTSImportSummaryRunTestEvent>().Publish(_setup);
}
#endregion
#region properties
/// <summary>
/// all properties that are exposed
/// </summary>
public enum PropertyNames
{
ImportFileName,
TestSetupName,
SampleRate,
RecordingMode,
TestLength,
PreTrigger,
PostTrigger,
ROIStart,
ROIEnd,
AAF_TDAS,
AAF_SLICE,
AllowAdvancedRecordingModes,
AllowTSRAIRRecordingModes
}
/// <summary>
/// full path to import file
/// </summary>
public string ImportFileName => _setup?.Filename ?? "";
public string TestSetupName
{
get => _setup?.TestId ?? "";
set
{
TestSetupImported = false;
_setup.TestId = value;
View?.SetTestName(_setup.TestId);
}
}
public double SampleRate
{
get => _setup?.SampleRate ?? 10000;
set
{
if (_setup.SampleRate != value)
{
TestSetupImported = false;
_setup.SampleRate = value;
}
OnPropertyChanged(PropertyNames.SampleRate.ToString());
OnPropertyChanged(PropertyNames.AAF_TDAS.ToString());
OnPropertyChanged(PropertyNames.AAF_SLICE.ToString());
}
}
private void OnPropertyChanged(PropertyNames sampleRate)
{
throw new NotImplementedException();
}
public RecordingModes RecordingMode
{
get => _setup?.Mode ?? RecordingModes.CircularBuffer;
set
{
if (_setup.Mode != value)
{
TestSetupImported = false;
switch (value)
{
case RecordingModes.CircularBuffer:
case RecordingModes.Recorder:
case RecordingModes.HybridRecorder:
_setup.Mode = value;
break;
default:
_setup.Mode = RecordingModes.CircularBuffer;
break;
}
}
OnPropertyChanged("RecordingMode");
OnPropertyChanged("SummaryPreTriggerVisibility");
OnPropertyChanged("PostTriggerOrTestLength");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string PreTrigger
{
get => _setup?.PreTrigger.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double preTrigger)) return;
//if (preTrigger * -1 > _setup.ROIStart) ROIStart = (preTrigger * -1).ToString("0.00");
//if (preTrigger * -1 > _setup.ROIEnd) ROIEnd = (preTrigger * -1).ToString("0.00");
TestSetupImported = false;
_setup.PreTrigger = preTrigger;
OnPropertyChanged("PreTrigger");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string PostTrigger
{
get => _setup?.PostTrigger.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double postTrigger)) return;
//if (postTrigger < _setup.ROIStart) ROIStart = postTrigger.ToString("0.00");
//if (postTrigger < _setup.ROIEnd) ROIEnd = postTrigger.ToString("0.00");
TestSetupImported = false;
_setup.PostTrigger = postTrigger;
OnPropertyChanged("PostTrigger");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string ROIStart
{
get => _setup?.ROIStart.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double roiStart)) return;
if (roiStart < _setup.PreTrigger * -1 || roiStart > _setup.PostTrigger || roiStart > _setup.ROIEnd) return;
TestSetupImported = false;
_setup.ROIStart = roiStart;
OnPropertyChanged("ROIStart");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
public string ROIEnd
{
get => _setup?.ROIEnd.ToString("0.00") ?? "";
set
{
if (!double.TryParse(value, out double roiEnd)) return;
if (roiEnd < _setup.PreTrigger * -1 || roiEnd > _setup.PostTrigger || roiEnd < _setup.ROIStart) return;
TestSetupImported = false;
_setup.ROIEnd = roiEnd;
OnPropertyChanged("ROIEnd");
OnPropertyChanged("IsROIValid");
OnPropertyChanged("ImportEnabled");
}
}
#endregion
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}