Files
DP44/DTS Viewer/DTS.Viewer.Modules/DTS.Viewer.TestModification/ViewModel/TestModificationViewModel.cs
2026-04-17 14:55:32 -04:00

408 lines
17 KiB
C#

using DTS.Common.Base;
using DTS.Common.Events;
using DTS.Common.Interactivity;
using DTS.Common.Interface;
using DTS.Common.Interface.Sensors;
using DTS.Common.Settings;
using DTS.Common.Storage;
using DTS.Common.Utilities.Logging;
using DTS.SensorDB;
using DTS.Viewer.ChartOptions.Model;
using DTS.Viewer.TestModification.Model;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Unity;
// ReSharper disable CheckNamespace
// ReSharper disable ConvertToAutoProperty
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedAutoPropertyAccessor.Local
// ReSharper disable NotAccessedField.Local
// ReSharper disable RedundantDefaultMemberInitializer
namespace DTS.Viewer.TestModification
{
public class TestModificationViewModel : BaseViewModel<ITestModificationViewModel>, ITestModificationViewModel
{
/// <summary>
/// retrieves latest calibration from database (or null if not in database or an error occurs)
/// <summary>
private static ISensorCalDbRecord GetLatestCalibration(ISensorDbRecord sensor)
{
if ( null == sensor)
{
return null;
}
try
{
var records = GetCalibrationsDb(sensor.id, sensor.SerialNumber);
if ( null == records || 0 == records.Length) { return null; }
Array.Sort(records, CompareCalibrations);
//calibrations should now be in ascending order so take the "last" one
return records[records.Length - 1];
}
catch (Exception)
{
//there's no access to APILogger here, so rather than adding a reference, just eat the error
}
return null;
}
private static ISensorCalDbRecord[] GetCalibrationsDb(int sensorId, string serialNumber)
{
_ = DbOperations.SensorCalibrationsGet(sensorId, serialNumber, out var records);
return records;
}
/// <summary>
/// compares two sensor calibration records
/// </summary>
private static int CompareCalibrations(ISensorCalDbRecord left, ISensorCalDbRecord right)
{
if (left == right) { return 0; }
if (null == left) { return 1; }
if (null == right) { return -1; }
var res = left.CalibrationDate.CompareTo(right.CalibrationDate);
if (res != 0)
{
return res;
}
return left.ModifyDate.CompareTo(right.ModifyDate);
}
/// <summary>
/// returns sensor given serial number
/// </summary>
private static ISensorDbRecord GetSensor(ISensorDbRecord[] records)
{
if ( null == records || 0 == records.Length) { return null; }
return records[0];
}
/// <summary>
/// updates calibration in db
/// http://manuscript.dts.local/f/cases/43735/SW-NFR-DataPRO-Add-option-to-map-sensitivity-edit-in-Viewer-back-to-Sensor-Database
/// </summary>
public void UpdateDatabaseMethod()
{
try
{
var cal = Model.Cal;
if (null == cal) { return; }
cal.CalibrationId = -1;
cal.ModifyDate = DateTime.Now;
var sc = new SensorCalibration(cal);
DbOperations.SensorCalibrationsInsert(sc, 0, true);
Model.Cal = GetLatestCalibration(Model.Sensor);
}
catch (Exception ex)
{
_eventAggregator.GetEvent<PageErrorEvent>().Publish(new PageErrorArg(new[] { $"{Resources.StringResources.FailedToModifySensitivity} {ex.Message}" }, null));
}
}
public ITestModificationView View { get; set; }
public IBaseViewModel Parent { get; set; }
private IEventAggregator _eventAggregator { get; set; }
private IUnityContainer _unityContainer { get; set; }
public InteractionRequest<Notification> NotificationRequest { get; private set; }
public new InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }
/// <summary>
/// Creates a new instance of the TestModificationViewListModel.
/// </summary>
/// <param name="view">The TestModification View interface.</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 TestModificationViewModel(ITestModificationView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)
: base(regionManager, eventAggregator, unityContainer)
{
Model = new TestModificationModel();
View = view;
View.DataContext = this;
NotificationRequest = new InteractionRequest<Notification>();
ConfirmationRequest = new InteractionRequest<Confirmation>();
_eventAggregator = eventAggregator;
_unityContainer = unityContainer;
_eventAggregator.GetEvent<RaiseNotification>().Subscribe(OnRaiseNotification);
_eventAggregator.GetEvent<GraphSelectedChannelsNotification>().Subscribe(OnGraphSelectedCountChanged);
_eventAggregator.GetEvent<ShiftT0Event>().Subscribe(OnShiftT0Event);
_eventAggregator.GetEvent<SetUseZeroForUnfilteredEvent>().Subscribe(OnSetUseZeroForUnfiltered);
}
private void OnSetUseZeroForUnfiltered(bool useZeroForUnfiltered)
{
UseZeroForUnfiltered = useZeroForUnfiltered;
}
private void OnShiftT0Event(ShiftT0EventArguments args)
{
if (args.IsInitialization) { return; }
if (args.IsKeyPress)
{
if (null == Model) { return; }
//if we can't modify no reason to continue, short circuit out
if (!TestModificationVisability) { return; }
if (null == Model.SelectedChannel || null == Model.SelectedChannel.ParentModule) { return; }
else
{
//go and modify the T0!
//calculate a new T0 given the sample rate
var t0 = Model.T0 + args.T0Steps * (1000D / Model.SelectedChannel.ParentModule.SampleRateHz);
Model.T0 = t0;
}
_eventAggregator.GetEvent<TestModificationChangedEvent>().Publish(Model);
}
else { Model.T0 = args.T0Time; }
}
#region Methods
public override void Initialize()
{
}
public override void Initialize(object parameter)
{
Parent = (IBaseViewModel)parameter;
}
/// <summary>
/// Private Event handler for RaiseNotification event.
/// </summary>
private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle)
{
// Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string.
var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, eventArgsWithTitle.MessageDetails, eventArgsWithTitle.Image);
NotificationRequest.Raise(new Notification
{
Content = eventArgsWithoutTitle,
Title = eventArgsWithTitle.Title
});
}
private static bool IsPopulating { get; set; }
private void OnGraphSelectedCountChanged(GraphSelectedChannelsNotificationArg arg)
{
if (Parent != arg?.ParentVM) return;
var channels = arg.SelectedChannels;
var canModify = channels.Count == 1 && channels.Count(x => x.IsSelected) == 1;
TestModificationVisability = canModify;
if (canModify)
{
IsPopulating = true;
Model.IsT0ModeTestOnly = SettingsDB.GetGlobalValueBool(Keys.ApplyShiftT0ModsTestOnly.ToString(), false);
var viewModel = _unityContainer.TryResolve<IViewerMainViewModel>();
Model.EnableSensitivityControl = viewModel.DoesUserHaveEditPermission;
Model.EnableLineFitControl = viewModel.DoesUserHaveEditPermission;
Model.EnableDescriptionControl = viewModel.DoesUserHaveEditPermission;
Model.EnableEUMultiplierControl = viewModel.DoesUserHaveEditPermission;
Model.EnableEUOffsetControl = viewModel.DoesUserHaveEditPermission;
Model.EnableFilterControl = viewModel.DoesUserHaveEditPermission;
Model.IsT0Enabled = viewModel.DoesUserHaveEditPermission;
Model.IsDataFlagEnabled = viewModel.DoesUserHaveEditPermission;
Model.SelectedChannel = channels[0];
TestModelManipulation.PopulateFromChannel(Model);
IsPopulating = false;
IsBackedUp = TestModelManipulation.BackupExists(Model);
_eventAggregator.GetEvent<ShowT0CursorEvent>().Publish(true);
DbOperations.SensorsGet(channels[0].SerialNumber, out var records);
var sensor = GetSensor(records);
if (null != sensor && 0 == sensor.SensorType)
{
//for now we only display analog sensor calibrations ...
Model.Sensor = sensor;
Model.Cal = GetLatestCalibration(Model.Sensor);
}
}
else if (channels.Count == 0)
{
Model.SelectedChannel = null;
}
else
{
_eventAggregator.GetEvent<ShowT0CursorEvent>().Publish(false);
}
}
#endregion
#region ContextRegion
#endregion
#region Commands
private DelegateCommand _previewCommand;
public DelegateCommand PreviewCommand => _previewCommand ?? (_previewCommand = new DelegateCommand(PreviewMethod));
private void PreviewMethod()
{
TestModelManipulation.PreviewLineFit(Model);
}
private DelegateCommand _writeCommand;
public DelegateCommand WriteCommand => _writeCommand ?? (_writeCommand = new DelegateCommand(WriteMethod));
private void WriteMethod()
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
//14661 Shifting T zero beyond post trigger seconds crashes application
//don't allow T0 to shift beyond test data
if (Model.IsModifiedT0 && !Model.ValidateT0())
{
_eventAggregator.GetEvent<PageErrorEvent>()
.Publish(new PageErrorArg(new[] { Resources.StringResources.T0MustBeInDataset }, null));
return;
}
var dialogResult = MessageBox.Show(window, Resources.StringResources.WriteFilesPrompt, "", MessageBoxButton.YesNo);
try
{
UseISOCodeFilterMapping = SettingsDB.GetGlobalValueBool("UseISOCodeFilterMapping", true);
}
catch (Exception ex)
{
APILogger.Log(ex);
}
APILogger.Log(Resources.StringResources.WriteFilesPrompt, $"User pressed {dialogResult.ToString()}");
if (dialogResult == MessageBoxResult.Yes)
{
TestModelManipulation.SaveModification(Model, UseISOCodeFilterMapping, UseZeroForUnfiltered);
IsBackedUp = TestModelManipulation.BackupExists(Model);
}
}
private DelegateCommand _undoCommand;
public DelegateCommand UndoCommand => _undoCommand ?? (_undoCommand = new DelegateCommand(UndoMethod));
private void UndoMethod()
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
var dialogResult = MessageBox.Show(window, Resources.StringResources.UndoPrompt, "", MessageBoxButton.YesNo);
APILogger.Log(Resources.StringResources.UndoPrompt, $"User pressed {dialogResult.ToString()}");
if (dialogResult == MessageBoxResult.Yes)
{
TestModelManipulation.UndoModification(Model);
}
}
private DelegateCommand _undoAllCommand;
public DelegateCommand UndoAllCommand => _undoAllCommand ?? (_undoAllCommand = new DelegateCommand(UndoAllMethod));
private void UndoAllMethod()
{
var window = Application.Current.MainWindow;
if (null == window) { return; }
var dialogResult = MessageBox.Show(window, Resources.StringResources.UndoAllPrompt, "", MessageBoxButton.YesNo);
APILogger.Log(Resources.StringResources.UndoAllPrompt, $"User pressed {dialogResult.ToString()}");
if (dialogResult == MessageBoxResult.Yes)
{
TestModelManipulation.UndoAllModification(Model);
IsBackedUp = TestModelManipulation.BackupExists(Model);
}
}
public void PublishChanges()
{
if (!IsPopulating && Model.IsModifiedDataFlag)
{
//Write this immediately
TestModelManipulation.SaveModificationDataFlag(Model);
IsBackedUp = TestModelManipulation.BackupExists(Model);
}
_eventAggregator?.GetEvent<TestModificationChangedEvent>().Publish(Model);
}
#endregion Commands
#region Properties
/// <summary>
/// when true forces the ISOCode field filter SoftwareFilter to always match the SoftwareFilter of the channel
/// Whenever the softwarefilter for a graph channel is modified it will check this value before
/// modifying the channel isocode
/// </summary>
public bool UseISOCodeFilterMapping { get; set; } = false;
private TestModificationModel _model = null; // new TestModificationModel();
public new TestModificationModel Model
{
get => _model;
set
{
if (_model != null) _model.Parent = null;
_model = value;
if (_model != null) _model.Parent = this;
OnPropertyChanged("Model");
}
}
public bool UseZeroForUnfiltered
{
get; set;
}
private bool _isFilterEnabled = false;
public bool IsFilterEnabled { get => _isFilterEnabled; set { _isFilterEnabled = value; OnPropertyChanged("IsFilterEnabled"); } }
private bool _testModificationVisability = false;
public bool TestModificationVisability { get => _testModificationVisability; set { _testModificationVisability = value; OnPropertyChanged("TestModificationVisability"); } }
///<summary>
///Occurs when a property value changes.
///</summary>
public new event PropertyChangedEventHandler PropertyChanged;
private new void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Gets the HeaderInfo.
/// </summary>
public string HeaderInfo => "TestSummaryRegion";
private bool _isBusy = false;
public new bool IsBusy
{
get => _isBusy;
set { _isBusy = value; OnPropertyChanged("IsBusy"); }
}
private bool _isDirty;
public new bool IsDirty
{
get => _isDirty;
set => _isDirty = value;
}
private bool _isNavigationIncluded;
public new bool IsNavigationIncluded
{
get => _isNavigationIncluded;
set => _isNavigationIncluded = value;
}
private bool _isBackedUp;
public bool IsBackedUp
{
get => _isBackedUp;
private set
{
_isBackedUp = value;
OnPropertyChanged("IsBackedUp");
}
}
#endregion
}
}