diff options
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels')
| -rw-r--r-- | Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs | 1567 |
1 files changed, 1567 insertions, 0 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..cf66efbd6 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs @@ -0,0 +1,1567 @@ +using GalaSoft.MvvmLight.Ioc; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using Tango.Core.Commands; +using Tango.Integration.Observables; +using Tango.Integration.Operators; +using Tango.Integration.Services; +using Tango.Logging; +using Tango.MachineStudio.Common.Authentication; +using Tango.MachineStudio.Common.Controls; +using Tango.MachineStudio.Common.Diagnostics; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Common.StudioApplication; +using Tango.MachineStudio.Common.Video; +using Tango.MachineStudio.Developer.Navigation; +using Tango.MachineStudio.Developer.Views; +using Tango.Settings; +using Tango.SharedUI; +using Tango.Transport; + +namespace Tango.MachineStudio.Developer.ViewModels +{ + /// <summary> + /// Represents the developer module main view, view model. + /// </summary> + /// <seealso cref="Tango.SharedUI.ViewModel" /> + public class MainViewVM : ViewModel<IMainView>, IShutdownRequestBlocker, IShutdownListener + { + private static object _syncLock = new object(); + + private INotificationProvider _notification; + private TimeSpan _runningJobEstimatedDuration; + private JobHandler _jobHandler; + private DeveloperNavigationManager _navigation; + private bool _blockInvalidateCommands; + private IAuthenticationProvider _authentication; + private ObservablesContext _machineDbContext; + private ObservablesContext _activeJobDbContext; + + #region Properties + + private ObservableCollection<Machine> _machines; + /// <summary> + /// Gets or sets the machines. + /// </summary> + public ObservableCollection<Machine> Machines + { + get { return _machines; } + set { _machines = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<ColorSpace> _colorSpaces; + /// <summary> + /// Gets or sets the color spaces. + /// </summary> + public ObservableCollection<ColorSpace> ColorSpaces + { + get { return _colorSpaces; } + set { _colorSpaces = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<Rml> _rmls; + /// <summary> + /// Gets or sets the RMLS. + /// </summary> + public ObservableCollection<Rml> Rmls + { + get { return _rmls; } + set { _rmls = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<WindingMethod> _windingMethods; + /// <summary> + /// Gets or sets the winding methods. + /// </summary> + public ObservableCollection<WindingMethod> WindingMethods + { + get { return _windingMethods; } + set { _windingMethods = value; RaisePropertyChangedAuto(); } + } + + /// <summary> + /// Gets or sets the application manager. + /// </summary> + public IStudioApplicationManager ApplicationManager { get; set; } + + /// <summary> + /// Gets or sets the video capture provider. + /// </summary> + public IVideoCaptureProvider VideoCaptureProvider { get; set; } + + protected Machine _selectedMachine; + /// <summary> + /// Gets or sets the selected machine. + /// </summary> + public Machine SelectedMachine + { + get { return _selectedMachine; } + set + { + _selectedMachine = value; + OnSelectedMachineChanged(); + RaisePropertyChangedAuto(); + InvalidateRelayCommands(); + + if (_selectedMachine != null) + { + _selectedMachine.Saved -= SelectedMachine_Saved; + _selectedMachine.Saved += SelectedMachine_Saved; + } + } + } + + private List<LiquidTypesRml> _liquidTypesRmls; + /// <summary> + /// Gets or sets the liquid types RMLS. + /// </summary> + public List<LiquidTypesRml> LiquidTypesRmls + { + get { return _liquidTypesRmls; } + set { _liquidTypesRmls = value; RaisePropertyChangedAuto(); } + } + + private ProcessParametersTablesGroup _rmlProcessParametersTablesGroup; + /// <summary> + /// Gets or sets the RML process parameters table group (cloned). + /// </summary> + public ProcessParametersTablesGroup RmlProcessParametersTableGroup + { + get { return _rmlProcessParametersTablesGroup; } + set + { _rmlProcessParametersTablesGroup = value; RaisePropertyChangedAuto(); OnProcessParametersTableGroupChanged(); } + } + + private ObservableCollection<ProcessParametersTablesGroup> _groupsHistory; + /// <summary> + /// Gets or sets the RML process parameters groups history. + /// </summary> + public ObservableCollection<ProcessParametersTablesGroup> GroupsHistory + { + get { return _groupsHistory; } + set { _groupsHistory = value; RaisePropertyChangedAuto(); } + } + + private ProcessParametersTablesGroup _selectedGroupHistory; + /// <summary> + /// Gets or sets the selected process parameters tables group history. + /// </summary> + public ProcessParametersTablesGroup SelectedGroupHistory + { + get { return _selectedGroupHistory; } + set { _selectedGroupHistory = value; RaisePropertyChangedAuto(); OnSelectedGroupHistoryChanged(); } + } + + private ProcessParametersTable _selectedProcessParametersTable; + /// <summary> + /// Gets or sets the selected process parameters table. + /// </summary> + public ProcessParametersTable SelectedProcessParametersTable + { + get { return _selectedProcessParametersTable; } + set { _selectedProcessParametersTable = value; RaisePropertyChangedAuto(); OnSelectedParametersTableChanged(); } + } + + private Job _activeJob; + /// <summary> + /// Gets or sets the selected machine job. + /// </summary> + public Job ActiveJob + { + get { return _activeJob; } + set + { + _activeJob = value; + RaisePropertyChangedAuto(); + OnActiveJobChanged(); + } + } + + private Job _selectedMachineJob; + /// <summary> + /// Gets or sets the selected machine job. + /// </summary> + public Job SelectedMachineJob + { + get { return _selectedMachineJob; } + set { _selectedMachineJob = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<Job> _selectedJobs; + /// <summary> + /// Gets or sets the selected jobs. + /// </summary> + public ObservableCollection<Job> SelectedJobs + { + get { return _selectedJobs; } + set { _selectedJobs = value; RaisePropertyChangedAuto(); } + } + + private Segment _selectedSegment; + /// <summary> + /// Gets or sets the job selected segment. + /// </summary> + public Segment SelectedSegment + { + get { return _selectedSegment; } + set { _selectedSegment = value; RaisePropertyChangedAuto(); OnSelectedSegmentChanged(); } + } + + private ObservableCollection<Segment> _selectedSegments; + /// <summary> + /// Gets or sets the selected segments. + /// </summary> + public ObservableCollection<Segment> SelectedSegments + { + get { return _selectedSegments; } + set { _selectedSegments = value; RaisePropertyChangedAuto(); } + } + + private BrushStop _selectedBrushStop; + /// <summary> + /// Gets or sets the selected segment selected brush stop. + /// </summary> + public BrushStop SelectedBrushStop + { + get { return _selectedBrushStop; } + set { _selectedBrushStop = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<BrushStop> _selectedBrushStops; + /// <summary> + /// Gets or sets the selected brush stops. + /// </summary> + public ObservableCollection<BrushStop> SelectedBrushStops + { + get { return _selectedBrushStops; } + set { _selectedBrushStops = value; RaisePropertyChangedAuto(); } + } + + private Rml _selectedRML; + /// <summary> + /// Gets or sets the selected RML. + /// </summary> + public Rml SelectedRML + { + get { return _selectedRML; } + set + { + _selectedRML = value; + InvalidateLiquidFactorsAndProcessTables(); + RaisePropertyChangedAuto(); + InvalidateRelayCommands(); + } + } + + private bool _isSideBarOpened; + /// <summary> + /// Gets or sets a value indicating whether the configuration panels are opened. + /// </summary> + public bool IsSideBarOpened + { + get { return _isSideBarOpened; } + set { _isSideBarOpened = value; RaisePropertyChangedAuto(); } + } + + private TimeSpan _estimatedDuration; + /// <summary> + /// Gets or sets the estimated duration for the selected job. + /// </summary> + public TimeSpan EstimatedDuration + { + get { return _estimatedDuration; } + set { _estimatedDuration = value; RaisePropertyChangedAuto(); } + } + + private bool _isJobRunning; + /// <summary> + /// Gets or sets a value indicating whether a job is currently running. + /// </summary> + public bool IsJobRunning + { + get { return _isJobRunning; } + set { _isJobRunning = value; RaisePropertyChangedAuto(); } + } + + private Job _runningJob; + /// <summary> + /// Gets or sets the currently running job. + /// </summary> + public Job RunningJob + { + get { return _runningJob; } + set { _runningJob = value; RaisePropertyChangedAuto(); } + } + + private double _runningJobProgress; + /// <summary> + /// Gets or sets the running job current progress. + /// </summary> + public double RunningJobProgress + { + get { return _runningJobProgress; } + set { _runningJobProgress = value; RaisePropertyChangedAuto(); } + } + + private TimeSpan _runningJobRemainingTime; + /// <summary> + /// Gets or sets the job remaining time. + /// </summary> + public TimeSpan RunningJobRemainingTime + { + get { return _runningJobRemainingTime; } + set { _runningJobRemainingTime = value; RaisePropertyChangedAuto(); } + } + + private bool _isJobCompleted; + /// <summary> + /// Gets or sets a value indicating whether the running job has completed successfully. + /// </summary> + public bool IsJobCompleted + { + get { return _isJobCompleted; } + set { _isJobCompleted = value; RaisePropertyChangedAuto(); } + } + + private bool _isJobFailed; + /// <summary> + /// Gets or sets a value indicating whether the running job has failed. + /// </summary> + public bool IsJobFailed + { + get { return _isJobFailed; } + set { _isJobFailed = value; RaisePropertyChangedAuto(); } + } + + private bool _showJobStatus; + /// <summary> + /// Gets or sets a value indicating whether to show all the relevant job status areas. + /// </summary> + public bool ShowJobStatus + { + get { return _showJobStatus; } + set { _showJobStatus = value; RaisePropertyChangedAuto(); } + } + + private bool _isJobCanceled; + /// <summary> + /// Gets or sets a value indicating whether the last running job was canceled. + /// </summary> + public bool IsJobCanceled + { + get { return _isJobCanceled; } + set { _isJobCanceled = value; RaisePropertyChangedAuto(); } + } + + private IMachineOperator _machineOperator; + /// <summary> + /// Gets or sets the machine operator. + /// </summary> + public IMachineOperator MachineOperator + { + get { return _machineOperator; } + set { _machineOperator = value; RaisePropertyChangedAuto(); } + } + + private IRealTimeGraph _fullScreenGraph; + /// <summary> + /// Gets or sets the full screen graph. + /// </summary> + public IRealTimeGraph FullScreenGraph + { + get { return _fullScreenGraph; } + set { _fullScreenGraph = value; RaisePropertyChangedAuto(); } + } + + private List<Segment> _runningJobSegments; + /// <summary> + /// Gets or sets the running job segments. + /// </summary> + public List<Segment> RunningJobSegments + { + get { return _runningJobSegments; } + set { _runningJobSegments = value; RaisePropertyChangedAuto(); } + } + + private ICollectionView _jobsCollectionView; + /// <summary> + /// Gets or sets the jobs collection view. + /// </summary> + public ICollectionView JobsCollectionView + { + get { return _jobsCollectionView; } + set + { + _jobsCollectionView = value; + BindingOperations.EnableCollectionSynchronization(_jobsCollectionView, _syncLock); + + RaisePropertyChangedAuto(); + } + } + + private ICollectionView _segmentsCollectionView; + /// <summary> + /// Gets or sets the segments collection view. + /// </summary> + public ICollectionView SegmentsCollectionView + { + get { return _segmentsCollectionView; } + set + { + _segmentsCollectionView = value; + BindingOperations.EnableCollectionSynchronization(_segmentsCollectionView, _syncLock); + RaisePropertyChangedAuto(); + } + } + + private ICollectionView _brushStopsCollectionView; + /// <summary> + /// Gets or sets the brush stops collection view. + /// </summary> + public ICollectionView BrushStopsCollectionView + { + get { return _brushStopsCollectionView; } + set + { + _brushStopsCollectionView = value; + BindingOperations.EnableCollectionSynchronization(_brushStopsCollectionView, _syncLock); + RaisePropertyChangedAuto(); + } + } + + private String _jobFilter; + /// <summary> + /// Gets or sets the job filter. + /// </summary> + public String JobFilter + { + get { return _jobFilter; } + set { _jobFilter = value; RaisePropertyChangedAuto(); OnJobFilterChanged(); } + } + + #endregion + + #region Commands + + /// <summary> + /// Gets or sets the edit machine command. + /// </summary> + public RelayCommand EditMachineCommand { get; set; } + + /// <summary> + /// Gets or sets the edit RML command. + /// </summary> + public RelayCommand EditRMLCommand { get; set; } + + /// <summary> + /// Gets or sets the toggle side bar command. + /// </summary> + public RelayCommand ToggleSideBarCommand { get; set; } + + /// <summary> + /// Gets or sets the save process parameters command. + /// </summary> + public RelayCommand SaveProcessParametersCommand { get; set; } + + /// <summary> + /// Gets or sets the save liquid factors command. + /// </summary> + public RelayCommand SaveLiquidFactorsCommand { get; set; } + + /// <summary> + /// Gets or sets the add segment command. + /// </summary> + public RelayCommand AddSegmentCommand { get; set; } + + /// <summary> + /// Gets or sets the remove segment command. + /// </summary> + public RelayCommand RemoveSegmentCommand { get; set; } + + /// <summary> + /// Gets or sets the add job command. + /// </summary> + public RelayCommand AddJobCommand { get; set; } + + /// <summary> + /// Gets or sets the remove job command. + /// </summary> + public RelayCommand RemoveJobCommand { get; set; } + + /// <summary> + /// Gets or sets the add brush stop command. + /// </summary> + public RelayCommand AddBrushStopCommand { get; set; } + + /// <summary> + /// Gets or sets the remove brush stop command. + /// </summary> + public RelayCommand RemoveBrushStopCommand { get; set; } + + /// <summary> + /// Gets or sets the save job command. + /// </summary> + public RelayCommand SaveJobCommand { get; set; } + + /// <summary> + /// Gets or sets the discard job command. + /// </summary> + public RelayCommand DiscardJobCommand { get; set; } + + /// <summary> + /// Gets or sets the start job command. + /// </summary> + public RelayCommand StartJobCommand { get; set; } + + /// <summary> + /// Gets or sets the stop job command. + /// </summary> + public RelayCommand StopJobCommand { get; set; } + + /// <summary> + /// Gets or sets the close job completion status command. + /// </summary> + public RelayCommand CloseJobCompletionStatusCommand { get; set; } + + /// <summary> + /// Gets or sets the load job command. + /// </summary> + public RelayCommand LoadJobCommand { get; set; } + + /// <summary> + /// Gets or sets the duplicate job command. + /// </summary> + public RelayCommand DuplicateJobCommand { get; set; } + + /// <summary> + /// Gets or sets the duplicate segment command. + /// </summary> + public RelayCommand DuplicateSegmentCommand { get; set; } + + /// <summary> + /// Gets or sets the duplicate brush stop command. + /// </summary> + public RelayCommand DuplicateBrushStopCommand { get; set; } + + #endregion + + #region Constructors + + /// <summary> + /// Initializes a new instance of the <see cref="MainViewVM"/> class. + /// </summary> + public MainViewVM(IMainView view) : base(view, true) + { + + } + + /// <summary> + /// Initializes a new instance of the <see cref="MainViewVM"/> class. + /// </summary> + /// <param name="applicationManager">The application manager.</param> + /// <param name="notificationProvider">The notification provider.</param> + [PreferredConstructor] + public MainViewVM(IMainView view, IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, IAuthenticationProvider authentication) : this(view) + { + SelectedJobs = new ObservableCollection<Job>(); + + LogManager.Log("Initializing machine Db context..."); + _machineDbContext = ObservablesContext.CreateDefault(); + + if (SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedMachineGuid != null) + { + LogManager.Log("Setting last selected machine from settings..."); + SelectedMachine = _machineDbContext.Machines.SingleOrDefault(x => x.Guid == SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedMachineGuid); + } + + if (SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedJobGuid != null && SelectedMachine != null) + { + LogManager.Log("Setting last selected job from settings..."); + SelectedMachineJob = SelectedMachine.Jobs.SingleOrDefault(x => x.Guid == SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedJobGuid); + } + + + _authentication = authentication; + + _notification = notificationProvider; + _navigation = navigation; + ApplicationManager = applicationManager; + VideoCaptureProvider = videoCaptureProvider; + + LogManager.Log("Initializing relay commands..."); + + //Initialize Commands... + EditMachineCommand = new RelayCommand(EditMachine, () => SelectedMachine != null); + EditRMLCommand = new RelayCommand(EditRML, () => SelectedRML != null); + ToggleSideBarCommand = new RelayCommand(() => IsSideBarOpened = !IsSideBarOpened); + SaveProcessParametersCommand = new RelayCommand(SaveProcessParameters, () => SelectedRML != null && SelectedRML.ProcessParametersTablesGroups.Count > 0); + SaveLiquidFactorsCommand = new RelayCommand(SaveLiquidFactors, () => SelectedRML != null); + AddSegmentCommand = new RelayCommand(AddSegment, () => ActiveJob != null); + RemoveSegmentCommand = new RelayCommand(RemoveSelectedSegments, () => SelectedSegment != null); + AddJobCommand = new RelayCommand(AddJob, () => SelectedMachine != null); + RemoveJobCommand = new RelayCommand(RemoveSelectedJobs, () => SelectedMachineJob != null); + AddBrushStopCommand = new RelayCommand(AddBrushStop, () => SelectedSegment != null); + RemoveBrushStopCommand = new RelayCommand(RemoveSelectedBrushStops, () => SelectedBrushStop != null); + SaveJobCommand = new RelayCommand(SaveActiveJob, () => SelectedMachine != null); + DiscardJobCommand = new RelayCommand(BackToJobs, () => SelectedMachine != null); + StartJobCommand = new RelayCommand(StartJob, () => ActiveJob != null && !IsJobRunning); + StopJobCommand = new RelayCommand(StopJob, () => IsJobRunning); + CloseJobCompletionStatusCommand = new RelayCommand(CloseJobCompletionStatusBar); + LoadJobCommand = new RelayCommand(LoadSelectedJob, () => SelectedMachineJob != null); + DuplicateJobCommand = new RelayCommand(DuplicateSelectedJobs, () => SelectedMachineJob != null); + DuplicateSegmentCommand = new RelayCommand(DuplicateSelectedSegments, () => SelectedSegment != null); + DuplicateBrushStopCommand = new RelayCommand(DuplicateSelectedBrushStops, () => SelectedBrushStop != null); + + ApplicationManager.ConnectedMachineChanged += ApplicationManager_ConnectedMachineChanged; + } + + #endregion + + #region Event Handlers + + /// <summary> + /// Handles the application manager connected machine changes event. + /// </summary> + /// <param name="sender">The sender.</param> + /// <param name="machine">The machine.</param> + private void ApplicationManager_ConnectedMachineChanged(object sender, IExternalBridgeClient machine) + { + MachineOperator = machine; + } + + /// <summary> + /// Handles the Saved event of the SelectedMachine. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> + private void SelectedMachine_Saved(object sender, EventArgs e) + { + InvalidateLiquidFactorsAndProcessTables(); + SelectedMachine.Reload(_machineDbContext); + } + + /// <summary> + /// Handles the LengthChanged event of the SelectedJob. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> + private void ActiveJob_LengthChanged(object sender, EventArgs e) + { + UpdateEstimatedDuration(); + } + + /// <summary> + /// Handles the DyeingSpeedMinInkUptakeChanged event of the SelectedProcessParametersTable. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> + private void SelectedProcessParametersTable_DyeingSpeedMinInkUptakeChanged(object sender, EventArgs e) + { + if (SelectedSegment != null) + { + foreach (var liquidVolume in SelectedSegment.BrushStops.SelectMany(x => x.LiquidVolumes)) + { + liquidVolume.Invalidate(); + } + } + + UpdateEstimatedDuration(); + } + + #endregion + + #region Properties Changes + + /// <summary> + /// Called when the selected parameters table has changed. + /// </summary> + protected virtual void OnSelectedParametersTableChanged() + { + if (SelectedProcessParametersTable != null) + { + LogManager.Log("Selected process parameters table changed."); + SelectedProcessParametersTable.DyeingSpeedMinInkUptakeChanged -= SelectedProcessParametersTable_DyeingSpeedMinInkUptakeChanged; + SelectedProcessParametersTable.DyeingSpeedMinInkUptakeChanged += SelectedProcessParametersTable_DyeingSpeedMinInkUptakeChanged; + + SetSegmentBrushStopsLiquidVolumes(SelectedSegment); + UpdateEstimatedDuration(); + } + } + + /// <summary> + /// Called when the process parameters table group has been changed + /// </summary> + protected virtual void OnProcessParametersTableGroupChanged() + { + if (RmlProcessParametersTableGroup != null && RmlProcessParametersTableGroup.ProcessParametersTables.Count > 0) + { + LogManager.Log("Process parameters group changed..."); + SelectedProcessParametersTable = RmlProcessParametersTableGroup.ProcessParametersTables.OrderBy(x => x.TableIndex).FirstOrDefault(); + + UpdateEstimatedDuration(); + } + } + + /// <summary> + /// Called when the selected segment has been changed + /// </summary> + protected virtual void OnSelectedSegmentChanged() + { + if (SelectedSegment != null) + { + LogManager.Log("Selected segment changed..."); + SetSegmentBrushStopsLiquidVolumes(SelectedSegment); + SelectedBrushStop = SelectedSegment.BrushStops.FirstOrDefault(); + + BrushStopsCollectionView = CollectionViewSource.GetDefaultView(SelectedSegment.BrushStops); + BrushStopsCollectionView.SortDescriptions.Add(new SortDescription(nameof(BrushStop.StopIndex), ListSortDirection.Ascending)); + } + } + + /// <summary> + /// Called when the selected group history has been changed + /// </summary> + protected virtual void OnSelectedGroupHistoryChanged() + { + if (SelectedGroupHistory != null) + { + LogManager.Log(String.Format("Parameters group {0} selected from history.", SelectedGroupHistory.Name)); + RmlProcessParametersTableGroup = SelectedGroupHistory.CloneGroup(); + } + } + + /// <summary> + /// Called when the machine has been changed + /// </summary> + protected virtual void OnSelectedMachineChanged() + { + if (SelectedMachine != null) + { + LogManager.Log(String.Format("Machine {0} changed.", SelectedMachine.SerialNumber)); + ReloadMachine(); + JobsCollectionView = CollectionViewSource.GetDefaultView(SelectedMachine.Jobs); + JobsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Job.LastUpdated), ListSortDirection.Descending)); + } + } + + /// <summary> + /// Called when the job filtering has changed. + /// </summary> + protected virtual void OnJobFilterChanged() + { + String filter = JobFilter.ToLower(); + + JobsCollectionView.Filter = (job) => + { + Job j = job as Job; + return String.IsNullOrWhiteSpace(filter) + || + j.Name.ToLower().Contains(filter) //Job name + || + j.User.Contact.FirstName.ToLower().Contains(filter) // User first name + || + j.Length.ToString().Contains(filter); //Job length + }; + } + + /// <summary> + /// Called when the active job has changed. + /// </summary> + protected virtual void OnActiveJobChanged() + { + if (ActiveJob != null) + { + LogManager.Log(String.Format("Active job {0} changed.", ActiveJob.Name)); + SegmentsCollectionView = CollectionViewSource.GetDefaultView(ActiveJob.Segments); + SegmentsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Segment.SegmentIndex), ListSortDirection.Ascending)); + } + } + + #endregion + + #region Drag & Drop + + /// <summary> + /// Switch the segment position in the job. + /// </summary> + /// <param name="dragged">The dragged.</param> + /// <param name="dropped">The dropped.</param> + public void OnDropSegment(Segment dragged, Segment dropped) + { + LogManager.Log(String.Format("Segment {0} Dropped on segment {1}", dragged.SegmentIndex, dropped.SegmentIndex)); + + dragged.SegmentIndex = dropped.SegmentIndex; + dropped.SegmentIndex++; + + int index = 1; + + foreach (var segment in ActiveJob.Segments.OrderBy(x => x.SegmentIndex)) + { + segment.SegmentIndex = index++; + } + + SegmentsCollectionView.Refresh(); + } + + /// <summary> + /// Switch the brush stop position in the segment. + /// </summary> + /// <param name="dragged">The dragged stop.</param> + /// <param name="dropped">The dropped stop.</param> + public void OnDropBrushStop(BrushStop dragged, BrushStop dropped) + { + LogManager.Log(String.Format("BrushStop {0} Dropped on BrushStop {1}", dragged.StopIndex, dropped.StopIndex)); + + dragged.SetStopIndex(dropped.StopIndex); + dropped.SetStopIndex(dropped.StopIndex + 1); + ArrangeBrushStopsIndices(); + } + + #endregion + + #region Running Job Management + + /// <summary> + /// Closes the job completion status bar. + /// </summary> + private void CloseJobCompletionStatusBar() + { + LogManager.Log("Closing job completion status bar..."); + _navigation.NavigateTo(DeveloperNavigationView.JobView); + IsJobCompleted = false; + IsJobFailed = false; + IsJobCanceled = false; + ShowJobStatus = false; + RunningJob = null; + } + + /// <summary> + /// Stops the job. + /// </summary> + private void StopJob() + { + LogManager.Log("Stopping job..."); + IsJobRunning = false; + IsJobCanceled = true; + _jobHandler.Cancel(); + } + + /// <summary> + /// Fails the job. + /// </summary> + private void SetJobFailed() + { + LogManager.Log("Setting job failed state..."); + IsJobRunning = false; + IsJobFailed = true; + } + + /// <summary> + /// Completes the job. + /// </summary> + private void SetJobCompleted() + { + LogManager.Log("Setting job completed state..."); + IsJobRunning = false; + IsJobCompleted = true; + } + + /// <summary> + /// Starts the job. + /// </summary> + private void StartJob() + { + LogManager.Log(String.Format("Starting job {0}...", ActiveJob.Name)); + if (MachineOperator == null || MachineOperator.State != TransportComponentState.Connected) + { + _notification.ShowError("No machine connected. Could not execute the specified job."); + return; + } + + if (SelectedProcessParametersTable == null) + { + _notification.ShowError("No process parameters table selected. Could not execute the specified job."); + return; + } + + RunningJobRemainingTime = TimeSpan.Zero; + RunningJobProgress = 0; + IsJobFailed = false; + IsJobCanceled = false; + IsJobCompleted = false; + IsJobRunning = true; + ShowJobStatus = true; + RunningJob = ActiveJob; + _runningJobEstimatedDuration = EstimatedDuration; + + RunningJobSegments = CreateRunningJobEffectiveSegments(RunningJob); + + _navigation.NavigateTo(DeveloperNavigationView.RunningJobView); + + LogManager.Log("Sending job to machine operator..."); + _jobHandler = MachineOperator.Print(ActiveJob, SelectedProcessParametersTable); + + _jobHandler.StatusReceived += (x, status) => + { + RunningJobRemainingTime = _runningJobEstimatedDuration - TimeSpan.FromSeconds(RunningJobProgress / (SelectedProcessParametersTable.DyeingSpeed / 100d)); + RunningJobProgress = status.Progress; + + foreach (var segment in RunningJobSegments) + { + var previousSegmentsWithThis = RunningJobSegments.Where(s => RunningJobSegments.IndexOf(s) <= RunningJobSegments.IndexOf(segment)).ToList(); + var segmentsDuration = TimeSpan.FromSeconds(previousSegmentsWithThis.Sum(s => s.Length) / (SelectedProcessParametersTable.DyeingSpeed / 100d)); + var segmentDuration = TimeSpan.FromSeconds(segment.Length / (SelectedProcessParametersTable.DyeingSpeed / 100d)); + TimeSpan remaining = segmentsDuration - TimeSpan.FromSeconds(RunningJobProgress / (SelectedProcessParametersTable.DyeingSpeed / 100d)); + if (remaining >= TimeSpan.Zero) + { + segment.RemainingTime = remaining; + } + if (remaining < segmentDuration) + { + segment.Started = true; + } + if (remaining <= TimeSpan.Zero) + { + segment.Completed = true; + segment.Started = false; + } + } + }; + + _jobHandler.Failed += (x, ex) => + { + LogManager.Log(ex, String.Format("Job {0} has failed.", RunningJob.Name)); + SetJobFailed(); + + InvokeUI(() => + { + _notification.ShowError("Job failed. " + ex.Message); + }); + }; + + _jobHandler.Completed += (x, e) => + { + LogManager.Log(String.Format("Job {0} has completed.", RunningJob.Name)); + SetJobCompleted(); + }; + + _jobHandler.Canceled += (x, y) => + { + LogManager.Log(String.Format("Job {0} has been canceled.", RunningJob.Name)); + //Finally Canceled.. + }; + } + + /// <summary> + /// Creates the running job effective segments. + /// </summary> + /// <param name="job">The job.</param> + /// <returns></returns> + private List<Segment> CreateRunningJobEffectiveSegments(Job job) + { + LogManager.Log("Creating job effective segments..."); + + List<Segment> segments = new List<Segment>(); + foreach (var s in job.Segments) + { + s.Completed = false; + s.Started = false; + segments.Add(s); + + if (job.EnableInterSegment && job.Segments.IndexOf(s) != job.Segments.Count - 1) + { + segments.Add(new Segment() + { + Length = job.InterSegmentLength, + BrushStops = new System.Collections.ObjectModel.ObservableCollection<BrushStop>() + { + new BrushStop() + { + Color = Colors.White, + } + }, + Started = false, + Completed = false + }); + } + } + + return segments; + } + + #endregion + + #region RML + + /// <summary> + /// Saves the liquid factors. + /// </summary> + private async void SaveLiquidFactors() + { + if (SelectedRML != null) + { + using (_notification.PushTaskItem("Saving Liquid Factors...")) + { + LogManager.Log(String.Format("Saving liquid factors for RML {0}...", SelectedRML.Name)); + await SelectedRML.SaveAsync(_activeJobDbContext); + InvalidateLiquidFactorsAndProcessTables(); + } + } + } + + /// <summary> + /// Navigates to the DB Module in order to edit the selected RML. + /// </summary> + private void EditRML() + { + LogManager.Log(String.Format("Requesting DB module for RML {0} editing...", SelectedRML.Name)); + ApplicationManager.RequestModule("Data Base", SelectedRML); + } + + /// <summary> + /// Saves the process parameters group. + /// </summary> + private async void SaveProcessParameters() + { + var response = _notification.ShowTextInput("Enter Group Name", "Group Name"); + + if (response == null) return; + + using (_notification.PushTaskItem("Saving Parameters Group...")) + { + LogManager.Log(String.Format("Saving process parameters group under the name {0}...", response)); + ProcessParametersTablesGroup group = new ProcessParametersTablesGroup(); + + List<ProcessParametersTable> tables = new List<ProcessParametersTable>(); + foreach (var table in RmlProcessParametersTableGroup.ProcessParametersTables) + { + var newTable = table.CloneEntity(); + newTable.ProcessParametersTablesGroup = group; + tables.Add(newTable); + } + + group.Active = true; + group.ProcessParametersTables = tables.ToObservableCollection(); + group.Rml = SelectedRML; + group.Name = response; + group.SaveDate = DateTime.UtcNow; + + foreach (var g in SelectedRML.ProcessParametersTablesGroups) + { + g.Active = false; + } + + SelectedRML.ProcessParametersTablesGroups.Add(group); + await SelectedRML.SaveAsync(_activeJobDbContext); + + InvalidateLiquidFactorsAndProcessTables(); + } + } + + /// <summary> + /// Invalidates the liquid factors and process parameters tables. + /// </summary> + private void InvalidateLiquidFactorsAndProcessTables() + { + if (SelectedRML != null && SelectedMachine != null) + { + LogManager.Log("Invalidating liquid factors, process parameters and process group history..."); + LiquidTypesRmls = SelectedMachine.Configuration.IdsPacks.OrderBy(x => x.PackIndex).Select(x => x.LiquidType).SelectMany(x => x.LiquidTypesRmls).Where(x => x.Rml.Guid == SelectedRML.Guid).ToList(); + RmlProcessParametersTableGroup = SelectedRML.ProcessParametersTablesGroups.ToList().SingleOrDefault(x => x.Active); + + var selectedHistory = RmlProcessParametersTableGroup; + + if (RmlProcessParametersTableGroup != null) + { + RmlProcessParametersTableGroup = RmlProcessParametersTableGroup.CloneGroup(); + RmlProcessParametersTableGroup.ProcessParametersTables = RmlProcessParametersTableGroup.ProcessParametersTables.OrderBy(x => x.TableIndex).ToObservableCollection(); + } + + GroupsHistory = SelectedRML.ProcessParametersTablesGroups.OrderByDescending(x => x.SaveDate).OrderBy(x => !x.Active).ToObservableCollection(); + + _selectedGroupHistory = selectedHistory; + + RaisePropertyChangedAuto(nameof(SelectedGroupHistory)); + } + } + + #endregion + + #region Active Job Management + + /// <summary> + /// Loads the selected job. + /// </summary> + private void LoadSelectedJob() + { + if (SelectedMachineJob != null) + { + using (_notification.PushTaskItem("Loading job details...")) + { + LogManager.Log(String.Format("Loading job {0}...", SelectedMachineJob.Name)); + SelectedSegments = new ObservableCollection<Segment>(); + SelectedBrushStops = new ObservableCollection<BrushStop>(); + SelectedRML = null; + SelectedSegment = null; + SelectedGroupHistory = null; + SelectedBrushStop = null; + SelectedProcessParametersTable = null; + RmlProcessParametersTableGroup = null; + + + _blockInvalidateCommands = false; + + LogManager.Log("Creating active job DB context..."); + _activeJobDbContext = ObservablesContext.CreateDefault(); + _activeJobDbContext.Configuration.LazyLoadingEnabled = true; + + LogManager.Log("Initializing available color spaces, RMLs & Winding methods..."); + ColorSpaces = _activeJobDbContext.ColorSpaces.ToObservableCollection(); + Rmls = _activeJobDbContext.Rmls.ToObservableCollection(); + WindingMethods = _activeJobDbContext.WindingMethods.ToObservableCollection(); + + LogManager.Log("Setting active job..."); + _activeJob = _activeJobDbContext.Jobs.SingleOrDefault(x => x.Guid == SelectedMachineJob.Guid); + + _selectedRML = ActiveJob.Rml; + + LogManager.Log("Setting selected segment..."); + _selectedSegment = ActiveJob.Segments.FirstOrDefault(); + + ActiveJob.LengthChanged -= ActiveJob_LengthChanged; + ActiveJob.LengthChanged += ActiveJob_LengthChanged; + + ActiveJob = _activeJob; + + SelectedRML = _selectedRML; + SelectedSegment = _selectedSegment; + + UpdateEstimatedDuration(); + + _blockInvalidateCommands = false; + InvalidateRelayCommands(); + + _navigation.NavigateTo(DeveloperNavigationView.JobView); + } + } + } + + /// <summary> + /// Saves the active job. + /// </summary> + private async void SaveActiveJob() + { + if (ActiveJob != null) + { + using (_notification.PushTaskItem("Saving job details...")) + { + LogManager.Log(String.Format("Saving the active job {0}...", ActiveJob.Name)); + ActiveJob.LastUpdated = DateTime.UtcNow; + ActiveJob.Rml = SelectedRML; + + await ActiveJob.SaveAsync(_activeJobDbContext); + ReloadMachine(); + SelectedMachineJob = SelectedMachine.Jobs.SingleOrDefault(x => x.Guid == ActiveJob.Guid); + } + } + } + + private void BackToJobs() + { + LogManager.Log("User request for 'back to jobs'..."); + LogManager.Log("Comparing active job with selected job..."); + + bool jobModified = !ActiveJob.CompareUsingJson(SelectedMachineJob); + + if (jobModified) + { + LogManager.Log("Selected job has been modified. Invoking confirmation dialog..."); + if (_notification.ShowQuestion("This will discard the current job changes. Are you sure?")) + { + LogManager.Log("Disposing active job db context..."); + _activeJobDbContext.Dispose(); + _navigation.NavigateTo(DeveloperNavigationView.MachineJobSelectionView); + } + } + else + { + LogManager.Log("Disposing active job db context..."); + _activeJobDbContext.Dispose(); + _navigation.NavigateTo(DeveloperNavigationView.MachineJobSelectionView); + } + } + + #endregion + + #region Private Methods + + private void ReloadMachine() + { + LogManager.Log("Reloading selected machine..."); + _machineDbContext.Dispose(); + _machineDbContext = ObservablesContext.CreateDefault(); + _machineDbContext.Configuration.LazyLoadingEnabled = true; + String machineGuid = _selectedMachine.Guid; + Machines = _machineDbContext.Machines.ToObservableCollection(); + _selectedMachine = Machines.SingleOrDefault(x => x.Guid == machineGuid); + RaisePropertyChanged(nameof(SelectedMachine)); + + JobsCollectionView = CollectionViewSource.GetDefaultView(SelectedMachine.Jobs); + JobsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Job.LastUpdated), ListSortDirection.Descending)); + } + + private void UpdateEstimatedDuration() + { + if (ActiveJob != null && SelectedProcessParametersTable != null && SelectedProcessParametersTable.DyeingSpeed > 0) + { + EstimatedDuration = TimeSpan.FromSeconds(ActiveJob.Length / (SelectedProcessParametersTable.DyeingSpeed / 100d)); + } + } + + private void SetSegmentBrushStopsLiquidVolumes(Segment segment) + { + if (!DesignMode && segment != null) + { + LogManager.Log("Setting segment brush stops liquid volumes..."); + foreach (var stop in segment.BrushStops) + { + stop.SetLiquidVolumes(SelectedMachine.Configuration, SelectedRML, SelectedProcessParametersTable); + } + } + } + + /// <summary> + /// Navigates to the Machine Designer Module in order to edit the selected machine. + /// </summary> + private void EditMachine() + { + LogManager.Log(String.Format("Requesting machine designer module for machine {0} editing...", SelectedMachine.SerialNumber)); + ApplicationManager.RequestModule("Machine Designer", SelectedMachine); + } + + #endregion + + #region Add / Remove / Duplicate Jobs, Segments & Brush Stops + + /// <summary> + /// Arranges the segments indices. + /// </summary> + private void ArrangeSegmentsIndices() + { + int index = 1; + + foreach (var segment in ActiveJob.Segments.OrderBy(x => x.SegmentIndex)) + { + segment.SegmentIndex = index++; + } + + SegmentsCollectionView.Refresh(); + } + + /// <summary> + /// Arranges the brush stops indices. + /// </summary> + private void ArrangeBrushStopsIndices() + { + int index = 0; + + foreach (var stop in SelectedSegment.BrushStops.OrderBy(x => x.StopIndex)) + { + stop.SetStopIndex(index++); + } + + if (SelectedSegment.BrushStops.Count > 1) + { + SelectedSegment.BrushStops.OrderBy(x => x.StopIndex).First().OffsetPercent = 0; + SelectedSegment.BrushStops.OrderBy(x => x.StopIndex).Last().OffsetPercent = 100; + } + + foreach (var stop in SelectedSegment.BrushStops.OrderBy(x => x.StopIndex)) + { + stop.RaiseStopIndex(); + stop.RaiseOffsetChanged(); + } + + BrushStopsCollectionView.Refresh(); + } + + /// <summary> + /// Removes the selected segments. + /// </summary> + private void RemoveSelectedSegments() + { + if (ActiveJob != null && SelectedSegment != null) + { + if (_notification.ShowQuestion("Are you sure you want to delete the selected segments?")) + { + LogManager.Log(String.Format("Removing {0} segments...", SelectedSegments.Count)); + + SelectedSegments.ToList().ForEach(x => + { + ActiveJob.Segments.Remove(x); + x.DefferedDelete(_activeJobDbContext); + }); + + ArrangeSegmentsIndices(); + } + } + } + + /// <summary> + /// Adds a new segment. + /// </summary> + private void AddSegment() + { + if (ActiveJob != null) + { + LogManager.LogFormat("Adding new segment to job {0}...", ActiveJob.Name); + Segment seg = new Segment(); + seg.Name = "Untitled Segment"; + seg.Length = 10; + + if (ActiveJob.Segments.Count > 0) + { + seg.SegmentIndex = ActiveJob.Segments.Max(x => x.SegmentIndex) + 1; + } + else + { + seg.SegmentIndex = 1; + } + ActiveJob.Segments.Add(seg); + SelectedSegment = seg; + AddBrushStop(); + ArrangeSegmentsIndices(); + } + } + + /// <summary> + /// Removes the selected jobs. + /// </summary> + private async void RemoveSelectedJobs() + { + if (SelectedMachine != null && SelectedMachineJob != null) + { + if (_notification.ShowQuestion("Are you sure you want to delete the selected jobs?")) + { + LogManager.Log(String.Format("Removing {0} jobs...", SelectedJobs.Count)); + SelectedJobs.ToList().ForEach(x => + { + SelectedMachine.Jobs.Remove(x); + x.DefferedDelete(_machineDbContext); + }); + + using (_notification.PushTaskItem("Removing selected jobs...")) + { + LogManager.Log("Saving selected machine to database..."); + await SelectedMachine.SaveAsync(_machineDbContext); + } + } + } + } + + /// <summary> + /// Adds a new job to the selected machine. + /// </summary> + private async void AddJob() + { + if (SelectedMachine != null) + { + String jobName = _notification.ShowTextInput("Please provide a job name", "Name"); + + if (!String.IsNullOrWhiteSpace(jobName)) + { + LogManager.Log(String.Format("Adding new job {0}...", jobName)); + + Job newJob = new Job(); + newJob.Name = jobName; + newJob.CreationDate = DateTime.UtcNow; + newJob.User = _authentication.CurrentUser; + newJob.Rml = _machineDbContext.Rmls.FirstOrDefault(); + newJob.WindingMethod = _machineDbContext.WindingMethods.FirstOrDefault(); + newJob.Machine = SelectedMachine; + + SelectedMachine.Jobs.Add(newJob); + LogManager.Log("Saving selected machine to database..."); + await SelectedMachine.SaveAsync(_machineDbContext); + SelectedMachineJob = newJob; + LoadSelectedJob(); + AddSegment(); + } + } + } + + /// <summary> + /// Removes the selected brush stop. + /// </summary> + private void RemoveSelectedBrushStops() + { + if (SelectedBrushStop != null && SelectedSegment != null) + { + if (_notification.ShowQuestion("Are you sure you want to delete the selected colors?")) + { + LogManager.Log(String.Format("Removing {0} brush stops...", SelectedBrushStops.Count)); + + SelectedBrushStops.ToList().ForEach(x => + { + SelectedSegment.BrushStops.Remove(x); + x.DefferedDelete(_activeJobDbContext); + }); + + ArrangeBrushStopsIndices(); + } + } + } + + /// <summary> + /// Adds a new brush stop to the selected segment. + /// </summary> + private void AddBrushStop() + { + if (SelectedSegment != null) + { + LogManager.LogFormat("Adding new brush stop to segment...", SelectedSegment.SegmentIndex.ToString()); + + var stop = new BrushStop(); + + if (SelectedSegment.BrushStops.Count > 0) + { + stop.StopIndex = SelectedSegment.BrushStops.Max(x => x.StopIndex) + 1; + } + else + { + stop.StopIndex = 0; + } + + stop.OffsetPercent = 100; + stop.Segment = SelectedSegment; + stop.ColorSpace = _activeJobDbContext.ColorSpaces.FirstOrDefault(); + stop.Color = Colors.Black; + stop.SetLiquidVolumes(SelectedMachine.Configuration, SelectedRML, SelectedProcessParametersTable); + SelectedSegment.BrushStops.Add(stop); + SelectedSegment.BrushStops.ToList().ForEach(x => x.RaiseOffsetChanged()); + ArrangeBrushStopsIndices(); + } + } + + /// <summary> + /// Duplicates the selected brush stops. + /// </summary> + private void DuplicateSelectedBrushStops() + { + LogManager.LogFormat("Duplicating {0} brush stops...", SelectedBrushStops.Count); + + foreach (var stop in SelectedBrushStops.OrderBy(x => x.StopIndex)) + { + var cloned = stop.Clone(); + cloned.StopIndex = SelectedSegment.BrushStops.Max(x => x.StopIndex) + 1; + SelectedSegment.BrushStops.Add(cloned); + } + + ArrangeBrushStopsIndices(); + } + + /// <summary> + /// Duplicates the selected segments. + /// </summary> + private void DuplicateSelectedSegments() + { + LogManager.LogFormat("Duplicating {0} segments...", SelectedSegments.Count); + + foreach (var segment in SelectedSegments.OrderBy(x => x.SegmentIndex)) + { + var cloned = segment.Clone(); + cloned.SegmentIndex = ActiveJob.Segments.Max(x => x.SegmentIndex) + 1; + ActiveJob.Segments.Add(cloned); + } + + ArrangeSegmentsIndices(); + } + + /// <summary> + /// Duplicates the selected jobs. + /// </summary> + private async void DuplicateSelectedJobs() + { + if (SelectedMachineJob != null) + { + using (_notification.PushTaskItem("Cloning selected jobs...")) + { + LogManager.LogFormat("Duplicating {0} jobs...", SelectedJobs.Count); + + int index = SelectedMachine.Jobs.Max(x => x.JobIndex); + + foreach (var job in SelectedJobs) + { + var cloned = job.Clone(); + cloned.JobIndex = ++index; + SelectedMachine.Jobs.Add(cloned); + } + + LogManager.Log("Saving selected machine to database..."); + await SelectedMachine.SaveAsync(_machineDbContext); + } + } + } + + #endregion + + #region Override Methods + + protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) + { + base.RaisePropertyChangedAuto(caller); + + if (!_blockInvalidateCommands) + { + InvalidateRelayCommands(); + } + } + + #endregion + + #region IShutdownRequestBlocker + + public Task<bool> OnShutdownRequest() + { + if (IsJobRunning) + { + InvokeUI(() => + { + _notification.ShowWarning("Please stop the currently running job before closing the developer module."); + }); + + return Task.FromResult(false); + } + + return Task.FromResult(true); + } + + #endregion + + #region IShutdownListener + + public void OnShuttingDown() + { + SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedMachineGuid = SelectedMachine != null ? SelectedMachine.Guid : null; + SettingsManager.Default.MachineStudio.DeveloperModule.LastSelectedJobGuid = SelectedMachineJob != null ? SelectedMachineJob.Guid : null; + } + + #endregion + + #region IMainView + + protected override void OnViewAttached() + { + base.OnViewAttached(); + } + + #endregion + } +} |
