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.BL.Entities; using Tango.Integration.Operation; 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; using Tango.BL; using Microsoft.Win32; using Tango.PMR.Embroidery; using Tango.EmbroideryUI; using System.IO; using System.Windows; using Tango.Core.Helpers; using System.Speech.Synthesis; using System.Media; using Tango.MachineStudio.Common.EventLogging; namespace Tango.MachineStudio.Developer.ViewModels { /// /// Represents the developer module main view, view model. /// /// public class MainViewVM : ViewModel, IShutdownRequestBlocker, IShutdownListener { private static object _syncLock = new object(); private const string EMB_FORMATS_EXPORT = "Baby Lock (PES)|*.pes|Tajima (DST)|*.dst|EXP|*.exp|PCS|*.pcs|HUS|*.hus|KSM|*.ksm"; private const string EMB_FORMATS_IMPORT = "Embroidery Files|*.pes;*.hus;*.dst"; private INotificationProvider _notification; private TimeSpan _runningJobEstimatedDuration; private JobHandler _jobHandler; private DeveloperNavigationManager _navigation; private bool _blockInvalidateCommands; private IAuthenticationProvider _authentication; private ObservablesContext _machineDbContext; private ObservablesContext _activeJobDbContext; private SpeechSynthesizer _speech; private SoundPlayer _soundPlayer; private SoundPlayer _soundPlayerErr; private IEventLogger _eventLogger; #region Properties private ObservableCollection _machines; /// /// Gets or sets the machines. /// public ObservableCollection Machines { get { return _machines; } set { _machines = value; RaisePropertyChangedAuto(); } } private ObservableCollection _colorSpaces; /// /// Gets or sets the color spaces. /// public ObservableCollection ColorSpaces { get { return _colorSpaces; } set { _colorSpaces = value; RaisePropertyChangedAuto(); } } private ObservableCollection _rmls; /// /// Gets or sets the RMLS. /// public ObservableCollection Rmls { get { return _rmls; } set { _rmls = value; RaisePropertyChangedAuto(); } } private ObservableCollection _windingMethods; /// /// Gets or sets the winding methods. /// public ObservableCollection WindingMethods { get { return _windingMethods; } set { _windingMethods = value; RaisePropertyChangedAuto(); } } private ObservableCollection _spoolTypes; /// /// Gets or sets the spool types. /// public ObservableCollection SpoolTypes { get { return _spoolTypes; } set { _spoolTypes = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the application manager. /// public IStudioApplicationManager ApplicationManager { get; set; } /// /// Gets or sets the video capture provider. /// public IVideoCaptureProvider VideoCaptureProvider { get; set; } protected Machine _selectedMachine; /// /// Gets or sets the selected machine. /// 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 _liquidTypesRmls; /// /// Gets or sets the liquid types RMLS. /// public List LiquidTypesRmls { get { return _liquidTypesRmls; } set { _liquidTypesRmls = value; RaisePropertyChangedAuto(); } } private ProcessParametersTablesGroup _rmlProcessParametersTablesGroup; /// /// Gets or sets the RML process parameters table group (cloned). /// public ProcessParametersTablesGroup RmlProcessParametersTableGroup { get { return _rmlProcessParametersTablesGroup; } set { _rmlProcessParametersTablesGroup = value; RaisePropertyChangedAuto(); OnProcessParametersTableGroupChanged(); } } private ObservableCollection _groupsHistory; /// /// Gets or sets the RML process parameters groups history. /// public ObservableCollection GroupsHistory { get { return _groupsHistory; } set { _groupsHistory = value; RaisePropertyChangedAuto(); } } private ProcessParametersTablesGroup _selectedGroupHistory; /// /// Gets or sets the selected process parameters tables group history. /// public ProcessParametersTablesGroup SelectedGroupHistory { get { return _selectedGroupHistory; } set { _selectedGroupHistory = value; RaisePropertyChangedAuto(); OnSelectedGroupHistoryChanged(); } } private ProcessParametersTable _selectedProcessParametersTable; /// /// Gets or sets the selected process parameters table. /// public ProcessParametersTable SelectedProcessParametersTable { get { return _selectedProcessParametersTable; } set { _selectedProcessParametersTable = value; RaisePropertyChangedAuto(); OnSelectedParametersTableChanged(); } } private Job _activeJob; /// /// Gets or sets the selected machine job. /// public Job ActiveJob { get { return _activeJob; } set { _activeJob = value; RaisePropertyChangedAuto(); OnActiveJobChanged(); } } private Job _selectedMachineJob; /// /// Gets or sets the selected machine job. /// public Job SelectedMachineJob { get { return _selectedMachineJob; } set { _selectedMachineJob = value; RaisePropertyChangedAuto(); } } private ObservableCollection _selectedJobs; /// /// Gets or sets the selected jobs. /// public ObservableCollection SelectedJobs { get { return _selectedJobs; } set { _selectedJobs = value; RaisePropertyChangedAuto(); } } private Segment _selectedSegment; /// /// Gets or sets the job selected segment. /// public Segment SelectedSegment { get { return _selectedSegment; } set { _selectedSegment = value; RaisePropertyChangedAuto(); OnSelectedSegmentChanged(); } } private ObservableCollection _selectedSegments; /// /// Gets or sets the selected segments. /// public ObservableCollection SelectedSegments { get { return _selectedSegments; } set { _selectedSegments = value; RaisePropertyChangedAuto(); } } private BrushStop _selectedBrushStop; /// /// Gets or sets the selected segment selected brush stop. /// public BrushStop SelectedBrushStop { get { return _selectedBrushStop; } set { _selectedBrushStop = value; RaisePropertyChangedAuto(); } } private ObservableCollection _selectedBrushStops; /// /// Gets or sets the selected brush stops. /// public ObservableCollection SelectedBrushStops { get { return _selectedBrushStops; } set { _selectedBrushStops = value; RaisePropertyChangedAuto(); } } private Rml _selectedRML; /// /// Gets or sets the selected RML. /// public Rml SelectedRML { get { return _selectedRML; } set { _selectedRML = value; InvalidateLiquidFactorsAndProcessTables(); RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } private bool _isSideBarOpened; /// /// Gets or sets a value indicating whether the configuration panels are opened. /// public bool IsSideBarOpened { get { return _isSideBarOpened; } set { _isSideBarOpened = value; RaisePropertyChangedAuto(); } } private TimeSpan _estimatedDuration; /// /// Gets or sets the estimated duration for the selected job. /// public TimeSpan EstimatedDuration { get { return _estimatedDuration; } set { _estimatedDuration = value; RaisePropertyChangedAuto(); } } private bool _isJobRunning; /// /// Gets or sets a value indicating whether a job is currently running. /// public bool IsJobRunning { get { return _isJobRunning; } set { _isJobRunning = value; RaisePropertyChangedAuto(); } } private Job _runningJob; /// /// Gets or sets the currently running job. /// public Job RunningJob { get { return _runningJob; } set { _runningJob = value; RaisePropertyChangedAuto(); } } private double _runningJobProgress; /// /// Gets or sets the running job current progress. /// public double RunningJobProgress { get { return _runningJobProgress; } set { _runningJobProgress = value; RaisePropertyChangedAuto(); } } private TimeSpan _runningJobRemainingTime; /// /// Gets or sets the job remaining time. /// public TimeSpan RunningJobRemainingTime { get { return _runningJobRemainingTime; } set { _runningJobRemainingTime = value; RaisePropertyChangedAuto(); } } private bool _isJobCompleted; /// /// Gets or sets a value indicating whether the running job has completed successfully. /// public bool IsJobCompleted { get { return _isJobCompleted; } set { _isJobCompleted = value; RaisePropertyChangedAuto(); } } private bool _isJobFailed; /// /// Gets or sets a value indicating whether the running job has failed. /// public bool IsJobFailed { get { return _isJobFailed; } set { _isJobFailed = value; RaisePropertyChangedAuto(); } } private bool _showJobStatus; /// /// Gets or sets a value indicating whether to show all the relevant job status areas. /// public bool ShowJobStatus { get { return _showJobStatus; } set { _showJobStatus = value; RaisePropertyChangedAuto(); } } private bool _isJobCanceled; /// /// Gets or sets a value indicating whether the last running job was canceled. /// public bool IsJobCanceled { get { return _isJobCanceled; } set { _isJobCanceled = value; RaisePropertyChangedAuto(); } } private IMachineOperator _machineOperator; /// /// Gets or sets the machine operator. /// public IMachineOperator MachineOperator { get { return _machineOperator; } set { _machineOperator = value; RaisePropertyChangedAuto(); } } private IRealTimeGraph _fullScreenGraph; /// /// Gets or sets the full screen graph. /// public IRealTimeGraph FullScreenGraph { get { return _fullScreenGraph; } set { _fullScreenGraph = value; RaisePropertyChangedAuto(); } } private List _runningJobSegments; /// /// Gets or sets the running job segments. /// public List RunningJobSegments { get { return _runningJobSegments; } set { _runningJobSegments = value; RaisePropertyChangedAuto(); } } private ICollectionView _jobsCollectionView; /// /// Gets or sets the jobs collection view. /// public ICollectionView JobsCollectionView { get { return _jobsCollectionView; } set { _jobsCollectionView = value; BindingOperations.EnableCollectionSynchronization(_jobsCollectionView, _syncLock); RaisePropertyChangedAuto(); } } private ICollectionView _segmentsCollectionView; /// /// Gets or sets the segments collection view. /// public ICollectionView SegmentsCollectionView { get { return _segmentsCollectionView; } set { _segmentsCollectionView = value; BindingOperations.EnableCollectionSynchronization(_segmentsCollectionView, _syncLock); RaisePropertyChangedAuto(); } } private ICollectionView _brushStopsCollectionView; /// /// Gets or sets the brush stops collection view. /// public ICollectionView BrushStopsCollectionView { get { return _brushStopsCollectionView; } set { _brushStopsCollectionView = value; BindingOperations.EnableCollectionSynchronization(_brushStopsCollectionView, _syncLock); RaisePropertyChangedAuto(); } } private String _jobFilter; /// /// Gets or sets the job filter. /// public String JobFilter { get { return _jobFilter; } set { _jobFilter = value; RaisePropertyChangedAuto(); OnJobFilterChanged(); } } #endregion #region Commands /// /// Gets or sets the edit machine command. /// public RelayCommand EditMachineCommand { get; set; } /// /// Gets or sets the edit RML command. /// public RelayCommand EditRMLCommand { get; set; } /// /// Gets or sets the toggle side bar command. /// public RelayCommand ToggleSideBarCommand { get; set; } /// /// Gets or sets the save process parameters command. /// public RelayCommand SaveProcessParametersCommand { get; set; } /// /// Gets or sets the save liquid factors command. /// public RelayCommand SaveLiquidFactorsCommand { get; set; } /// /// Gets or sets the add segment command. /// public RelayCommand AddSegmentCommand { get; set; } /// /// Gets or sets the remove segment command. /// public RelayCommand RemoveSegmentCommand { get; set; } /// /// Gets or sets the add job command. /// public RelayCommand AddJobCommand { get; set; } /// /// Gets or sets the remove job command. /// public RelayCommand RemoveJobCommand { get; set; } /// /// Gets or sets the add brush stop command. /// public RelayCommand AddBrushStopCommand { get; set; } /// /// Gets or sets the remove brush stop command. /// public RelayCommand RemoveBrushStopCommand { get; set; } /// /// Gets or sets the save job command. /// public RelayCommand SaveJobCommand { get; set; } /// /// Gets or sets the discard job command. /// public RelayCommand DiscardJobCommand { get; set; } /// /// Gets or sets the start job command. /// public RelayCommand StartJobCommand { get; set; } /// /// Gets or sets the stop job command. /// public RelayCommand StopJobCommand { get; set; } /// /// Gets or sets the close job completion status command. /// public RelayCommand CloseJobCompletionStatusCommand { get; set; } /// /// Gets or sets the load job command. /// public RelayCommand LoadJobCommand { get; set; } /// /// Gets or sets the duplicate job command. /// public RelayCommand DuplicateJobCommand { get; set; } /// /// Gets or sets the duplicate segment command. /// public RelayCommand DuplicateSegmentCommand { get; set; } /// /// Gets or sets the duplicate brush stop command. /// public RelayCommand DuplicateBrushStopCommand { get; set; } /// /// Gets or sets the push process parameters command. /// public RelayCommand PushProcessParametersCommand { get; set; } /// /// Gets or sets the import embroidery file command. /// public RelayCommand ImportEmbroideryFileCommand { get; set; } /// /// Gets or sets the display job embroidery file command. /// public RelayCommand DisplayJobEmbroideryFileCommand { get; set; } #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// The application manager. /// The notification provider. public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, IAuthenticationProvider authentication, IEventLogger eventLogger) { SelectedJobs = new ObservableCollection(); LogManager.Log("Initializing machine Db context..."); _machineDbContext = ObservablesContext.CreateDefault(); Machines = _machineDbContext.Machines.ToObservableCollection(); 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; _eventLogger = eventLogger; LogManager.Log("Initializing relay commands..."); _speech = new SpeechSynthesizer(); _soundPlayer = new SoundPlayer(EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.MachineStudio.Developer.bip.wav")); _soundPlayerErr = new SoundPlayer(EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.MachineStudio.Developer.error.wav")); _speech.SelectVoice(_speech.GetInstalledVoices().LastOrDefault(x => x.VoiceInfo.Gender == VoiceGender.Female).VoiceInfo.Name); //Initialize Commands... EditMachineCommand = new RelayCommand(EditMachine, () => SelectedMachine != null); EditRMLCommand = new RelayCommand(EditRML, () => SelectedRML != null); ToggleSideBarCommand = new RelayCommand(() => IsSideBarOpened = !IsSideBarOpened); 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 && MachineOperator != null && !MachineOperator.MachineEventsStateProvider.Events.ToList().Exists(x => x.ActionTypes.Contains(BL.Enumerations.ActionTypes.PreventJobExecution))); 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); SaveProcessParametersCommand = new RelayCommand(SaveProcessParameters, () => SelectedRML != null && SelectedRML.ProcessParametersTablesGroups.Count > 0); PushProcessParametersCommand = new RelayCommand(PushProcessParameters, () => SelectedRML != null && SelectedRML.ProcessParametersTablesGroups.Count > 0 && SelectedProcessParametersTable != null && MachineOperator != null); ImportEmbroideryFileCommand = new RelayCommand(ImportEmbroideryFile, () => SelectedMachine != null); DisplayJobEmbroideryFileCommand = new RelayCommand(DisplayJobEmbroideryFile); ApplicationManager.ConnectedMachineChanged += ApplicationManager_ConnectedMachineChanged; } #endregion #region Event Handlers /// /// Handles the application manager connected machine changes event. /// /// The sender. /// The machine. private void ApplicationManager_ConnectedMachineChanged(object sender, IExternalBridgeClient machine) { MachineOperator = machine; if (MachineOperator != null) { MachineOperator.MachineEventsStateProvider.EventsChanged -= MachineEventsStateProvider_EventsChanged; MachineOperator.MachineEventsStateProvider.EventsChanged += MachineEventsStateProvider_EventsChanged; MachineOperator.MachineEventsStateProvider.NewEvents -= MachineEventsStateProvider_NewEvents; MachineOperator.MachineEventsStateProvider.NewEvents += MachineEventsStateProvider_NewEvents; } } private void MachineEventsStateProvider_NewEvents(object sender, IEnumerable events) { HandleNewHardwareEvents(events); } private void MachineEventsStateProvider_EventsChanged(object sender, IEnumerable changedEvents) { InvokeUI(StartJobCommand.RaiseCanExecuteChanged); } /// /// Handles the Saved event of the SelectedMachine. /// /// The source of the event. /// The instance containing the event data. private void SelectedMachine_Saved(object sender, EventArgs e) { InvalidateLiquidFactorsAndProcessTables(); SelectedMachine.Reload(_machineDbContext); } /// /// Handles the LengthChanged event of the SelectedJob. /// /// The source of the event. /// The instance containing the event data. private void ActiveJob_LengthChanged(object sender, EventArgs e) { UpdateEstimatedDuration(); } /// /// Handles the DyeingSpeedMinInkUptakeChanged event of the SelectedProcessParametersTable. /// /// The source of the event. /// The instance containing the event data. 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 Hardware Events private void HandleNewHardwareEvents(IEnumerable events) { if (IsJobRunning) { SpeakError(events.Last().EventType.Name); if (events.ToList().Exists(x => x.ActionTypes.Contains(BL.Enumerations.ActionTypes.AbortRunningJob))) { if (_jobHandler != null) { InvokeUI(StopJob); } } } } #endregion #region Sound private void SpeakInfo(String text) { _soundPlayer.Play(); _speech.SpeakAsync(text); } private void SpeakError(String text) { _soundPlayerErr.Play(); _speech.SpeakAsync(text); } #endregion #region Properties Changes /// /// Called when the selected parameters table has changed. /// 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(); } } /// /// Called when the process parameters table group has been changed /// 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(); } } /// /// Called when the selected segment has been changed /// 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)); } } /// /// Called when the selected group history has been changed /// protected virtual void OnSelectedGroupHistoryChanged() { if (SelectedGroupHistory != null) { LogManager.Log(String.Format("Parameters group {0} selected from history.", SelectedGroupHistory.Name)); RmlProcessParametersTableGroup = SelectedGroupHistory.CloneGroup(); } } /// /// Called when the machine has been changed /// 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)); } } /// /// Called when the job filtering has changed. /// 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 }; } /// /// Called when the active job has changed. /// 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 /// /// Switch the segment position in the job. /// /// The dragged. /// The dropped. 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(); } /// /// Switch the brush stop position in the segment. /// /// The dragged stop. /// The dropped stop. 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 /// /// Closes the job completion status bar. /// private void CloseJobCompletionStatusBar() { LogManager.Log("Closing job completion status bar..."); _navigation.NavigateTo(DeveloperNavigationView.JobView); IsJobCompleted = false; IsJobFailed = false; IsJobCanceled = false; ShowJobStatus = false; RunningJob = null; } /// /// Stops the job. /// private void StopJob() { LogManager.Log("Stopping job..."); IsJobRunning = false; IsJobCanceled = true; _jobHandler.Cancel(); } /// /// Fails the job. /// private void SetJobFailed() { if (IsJobRunning) { LogManager.Log("Setting job failed state..."); IsJobRunning = false; IsJobFailed = true; SpeakError("Job Failed!"); } } /// /// Completes the job. /// private void SetJobCompleted() { LogManager.Log("Setting job completed state..."); IsJobRunning = false; IsJobCompleted = true; SpeakInfo("Job Completed!"); } /// /// Starts the job. /// 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); try { LogManager.Log("Sending job to machine operator..."); _jobHandler = MachineOperator.Print(ActiveJob, SelectedProcessParametersTable); _eventLogger.Log(String.Format("Job '{0}' started...", ActiveJob.Name)); _jobHandler.StatusReceived += (x, status) => { if (IsJobRunning) { RunningJobRemainingTime = _runningJobEstimatedDuration - TimeSpan.FromSeconds(RunningJobProgress / (SelectedProcessParametersTable.DyeingSpeed / 100d)); RunningJobProgress = status.Progress; } foreach (var segment in RunningJobSegments) { if (!IsJobRunning) { break; } 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) { if (!segment.Started) { segment.Started = true; if (segment.ID != -1) { SpeakInfo(String.Format("Segment {0} Started.", segment.SegmentIndex)); _eventLogger.Log(String.Format("Segment {0} Started.", segment.SegmentIndex)); } else { SpeakInfo(String.Format("Inter Segment Started.")); _eventLogger.Log("Inter Segment Started."); } } } if (remaining <= TimeSpan.Zero) { if (!segment.Completed) { segment.Completed = true; } } } }; _jobHandler.Failed += (x, ex) => { LogManager.Log(ex, String.Format("Job {0} has failed.", RunningJob.Name)); _eventLogger.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)); _eventLogger.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)); _eventLogger.Log(String.Format("Job {0} has been canceled.", RunningJob.Name)); //Finally Canceled.. }; } catch (Exception ex) { LogManager.Log(ex); _eventLogger.Log(ex, "An error occurred while starting the job."); _notification.ShowError("An error occurred while starting the job. " + Environment.NewLine + ex.Message); SetJobFailed(); } } /// /// Creates the running job effective segments. /// /// The job. /// private List CreateRunningJobEffectiveSegments(Job job) { LogManager.Log("Creating job effective segments..."); List segments = new List(); 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, ID = -1, BrushStops = new System.Collections.ObjectModel.ObservableCollection() { new BrushStop() { ColorSpace = ColorSpaces.Single(x => x.Code == BL.Enumerations.ColorSpaces.RGB.ToInt32()), Color = Colors.White, } }, Started = false, Completed = false }); } } return segments; } #endregion #region RML /// /// Saves the liquid factors. /// 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(); } } } /// /// Navigates to the DB Module in order to edit the selected RML. /// private void EditRML() { LogManager.Log(String.Format("Requesting DB module for RML {0} editing...", SelectedRML.Name)); ApplicationManager.RequestModule("Data Base", SelectedRML); } /// /// Invalidates the liquid factors and process parameters tables. /// 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 Process Parameters Management /// /// Uploads the selected process parameters table. /// private async void PushProcessParameters() { using (_notification.PushTaskItem("Uploading Process Parameters...")) { try { LogManager.Log(String.Format("Uploading process parameters table {0}...", SelectedProcessParametersTable.Name)); await MachineOperator.UploadProcessParameters(SelectedProcessParametersTable); } catch (Exception ex) { LogManager.LogFormat(ex, "Failed to upload process parameters table {0}", SelectedProcessParametersTable.Name); _notification.ShowError("Failed to upload the selected process parameters." + Environment.NewLine + ex.Message); } } } /// /// Saves the process parameters group. /// 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 tables = new List(); 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(); } } #endregion #region Active Job Management /// /// Loads the selected job. /// private void LoadSelectedJob() { if (SelectedMachineJob != null) { using (_notification.PushTaskItem("Loading job details...")) { LogManager.Log(String.Format("Loading job {0}...", SelectedMachineJob.Name)); SelectedSegments = new ObservableCollection(); SelectedBrushStops = new ObservableCollection(); 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(); SpoolTypes = _activeJobDbContext.SpoolTypes.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); } } } /// /// Saves the active job. /// 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; ActiveJob.EstimatedDurationMili = (int)EstimatedDuration.TotalMilliseconds; 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); } } } /// /// Navigates to the Machine Designer Module in order to edit the selected machine. /// 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 /// /// Arranges the segments indices. /// private void ArrangeSegmentsIndices() { int index = 1; foreach (var segment in ActiveJob.Segments.OrderBy(x => x.SegmentIndex)) { segment.SegmentIndex = index++; } SegmentsCollectionView.Refresh(); } /// /// Arranges the brush stops indices. /// 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(); } /// /// Removes the selected segments. /// 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(); } } } /// /// Adds a new segment. /// 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(); } } /// /// Removes the selected jobs. /// 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); } } } } /// /// Adds a new job to the selected machine. /// 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.UserGuid = _authentication.CurrentUser.Guid; newJob.Rml = _machineDbContext.Rmls.FirstOrDefault(); newJob.WindingMethod = _machineDbContext.WindingMethods.FirstOrDefault(); newJob.SpoolType = _machineDbContext.SpoolTypes.FirstOrDefault(); newJob.Machine = SelectedMachine; SelectedMachine.Jobs.Add(newJob); LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); SelectedMachineJob = newJob; LoadSelectedJob(); AddSegment(); } } } /// /// Removes the selected brush stop. /// 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(); } } } /// /// Adds a new brush stop to the selected segment. /// 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(); } } /// /// Duplicates the selected brush stops. /// 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(); } /// /// Duplicates the selected segments. /// 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(); } /// /// Duplicates the selected jobs. /// 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 Embroidery /// /// Imports embroidery file. /// private void ImportEmbroideryFile() { OpenFileDialog dlg = new OpenFileDialog(); dlg.Title = "Select embroidery file"; dlg.Filter = EMB_FORMATS_IMPORT; if (dlg.ShowDialogCenter()) { var view = new EmbroideryImportView(); _notification.ShowModalDialog( new EmbroideryImportViewVM() { FileName = dlg.FileName }, view, (vm) => { String jobName = _notification.ShowTextInput("Please provide a job name", "Name"); if (jobName != null) { AddJobFromEmbroideryFile(jobName, vm, dlg.FileName, view.EmbroideryImageBytes); } }, () => { }); } } private async void AddJobFromEmbroideryFile(String jobName, EmbroideryImportViewVM vm, String fileName, byte[] imageBytes) { LogManager.Log(String.Format("Adding new job from embroidery file {0}...", jobName)); Job job = new Job(); job.Name = jobName; job.Name = jobName; job.CreationDate = DateTime.UtcNow; job.UserGuid = _authentication.CurrentUser.Guid; job.Rml = _machineDbContext.Rmls.FirstOrDefault(); job.WindingMethod = _machineDbContext.WindingMethods.FirstOrDefault(); job.SpoolType = _machineDbContext.SpoolTypes.FirstOrDefault(); job.Machine = SelectedMachine; job.EmbroideryFileName = Path.GetFileName(fileName); job.EmbroideryFileData = File.ReadAllBytes(fileName); job.EmbroideryJpeg = imageBytes; job.HasEmbroideryFile = true; foreach (var path in vm.Paths.Skip(1)) { Segment segment = new Segment(); double baseLength = path.Length / 1000d; double embThicknessLength = (vm.EmbroideryMaterialThickness * path.StitchCount) / 1000d; double stabilizerThicknessLength = (vm.StabilizerThickness * path.StitchCount) / 1000d; double totalLength = (baseLength + embThicknessLength) * vm.SelectedEmbroideryMaterial.Coefficient; if (vm.HasStabilizer) { totalLength += (stabilizerThicknessLength * vm.SelectedStabilizer.Coefficient); } segment.Length = totalLength; segment.Name = "Embroidery Segment"; segment.SegmentIndex = vm.Paths.IndexOf(path) + 2; if (path.Brush is SolidColorBrush) { var brush = (path.Brush as SolidColorBrush); segment.BrushStops.Add(new BrushStop() { Red = brush.Color.R, Green = brush.Color.G, Blue = brush.Color.B, ColorSpace = _machineDbContext.ColorSpaces.ToList().SingleOrDefault(x => x.Code == BL.Enumerations.ColorSpaces.RGB.ToInt32()), }); } else { var brush = (path.Brush as LinearGradientBrush); foreach (var stop in brush.GradientStops) { segment.BrushStops.Add(new BrushStop() { StopIndex = brush.GradientStops.IndexOf(stop), Red = stop.Color.R, Green = stop.Color.G, Blue = stop.Color.B, OffsetPercent = stop.Offset * 100d, ColorSpace = _machineDbContext.ColorSpaces.ToList().SingleOrDefault(x => x.Code == BL.Enumerations.ColorSpaces.RGB.ToInt32()), }); } } job.Segments.Add(segment); } SelectedMachine.Jobs.Add(job); LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); SelectedMachineJob = job; LoadSelectedJob(); } private void DisplayJobEmbroideryFile(Job job) { _notification.ShowModalDialog(new EmbroideryDisplayViewVM(job), (vm) => { SaveFileDialog dlg = new SaveFileDialog(); dlg.Title = "Select embroidery file location and format"; dlg.Filter = EMB_FORMATS_EXPORT; dlg.FileName = job.EmbroideryFileName; if (dlg.ShowDialogCenter()) { try { String tempPath = PathHelper.GetTempFolderPath(); String filePath = Path.Combine(tempPath, job.EmbroideryFileName); File.WriteAllBytes(filePath, job.EmbroideryFileData); EmbroideryFileConverter.ConvertEmbroideryFile(filePath, dlg.FileName); _notification.ShowInfo("Embroidery file exported successfully."); } catch (Exception ex) { LogManager.Log(ex, "An error has occurred while trying to export the attached embroidery file."); _notification.ShowError("An error has occurred while trying to export the attached embroidery file."); } } }, () => { }); } #endregion #region Override Methods protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) { base.RaisePropertyChangedAuto(caller); if (!_blockInvalidateCommands) { InvalidateRelayCommands(); } } #endregion #region IShutdownRequestBlocker public Task 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 } }