408 lines
17 KiB
C#
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
|
|||
|
|
}
|
|||
|
|
}
|