From d33c19b3ac6803de4b5c8d475832efef131c1a45 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Wed, 30 Dec 2020 15:11:34 +0000 Subject: Revert "Hope it is fine" --- .../PPC/Modules/Tango.PPC.BackupRestore/App.xaml | 11 + .../Tango.PPC.BackupRestore/BackupRestoreModule.cs | 84 + .../Tango.PPC.BackupRestore/Images/backup-big.png | Bin 0 -> 3044 bytes .../Images/backup-restore.png | Bin 0 -> 89496 bytes .../Tango.PPC.BackupRestore/Images/restore.png | Bin 0 -> 3252 bytes .../Properties/AssemblyInfo.cs | 20 + .../Properties/Resources.Designer.cs | 63 + .../Properties/Resources.resx | 117 ++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../Tango.PPC.BackupRestore.csproj | 246 +++ .../Tango.PPC.BackupRestore/ViewModelLocator.cs | 95 + .../ViewModels/BackupCompletedViewVM.cs | 20 + .../ViewModels/BackupErrorViewVM.cs | 37 + .../ViewModels/BackupViewVM.cs | 163 ++ .../ViewModels/MainViewVM.cs | 34 + .../ViewModels/RestoreCompletedViewVM.cs | 51 + .../ViewModels/RestoreErrorViewVM.cs | 38 + .../ViewModels/RestoreViewVM.cs | 168 ++ .../ViewModels/WelcomeViewVM.cs | 48 + .../Views/BackupCompletedView.xaml | 37 + .../Views/BackupCompletedView.xaml.cs | 28 + .../Views/BackupErrorView.xaml | 39 + .../Views/BackupErrorView.xaml.cs | 28 + .../Views/BackupProgressView.xaml | 38 + .../Views/BackupProgressView.xaml.cs | 28 + .../Tango.PPC.BackupRestore/Views/BackupView.xaml | 99 ++ .../Views/BackupView.xaml.cs | 28 + .../Tango.PPC.BackupRestore/Views/MainView.xaml | 39 + .../Tango.PPC.BackupRestore/Views/MainView.xaml.cs | 30 + .../Views/RestoreCompletedView.xaml | 37 + .../Views/RestoreCompletedView.xaml.cs | 28 + .../Views/RestoreErrorView.xaml | 39 + .../Views/RestoreErrorView.xaml.cs | 28 + .../Views/RestoreProgressView.xaml | 38 + .../Views/RestoreProgressView.xaml.cs | 28 + .../Tango.PPC.BackupRestore/Views/RestoreView.xaml | 160 ++ .../Views/RestoreView.xaml.cs | 28 + .../Tango.PPC.BackupRestore/Views/WelcomeView.xaml | 72 + .../Views/WelcomeView.xaml.cs | 28 + .../PPC/Modules/Tango.PPC.BackupRestore/app.config | 61 + .../Tango.PPC.BackupRestore/packages.config | 7 + .../PPC/Modules/Tango.PPC.Browser/App.xaml | 11 + .../Attributes/BoundObjectAttribute.cs | 20 + .../BoundsObjects/KeyboardHandler.cs | 66 + .../PPC/Modules/Tango.PPC.Browser/BrowserModule.cs | 101 ++ .../Modules/Tango.PPC.Browser/CefSharpOutput.zip | Bin 0 -> 143444091 bytes .../Helpers/BoundObjectsHelper.cs | 72 + .../Modules/Tango.PPC.Browser/Images/browser.png | Bin 0 -> 2539 bytes .../Navigation/BrowserNavigationRequest.cs | 19 + .../Tango.PPC.Browser/Properties/AssemblyInfo.cs | 20 + .../Properties/Resources.Designer.cs | 63 + .../Tango.PPC.Browser/Properties/Resources.resx | 117 ++ .../Properties/Settings.Designer.cs | 26 + .../Tango.PPC.Browser/Properties/Settings.settings | 7 + .../RequestHandlers/ChromiumRequestHandler.cs | 114 ++ .../Modules/Tango.PPC.Browser/Scripts/keyboard.js | 21 + .../Tango.PPC.Browser/Tango.PPC.Browser.csproj | 199 +++ .../ViewContracts/IBrowserView.cs | 18 + .../Modules/Tango.PPC.Browser/ViewModelLocator.cs | 32 + .../Tango.PPC.Browser/ViewModels/BrowserViewVM.cs | 134 ++ .../Tango.PPC.Browser/Views/BrowserView.xaml | 77 + .../Tango.PPC.Browser/Views/BrowserView.xaml.cs | 211 +++ .../Modules/Tango.PPC.Browser/Views/ErrorView.xaml | 23 + .../Tango.PPC.Browser/Views/ErrorView.xaml.cs | 29 + .../PPC/Modules/Tango.PPC.Browser/app.config | 90 + .../PPC/Modules/Tango.PPC.Browser/packages.config | 11 + .../Tango.PPC.BugReporting/BugReportingModule.cs | 2 +- .../TFS/TeamFoundationServicePPCClient.cs | 73 +- .../Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj | 235 +++ .../Tango.PPC.BugReporting/ViewModelLocator.cs | 2 +- .../Converters/MachineEventToViewConverter.cs | 7 + .../EventsViews/ThreadBreakView.xaml | 26 + .../EventsViews/ThreadBreakView.xaml.cs | 49 + .../Modules/Tango.PPC.Events/Resources/Styles.xaml | 4 +- .../Tango.PPC.Events/Tango.PPC.Events.csproj | 9 +- .../Tango.PPC.Events/ViewModels/MainViewVM.cs | 32 +- .../Modules/Tango.PPC.Events/Views/MainView.xaml | 8 +- .../AppBarItems/JobProgressAppBarItemView.xaml | 5 +- .../AppButtons/StartPrintingButton.cs | 4 +- .../Tango.PPC.Jobs/Controls/JobOutlineControl.cs | 319 ++++ .../Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml | 3 + .../Tango.PPC.Jobs/Controls/RunningJobViewer.xaml | 3 + .../Converters/ColorSpaceToVisibilityConverter.cs | 12 +- .../Dialogs/AdvancedColorCorrectionView.xaml | 68 +- .../Dialogs/AdvancedColorCorrectionViewVM.cs | 2 +- .../Dialogs/BasicColorCorrectionView.xaml | 9 +- .../Dialogs/CatalogSelectionView.xaml | 2 +- .../Tango.PPC.Jobs/Dialogs/ImportJobView.xaml | 2 +- .../Tango.PPC.Jobs/Images/JobView/transparent.jpg | Bin 0 -> 27097 bytes .../Images/JobView/transparent_small.jpg | Bin 0 -> 10743 bytes .../Modules/Tango.PPC.Jobs/Images/color-picker.png | Bin 0 -> 1171 bytes .../PPC/Modules/Tango.PPC.Jobs/Images/sync.png | Bin 0 -> 4127 bytes .../PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png | Bin 0 -> 6743 bytes .../NewSynchronizardJobsNotificationItem.cs | 32 + .../NewSynchronizardJobsNotificationItemView.xaml | 30 + ...ewSynchronizardJobsNotificationItemView.xaml.cs | 30 + .../Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj | 26 +- .../Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs | 108 +- .../Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs | 37 +- .../Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs | 149 +- .../Tango.PPC.Jobs/ViewModels/JobsViewVM.cs | 186 +- .../Tango.PPC.Jobs/ViewModels/MainViewVM.cs | 66 +- .../Tango.PPC.Jobs/Views/JobProgressView.xaml | 138 +- .../Tango.PPC.Jobs/Views/JobSummeryView.xaml | 2 +- .../PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml | 323 ++-- .../Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs | 16 +- .../PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml | 14 +- .../MachineSettingsModule.cs | 2 +- .../ViewModels/MainViewVM.cs | 229 ++- .../Tango.PPC.MachineSettings/Views/MainView.xaml | 186 +- .../PPC/Modules/Tango.PPC.Maintenance/App.xaml | 11 + .../Commands/HomingMotorCommand.cs | 80 + .../Commands/OpenCloseDyeingHeadCommand.cs | 31 + .../Commands/OpenCloseLeftLeadingWheelsCommand.cs | 30 + .../Commands/OpenCloseMotorCommand.cs | 158 ++ .../Commands/OpenCloseRightLeadingWheelsCommand.cs | 30 + .../Commands/ResetThreadLoadingCommand.cs | 24 + .../Controls/StateTouchButton.cs | 109 ++ .../Converters/LiquidTypeToBrushConverter.cs | 74 + .../Converters/LiquidTypeToShortNameConverter.cs | 41 + .../MidTankLevelToElementHeightConverter.cs | 34 + .../Converters/StringToFirstLetterConverter.cs | 30 + .../Dialogs/CleanerDispensingView.xaml | 66 + .../Dialogs/CleanerDispensingView.xaml.cs | 28 + .../Dialogs/CleanerDispensingViewVM.cs | 128 ++ .../Dialogs/HeadCleaningView.xaml | 56 + .../Dialogs/HeadCleaningView.xaml.cs | 28 + .../Dialogs/HeadCleaningViewVM.cs | 150 ++ .../PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs | 35 + .../PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs | 21 + .../Guides/HandleWasteCartridgeGuide.cs | 43 + .../Guides/LoadInkCartridgeGuide.cs | 43 + .../Guides/LoadNewThreadGuide.cs | 43 + .../Guides/ReplaceAirFilterGuide.cs | 43 + .../Guides/ReplaceThreadGuide.cs | 43 + .../Tango.PPC.Maintenance/Helpers/GuideHelper.cs | 33 + .../Images/Guides/Loading-New-Thread.gif | Bin 0 -> 4092741 bytes .../Images/Guides/Loading-an-Ink-Cartridge.gif | Bin 0 -> 4197318 bytes .../Images/Guides/Replacing-the-Air-Filter.gif | Bin 0 -> 3500573 bytes .../Images/Guides/Replacing-the-Thread.gif | Bin 0 -> 13319358 bytes .../Images/Guides/Residue-Cartridges-A.gif | Bin 0 -> 3567850 bytes .../Guides/handling-the-waste-cartridges.png | Bin 0 -> 2174 bytes .../Images/Guides/loading-an-ink-cartridge.png | Bin 0 -> 2266 bytes .../Images/Guides/loading-new-thread.png | Bin 0 -> 2228 bytes .../Images/Guides/machine-image.png | Bin 0 -> 138220 bytes .../Images/Guides/replacing-the-air-filter.png | Bin 0 -> 2269 bytes .../Images/Guides/replacing-the-thread.png | Bin 0 -> 2175 bytes .../Tango.PPC.Maintenance/Images/Waste/absent.png | Bin 0 -> 892 bytes .../Images/Waste/present_empty_error.png | Bin 0 -> 1440 bytes .../Images/Waste/present_empty_right.png | Bin 0 -> 1497 bytes .../Images/Waste/present_full_right.png | Bin 0 -> 2035 bytes .../Tango.PPC.Maintenance/Images/action.png | Bin 0 -> 1152 bytes .../Tango.PPC.Maintenance/Images/cl-full.png | Bin 0 -> 3454 bytes .../Tango.PPC.Maintenance/Images/cone-empty.png | Bin 0 -> 4125 bytes .../Tango.PPC.Maintenance/Images/cone-full.png | Bin 0 -> 3018 bytes .../Tango.PPC.Maintenance/Images/guides.png | Bin 0 -> 2099 bytes .../Tango.PPC.Maintenance/Images/head_cleaning.png | Bin 0 -> 44260 bytes .../Modules/Tango.PPC.Maintenance/Images/inks.png | Bin 0 -> 2075 bytes .../Tango.PPC.Maintenance/Images/l-full.png | Bin 0 -> 19717 bytes .../Tango.PPC.Maintenance/Images/lubricant2.png | Bin 0 -> 194234 bytes .../Tango.PPC.Maintenance/Images/maintenance.png | Bin 0 -> 686 bytes .../Tango.PPC.Maintenance/Images/status.png | Bin 0 -> 1663 bytes .../Images/temperature-green.png | Bin 0 -> 926 bytes .../Images/temperature-red.png | Bin 0 -> 928 bytes .../Images/temperature-yellow.png | Bin 0 -> 927 bytes .../Images/thread_loading.png | Bin 0 -> 7209 bytes .../Tango.PPC.Maintenance/MaintenanceCommand.cs | 81 + .../Tango.PPC.Maintenance/MaintenanceModule.cs | 84 + .../Models/MidTankLevelModel.cs | 35 + .../Models/OverallTemperatureModel.cs | 30 + .../Properties/AssemblyInfo.cs | 20 + .../Properties/Resources.Designer.cs | 63 + .../Properties/Resources.resx | 117 ++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../Tango.PPC.Maintenance/Resources/Guides.xaml | 60 + .../Tango.PPC.Maintenance.csproj | 320 ++++ .../Tango.PPC.Maintenance/Themes/Generic.xaml | 9 + .../Tango.PPC.Maintenance/ViewModelLocator.cs | 56 + .../ViewModels/GeneralGuideViewVM.cs | 40 + .../Tango.PPC.Maintenance/ViewModels/MainViewVM.cs | 31 + .../ViewModels/MaintenanceViewVM.cs | 324 ++++ .../Views/GeneralGuideView.xaml | 55 + .../Views/GeneralGuideView.xaml.cs | 33 + .../Tango.PPC.Maintenance/Views/MainView.xaml | 22 + .../Tango.PPC.Maintenance/Views/MainView.xaml.cs | 28 + .../Views/MaintenanceView.xaml | 341 ++++ .../Views/MaintenanceView.xaml.cs | 30 + .../PPC/Modules/Tango.PPC.Maintenance/app.config | 61 + .../Modules/Tango.PPC.Maintenance/packages.config | 11 + .../Models/StorageNavigationIntent.cs | 4 +- .../PPC/Modules/Tango.PPC.Storage/StorageModule.cs | 2 +- .../Tango.PPC.Storage/ViewModels/MainViewVM.cs | 60 +- .../Modules/Tango.PPC.Storage/Views/MainView.xaml | 70 +- .../Dialogs/EmbeddedLogItemDetailsView.xaml | 80 + .../Dialogs/EmbeddedLogItemDetailsView.xaml.cs | 28 + .../Dialogs/EmbeddedLogItemDetailsViewVM.cs | 21 + .../Dialogs/SynchronizationDetailsView.xaml | 74 + .../Dialogs/SynchronizationDetailsView.xaml.cs | 28 + .../Dialogs/SynchronizationDetailsViewVM.cs | 22 + .../Dialogs/UpdateDetailsView.xaml | 87 + .../Dialogs/UpdateDetailsView.xaml.cs | 28 + .../Dialogs/UpdateDetailsViewVM.cs | 21 + .../Tango.PPC.Technician/Images/browser.png | Bin 0 -> 2539 bytes .../Tango.PPC.Technician/Images/circuit-board.png | Bin 0 -> 2492 bytes .../Tango.PPC.Technician/Images/conveyor.png | Bin 0 -> 4349 bytes .../Modules/Tango.PPC.Technician/Images/exit.png | Bin 0 -> 1784 bytes .../Tango.PPC.Technician/Images/mobile-phone.png | Bin 0 -> 4438 bytes .../Tango.PPC.Technician/Images/packages.png | Bin 0 -> 1781 bytes .../Images/remote_connections.png | Bin 0 -> 4186 bytes .../Tango.PPC.Technician/Images/shutdown.png | Bin 0 -> 3703 bytes .../Modules/Tango.PPC.Technician/Images/sync.png | Bin 0 -> 4127 bytes .../Tango.PPC.Technician.csproj | 71 + .../Tango.PPC.Technician/ViewModelLocator.cs | 36 + .../ViewModels/CatalogViewVM.cs | 23 +- .../ViewModels/LoggingViewVM.cs | 125 +- .../Tango.PPC.Technician/ViewModels/MainViewVM.cs | 4 +- .../ViewModels/PackagesViewVM.cs | 44 + .../ViewModels/RemoteConnectionsViewVM.cs | 64 + .../ViewModels/SystemViewVM.cs | 87 +- .../ViewModels/UpdatesViewVM.cs | 107 ++ .../Tango.PPC.Technician/Views/CatalogView.xaml | 134 +- .../Tango.PPC.Technician/Views/LoggingView.xaml | 178 +- .../Tango.PPC.Technician/Views/MainView.xaml | 3 + .../Tango.PPC.Technician/Views/PackagesView.xaml | 103 ++ .../Views/PackagesView.xaml.cs | 28 + .../Views/RemoteConnectionsView.xaml | 88 + .../Views/RemoteConnectionsView.xaml.cs | 28 + .../Tango.PPC.Technician/Views/SystemView.xaml | 321 +++- .../Tango.PPC.Technician/Views/UpdatesView.xaml | 160 ++ .../Tango.PPC.Technician/Views/UpdatesView.xaml.cs | 28 + .../Application/IPPCApplicationManager.cs | 31 + .../Authentication/IAuthenticationProvider.cs | 11 + .../Tango.PPC.Common/BackupRestore/BackupFile.cs | 81 + .../Tango.PPC.Common/BackupRestore/BackupMode.cs | 23 + .../BackupRestoreProgressEventArgs.cs | 36 + .../BackupRestore/BackupRestoreStage.cs | 63 + .../BackupRestore/BackupSettings.cs | 19 + .../BackupRestore/DefaultBackupManager.cs | 604 +++++++ .../BackupRestore/IBackupManager.cs | 43 + .../BackupRestore/RestoreResult.cs | 14 + .../BackupRestore/RestoreSettings.cs | 31 + .../Connection/DefaultMachineProvider.cs | 136 +- .../Connection/IMachineProvider.cs | 15 + .../Connectivity/IConnectivityProvider.cs | 7 +- .../Console/DefaultConsoleEngineService.cs | 92 + .../Console/IConsoleEngineService.cs | 16 + .../Controls/ImageGalleryControl.cs | 114 ++ .../Controls/ImageGalleryControl.xaml | 101 ++ .../DataStore/DefaultDataStoreService.cs | 492 +++++ .../DataStore/IDataStoreService.cs | 14 + .../EventLogging/DefaultEventLogger.cs | 61 +- .../Tango.PPC.Common/EventLogging/IEventLogger.cs | 3 +- .../ExternalBridge/PPCExternalBridgeService.cs | 36 +- .../FileSystem/DefaultFileSystemService.cs | 433 +++++ .../FileSystem/FileSystemOperation.cs | 51 + .../FileSystem/FileSystemOperationMode.cs | 14 + .../FileSystem/IFileSystemService.cs | 20 + .../PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs | 24 + .../PPC/Tango.PPC.Common/Helpers/LogsHelper.cs | 24 + .../PPC/Tango.PPC.Common/IPPCService.cs | 36 + .../PPC/Tango.PPC.Common/Images/cl-full.png | Bin 0 -> 3454 bytes .../PPC/Tango.PPC.Common/Images/lubricant2.png | Bin 0 -> 194234 bytes .../Insights/DefaultInsightsService.cs | 154 ++ .../Tango.PPC.Common/Insights/IInsightsService.cs | 13 + .../MachineSetup/MachineSetupManager.cs | 200 ++- .../MachineUpdate/IMachineUpdateManager.cs | 59 +- .../MachineUpdate/MachineUpdateManager.cs | 1877 +++++++++++++++----- .../MachineUpdate/MachineUpdateResult.cs | 13 + .../MachineUpdate/UpdatePackageFile.cs | 13 - .../PPC/Tango.PPC.Common/Models/FineTuneItem.cs | 2 + .../Navigation/INavigationManager.cs | 17 +- .../Tango.PPC.Common/Navigation/NavigationView.cs | 3 +- .../Tango.PPC.Common/Notifications/AppBarItem.cs | 10 + .../Notifications/AppBarPriority.cs | 15 + .../Notifications/INotificationProvider.cs | 16 +- .../Notifications/NotificationItem.cs | 25 +- .../NotificationItems/MessageNotificationItem.cs | 3 +- .../MessageNotificationItemView.xaml | 14 +- .../OS/DefaultOperationSystemManager.cs | 22 + .../Tango.PPC.Common/OS/IOperationSystemManager.cs | 11 + .../PPC/Tango.PPC.Common/PPCSettings.cs | 190 +- .../PPC/Tango.PPC.Common/PPCViewModel.cs | 50 +- .../Performance/DefaultPerformanceService.cs | 219 +++ .../Performance/IPerformanceService.cs | 14 + .../Properties/Resources.Designer.cs | 22 +- .../PPC/Tango.PPC.Common/Properties/Resources.resx | 20 +- .../PPC/Tango.PPC.Common/Publish/PPCPublisher.cs | 97 +- .../PPC/Tango.PPC.Common/Publish/PublishInfo.cs | 22 +- .../PPC/Tango.PPC.Common/Publish/PublishOptions.cs | 25 +- .../RemoteActions/IRemoteActionsService.cs | 13 + .../DefaultRemoteAssistanceProvider.cs | 31 +- .../RemoteAssistance/IRemoteAssistanceProvider.cs | 4 +- .../RemoteDesktop/DefaultRemoteDesktopService.cs | 584 ++++++ .../RemoteDesktop/IRemoteDesktopService.cs | 24 + .../RemoteDesktop/RemoteDesktopClient.cs | 20 + .../RemoteJob/DefaultRemoteJobService.cs | 177 ++ .../RemoteJob/IRemoteJobService.cs | 14 + .../PPC/Tango.PPC.Common/Resources/Colors.xaml | 11 + .../PPC/Tango.PPC.Common/Resources/Merged.xaml | 10 + .../PPC/Tango.PPC.Common/Resources/Styles.xaml | 65 + .../PPC/Tango.PPC.Common/Resources/finger3.png | Bin 0 -> 1005 bytes .../PPC/Tango.PPC.Common/Resources/tap.png | Bin 0 -> 1316 bytes .../SQL/DefaultRemoteSqlService.cs | 59 + .../PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs | 13 + .../PPC/Tango.PPC.Common/SafetyLevelOperations.csv | 3 + .../Storage/DefaultStorageProvider.cs | 23 +- .../Tango.PPC.Common/Storage/IStorageProvider.cs | 6 +- .../DefaultMachineDataSynchronizer.cs | 662 +++++++ .../Synchronization/IMachineDataSynchronizer.cs | 26 + .../SynchronizationEndedEventArgs.cs | 15 + .../Synchronization/SynchronizationState.cs | 23 + .../Synchronization/SynchronizationStatus.cs | 47 + .../SynchronizationStatusChangedEventArgs.cs | 13 + .../SystemInfo/DefaultSystemInfoService.cs | 138 ++ .../SystemInfo/ISystemInfoService.cs | 17 + .../PPC/Tango.PPC.Common/Tango.PPC.Common.csproj | 141 +- .../ThreadLoading/IThreadLoadingService.cs | 14 + .../UWF/AlternativeUnifiedWriteFilterManager.cs | 48 +- .../UWF/DefaultUnifiedWriteFilterManager.cs | 35 +- .../UWF/IUnifiedWriteFilterManager.cs | 3 +- .../UpdatePackages/DefaultPackageRunner.cs | 362 ++++ .../Tango.PPC.Common/UpdatePackages/IPPCPackage.cs | 13 + .../UpdatePackages/IPackageRunner.cs | 18 + .../UpdatePackages/PPCPackageAttribute.cs | 26 + .../UpdatePackages/PackageContext.cs | 28 + .../UpdatePackages/PackageProgressEventArgs.cs | 17 + .../UpdatePackages/PackageRunnerResult.cs | 13 + .../UpdatePackages/PackageStateChangedEventArgs.cs | 16 + .../UpdatePackages/PackagesFile.cs | 19 + .../Tango.PPC.Common/Web/CheckForUpdateRequest.cs | 16 +- .../Tango.PPC.Common/Web/CheckForUpdateResponse.cs | 10 + .../Web/DownloadMachineDataRequest.cs | 24 + .../Web/DownloadMachineDataResponse.cs | 27 + .../Tango.PPC.Common/Web/DownloadUpdateRequest.cs | 2 +- .../Tango.PPC.Common/Web/DownloadUpdateResponse.cs | 6 + .../Tango.PPC.Common/Web/LatestVersionResponse.cs | 1 + .../PPC/Tango.PPC.Common/Web/LoginRequest.cs | 1 + .../Tango.PPC.Common/Web/MachineSetupRequest.cs | 1 - .../Tango.PPC.Common/Web/MachineSetupResponse.cs | 7 + .../Web/MachineUpdateCompletedRequest.cs | 19 + .../Web/MachineUpdateCompletedResponse.cs | 15 + .../NotifyMachineDataDownloadCompletedRequest.cs | 27 + .../NotifyMachineDataDownloadCompletedResponse.cs | 16 + .../PPC/Tango.PPC.Common/Web/PPCWebClient.cs | 5 + .../PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs | 45 + .../Web/SynchronizationFailedEntity.cs | 14 + .../PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs | 3 +- .../PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs | 1 + .../PPC/Tango.PPC.Common/Web/UpdatedEntity.cs | 31 + .../Web/UploadMachineDataRequest.cs | 31 + .../Web/UploadMachineDataResponse.cs | 31 + .../PPC/Tango.PPC.Common/packages.config | 1 + .../PPC/Tango.PPC.DataSynchronizer.CLI/App.config | 28 + .../PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs | 107 ++ .../Properties/AssemblyInfo.cs | 36 + .../Tango.PPC.DataSynchronizer.CLI.csproj | 75 + .../Tango.PPC.DataSynchronizer.CLI/packages.config | 4 + .../PPC/Tango.PPC.Publisher.UI/MainWindow.xaml | 19 +- .../PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs | 27 +- .../Tango.PPC.Publisher.UI.csproj | 6 + .../Tango.PPC.Publisher.UI.json | 164 ++ .../Tango.PPC.SchemaSynchronizer.CLI/App.config | 6 + .../Tango.PPC.SchemaSynchronizer.CLI/Program.cs | 54 + .../Properties/AssemblyInfo.cs | 36 + .../Tango.PPC.SchemaSynchronizer.CLI.csproj | 63 + .../Events/PushEmulatedEventRequest.cs | 20 + .../Events/PushEmulatedEventResponse.cs | 12 + .../Information/GetMachineInformationRequest.cs | 12 + .../Information/GetMachineInformationResponse.cs | 13 + .../Information/InformationPackage.cs | 19 + .../Insights/InsightsDownloadCompletedRequest.cs | 13 + .../Insights/InsightsDownloadCompletedResponse.cs | 12 + .../Insights/InsightsMinDateRequest.cs | 12 + .../Insights/InsightsMinDateResponse.cs | 13 + .../Tango.PPC.Shared/Insights/InsightsRequest.cs | 25 + .../Tango.PPC.Shared/Insights/InsightsResponse.cs | 14 + .../PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs | 21 + .../PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs | 18 + .../Jobs/RemoteJobUpdateRequest.cs | 13 + .../Jobs/RemoteJobUpdateResponse.cs | 22 + .../Tango.PPC.Shared/Logs/GetLogFilesRequest.cs | 13 + .../Tango.PPC.Shared/Logs/GetLogFilesResponse.cs | 18 + .../PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs | 17 + .../PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs | 14 + .../Performance/PerformancePackage.cs | 25 + .../Performance/StartPerformanceUpdatesRequest.cs | 12 + .../Performance/StartPerformanceUpdatesResponse.cs | 13 + .../Tango.PPC.Shared/Properties/AssemblyInfo.cs | 23 + .../Properties/Resources.Designer.cs | 62 + .../PPC/Tango.PPC.Shared/Properties/Resources.resx | 117 ++ .../Properties/Settings.Designer.cs | 30 + .../Tango.PPC.Shared/Properties/Settings.settings | 7 + .../SimulateApplicationExceptionRequest.cs | 13 + .../SimulateApplicationExceptionResponse.cs | 12 + .../StartRemoteApplicationUpgradeRequest.cs | 15 + .../StartRemoteApplicationUpgradeResponse.cs | 24 + .../StartRemoteFirmwareUpgradeRequest.cs | 13 + .../StartRemoteFirmwareUpgradeResponse.cs | 24 + .../PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs | 13 + .../PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs | 19 + .../PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs | 52 + .../SQL/RemoteSqlColumnCollection.cs | 78 + .../PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs | 188 ++ .../PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs | 153 ++ .../PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj | 148 ++ .../PPC/Tango.PPC.Shared/Themes/Generic.xaml | 6 + .../Updates/GetUpdatesAndPackagesRequest.cs | 13 + .../Updates/GetUpdatesAndPackagesResponse.cs | 22 + .../Updates/PackageInstallation.cs | 26 + .../Updates/PackageInstallationState.cs | 15 + .../PPC/Tango.PPC.Shared/Updates/PackageType.cs | 14 + Software/Visual_Studio/PPC/Tango.PPC.UI/App.config | 7 +- .../Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs | 102 +- .../Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.cs | 31 + .../AppBarItems/PowerOffAppBarItemView.xaml | 30 + .../AppBarItems/PowerOffAppBarItemView.xaml.cs | 28 + .../Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs | 31 + .../AppBarItems/PowerUpAppBarItemView.xaml | 30 + .../AppBarItems/PowerUpAppBarItemView.xaml.cs | 28 + .../DefaultAuthenticationProvider.cs | 18 + .../Connectivity/DefaultConnectivityProvider.cs | 44 +- .../Controls/MachineStatusControl.xaml | 49 + .../Controls/MachineStatusControl.xaml.cs | 28 + .../Dialogs/FirmwareUpgradeFromFileView.xaml | 28 + .../Dialogs/FirmwareUpgradeFromFileView.xaml.cs | 28 + .../Dialogs/FirmwareUpgradeFromFileViewVM.cs | 15 + .../Dialogs/InsufficientLiquidQuantityView.xaml | 62 +- .../Dialogs/InsufficientLiquidQuantityView.xaml.cs | 6 +- .../PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml | 32 + .../PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs | 34 + .../PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs | 128 ++ .../SafetyLevelOperationsConfirmationView.xaml | 52 + .../SafetyLevelOperationsConfirmationView.xaml.cs | 28 + .../SafetyLevelOperationsConfirmationViewVM.cs | 82 + .../PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml | 225 +++ .../Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs | 28 + .../PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs | 245 +++ .../Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml | 170 ++ .../Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs | 28 + .../Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs | 287 +++ .../Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml | 21 +- .../Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs | 8 +- .../PPC/Tango.PPC.UI/Images/GlobalStatus/error.png | Bin 0 -> 810 bytes .../Images/GlobalStatus/getting-ready.png | Bin 0 -> 586 bytes .../Tango.PPC.UI/Images/GlobalStatus/service.png | Bin 0 -> 844 bytes .../Images/GlobalStatus/shutting-down.png | Bin 0 -> 1190 bytes .../PPC/Tango.PPC.UI/Images/Menu/backup.png | Bin 0 -> 1834 bytes .../Images/ThreadLoading/DryerClose/1.jpg | Bin 0 -> 57998 bytes .../Images/ThreadLoading/DryerClose/2.jpg | Bin 0 -> 58057 bytes .../Images/ThreadLoading/DryerClose/3.jpg | Bin 0 -> 59306 bytes .../Images/ThreadLoading/DryerClose/4.jpg | Bin 0 -> 55777 bytes .../Images/ThreadLoading/FeedingUnits/1.JPG | Bin 0 -> 50823 bytes .../Images/ThreadLoading/FeedingUnits/2.JPG | Bin 0 -> 36100 bytes .../Images/ThreadLoading/FeedingUnits/3.JPG | Bin 0 -> 52652 bytes .../Images/ThreadLoading/FeedingUnits/4.JPG | Bin 0 -> 62531 bytes .../Images/ThreadLoading/FeedingUnits/arc/1.jpg | Bin 0 -> 50823 bytes .../Images/ThreadLoading/FeedingUnits/arc/2.jpg | Bin 0 -> 36100 bytes .../Images/ThreadLoading/FeedingUnits/arc/3.jpg | Bin 0 -> 52652 bytes .../Images/ThreadLoading/FeedingUnits/arc/4.jpg | Bin 0 -> 62531 bytes .../Images/ThreadLoading/FeedingUnits/arc/5.jpg | Bin 0 -> 123123 bytes .../Images/ThreadLoading/GuidingUnits/1.JPG | Bin 0 -> 47345 bytes .../NewThread/ReadyForLoading/arc/1.jpg | Bin 0 -> 70545 bytes .../NewThread/ReadyForLoading/arc/2.JPG | Bin 0 -> 50823 bytes .../NewThread/ReadyForLoading/arc/3.JPG | Bin 0 -> 36100 bytes .../NewThread/ReadyForLoading/arc/4.JPG | Bin 0 -> 85970 bytes .../NewThread/ReadyForLoading/arc/5.JPG | Bin 0 -> 123123 bytes .../NewThread/ReadyForLoading/arc/6.JPG | Bin 0 -> 67829 bytes .../NewThread/ReadyForLoading/arc/7.jpg | Bin 0 -> 229536 bytes .../NewThread/TS1800_CloseUp_Feeder_P.jpg | Bin 0 -> 94899 bytes .../ThreadLoading/NewThread/machine_full.jpg | Bin 0 -> 67243 bytes .../Images/ThreadLoading/TheDryer/1.jpg | Bin 0 -> 39336 bytes .../Images/ThreadLoading/TheDryer/2.jpg | Bin 0 -> 36100 bytes .../Images/ThreadLoading/TheDryer/3.jpg | Bin 0 -> 45420 bytes .../Images/ThreadLoading/TheDryer/4.jpg | Bin 0 -> 46782 bytes .../Images/ThreadLoading/TheDryer/5.jpg | Bin 0 -> 49932 bytes .../PPC/Tango.PPC.UI/Images/backup-big.png | Bin 0 -> 3044 bytes .../PPC/Tango.PPC.UI/Images/backup-restore.png | Bin 0 -> 89496 bytes .../PPC/Tango.PPC.UI/Images/firmware.png | Bin 0 -> 3956 bytes .../PPC/Tango.PPC.UI/Images/loading_anim.gif | Bin 0 -> 798338 bytes .../PPC/Tango.PPC.UI/Images/machine-image.png | Bin 0 -> 138220 bytes .../PPC/Tango.PPC.UI/Images/power_off.gif | Bin 0 -> 397334 bytes .../PPC/Tango.PPC.UI/Images/power_off_2.gif | Bin 0 -> 32040 bytes .../PPC/Tango.PPC.UI/Images/powerup.gif | Bin 0 -> 380322 bytes .../PPC/Tango.PPC.UI/Images/restore.png | Bin 0 -> 3252 bytes .../PPC/Tango.PPC.UI/Images/thread_loading.gif | Bin 0 -> 4092741 bytes .../PPC/Tango.PPC.UI/Images/thread_loading.png | Bin 0 -> 7209 bytes .../Tango.PPC.UI/Images/thread_loading_preview.png | Bin 0 -> 529370 bytes .../PPC/Tango.PPC.UI/Images/update_available.png | Bin 0 -> 2856 bytes .../PPC/Tango.PPC.UI/InternalModule.cs | 84 + .../PPC/Tango.PPC.UI/MainWindow.xaml.cs | 21 +- .../Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs | 156 ++ .../Modules/DefaultStudioModuleLoader.cs | 152 -- .../Navigation/DefaultNavigationManager.cs | 382 ++-- .../Notifications/DefaultNotificationProvider.cs | 128 +- .../UpdateAvailableNotificationItem.cs | 52 + .../UpdateAvailableNotificationItemView.xaml | 30 + .../UpdateAvailableNotificationItemView.xaml.cs | 30 + .../PPCApplication/DefaultPPCApplicationManager.cs | 252 ++- .../Printing/DefaultPrintingManager.cs | 6 +- .../PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs | 2 +- .../RemoteActions/DefaultRemoteActionsService.cs | 54 + .../PPC/Tango.PPC.UI/Resources/Colors.xaml | 2 + .../PPC/Tango.PPC.UI/Tango.PPC.UI.csproj | 223 ++- .../ThreadLoading/DefaultThreadLoadingService.cs | 65 + .../PPC/Tango.PPC.UI/ViewModelLocator.cs | 84 +- .../ViewModels/ExternalBridgeViewVM.cs | 52 +- .../ViewModels/InternalModuleViewVM.cs | 17 + .../PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs | 250 ++- .../PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs | 65 +- .../PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs | 8 +- .../Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs | 5 +- .../Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs | 536 +++++- .../PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs | 154 ++ .../PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs | 134 ++ .../Tango.PPC.UI/ViewModels/RestartingViewVM.cs | 27 + .../PPC/Tango.PPC.UI/Views/EmergencyView.xaml | 16 +- .../PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml | 19 +- .../PPC/Tango.PPC.UI/Views/InternalModuleView.xaml | 18 + .../Tango.PPC.UI/Views/InternalModuleView.xaml.cs | 28 + .../PPC/Tango.PPC.UI/Views/LayoutView.xaml | 131 +- .../PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs | 16 +- .../PPC/Tango.PPC.UI/Views/LoadingView.xaml | 11 +- .../PPC/Tango.PPC.UI/Views/MachineSetupView.xaml | 2 +- .../PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml | 5 +- .../Tango.PPC.UI/Views/MachineUpdateView.xaml.cs | 6 +- .../PPC/Tango.PPC.UI/Views/MainView.xaml | 58 +- .../PPC/Tango.PPC.UI/Views/PowerOffView.xaml | 20 + .../PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs | 28 + .../Tango.PPC.UI/Views/RestartingSystemView.xaml | 40 +- .../PPC/Tango.PPC.UI/Views/RestartingView.xaml | 52 + .../PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs | 28 + .../Visual_Studio/PPC/Tango.PPC.UI/app.manifest | 2 +- .../PPC/Tango.PPC.UI/firmware_package.tfp | Bin 0 -> 270787 bytes .../PPC/Tango.PPC.Updater/IdentityUtils.cs | 118 ++ .../PPC/Tango.PPC.Updater/Images/warning.png | Bin 0 -> 8947 bytes .../PPC/Tango.PPC.Updater/MainWindow.xaml | 35 +- .../PPC/Tango.PPC.Updater/MainWindow.xaml.cs | 174 +- .../PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj | 4 + .../Tango.PPC.Packages.Auth2/Auth2.cs | 79 + .../Properties/AssemblyInfo.cs | 36 + .../Tango.PPC.Packages.Auth2.csproj | 88 + .../Tango.PPC.Packages.Auth2/app.config | 39 + .../Tango.PPC.Packages.Auth2/packages.config | 4 + .../CefInstaller.cs | 58 + .../Properties/AssemblyInfo.cs | 36 + .../Tango.PPC.Packages.CefInstaller.csproj | 77 + .../App.config | 49 + .../JobRunsStartTimePatch.cs | 41 + .../Properties/AssemblyInfo.cs | 36 + ...Tango.PPC.Packages.JobRunsStartTimePatch.csproj | 88 + .../packages.config | 4 + .../Properties/AssemblyInfo.cs | 36 + .../SamplePostPackage.cs | 23 + .../Tango.PPC.Packages.SamplePostPackage.csproj | 70 + .../Properties/AssemblyInfo.cs | 36 + .../SamplePrePackage.cs | 23 + .../Tango.PPC.Packages.SamplePrePackage.csproj | 70 + 559 files changed, 27293 insertions(+), 1794 deletions(-) create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/App.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/BackupRestoreModule.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.resx create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.settings create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Tango.PPC.BackupRestore.csproj create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModelLocator.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupCompletedViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupErrorViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/MainViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreCompletedViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreErrorViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/WelcomeViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/app.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/packages.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/App.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Attributes/BoundObjectAttribute.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BoundsObjects/KeyboardHandler.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BrowserModule.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zip create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Helpers/BoundObjectsHelper.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Navigation/BrowserNavigationRequest.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.resx create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.settings create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/RequestHandlers/ChromiumRequestHandler.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Scripts/keyboard.js create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Tango.PPC.Browser.csproj create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewContracts/IBrowserView.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModelLocator.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModels/BrowserViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/app.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/packages.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobOutlineControl.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpg create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpg create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItem.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/App.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/HomingMotorCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseDyeingHeadCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseLeftLeadingWheelsCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseMotorCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseRightLeadingWheelsCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/ResetThreadLoadingCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Controls/StateTouchButton.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToBrushConverter.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToShortNameConverter.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/MidTankLevelToElementHeightConverter.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/StringToFirstLetterConverter.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/HandleWasteCartridgeGuide.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadInkCartridgeGuide.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadNewThreadGuide.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceAirFilterGuide.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceThreadGuide.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Helpers/GuideHelper.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gif create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gif create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gif create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gif create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gif create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceCommand.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceModule.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/MidTankLevelModel.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/OverallTemperatureModel.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.resx create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.settings create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Resources/Guides.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Tango.PPC.Maintenance.csproj create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Themes/Generic.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModelLocator.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/GeneralGuideViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MainViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MaintenanceViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/app.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/packages.config create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.png create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/PackagesViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/RemoteConnectionsViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/UpdatesViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml create mode 100644 Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupFile.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupMode.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreProgressEventArgs.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreStage.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupSettings.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/DefaultBackupManager.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/IBackupManager.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreResult.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreSettings.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/IDataStoreService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/LogsHelper.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/IInsightsService.cs delete mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarPriority.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/DefaultRemoteJobService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/IRemoteJobService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/SafetyLevelOperations.csv create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/DefaultMachineDataSynchronizer.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/IMachineDataSynchronizer.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationEndedEventArgs.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationState.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatus.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatusChangedEventArgs.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/ThreadLoading/IThreadLoadingService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/DefaultPackageRunner.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPPCPackage.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPackageRunner.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PPCPackageAttribute.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageContext.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageProgressEventArgs.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageRunnerResult.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageStateChangedEventArgs.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackagesFile.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/SynchronizationFailedEntity.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdatedEntity.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/App.config create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Tango.PPC.DataSynchronizer.CLI.csproj create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/packages.config create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.json create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/App.config create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Program.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Tango.PPC.SchemaSynchronizer.CLI.csproj create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/InformationPackage.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/PerformancePackage.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.resx create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.Designer.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.settings create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumnCollection.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Themes/Generic.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesRequest.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesResponse.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallation.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallationState.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageType.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPG create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpg create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gif create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gif create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gif create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gif create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gif create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.png create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/InternalModule.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs delete mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItem.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/ThreadLoading/DefaultThreadLoadingService.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/InternalModuleViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/RestartingViewVM.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfp create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Updater/IdentityUtils.cs create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.png create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Auth2.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Tango.PPC.Packages.Auth2.csproj create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/app.config create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/packages.config create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/App.config create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/JobRunsStartTimePatch.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Tango.PPC.Packages.JobRunsStartTimePatch.csproj create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/packages.config create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Properties/AssemblyInfo.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs create mode 100644 Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj (limited to 'Software/Visual_Studio/PPC') diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/App.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/App.xaml new file mode 100644 index 000000000..595ed2299 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/App.xaml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/BackupRestoreModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/BackupRestoreModule.cs new file mode 100644 index 000000000..25cdfbb27 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/BackupRestoreModule.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.BL.Enumerations; +using Tango.PPC.Common; +using Tango.PPC.BackupRestore.Views; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.BackupRestore +{ + /// + /// Represents a PPC . + /// + /// + [PPCModule(20)] + public class BackupRestoreModule : PPCModuleBase + { + /// + /// Gets the module name. + /// + public override string Name + { + get + { + return "Backup & Restore"; + } + } + + /// + /// Gets the module description. + /// + public override string Description + { + get + { + return "Tango Backup/Restore Module"; + } + } + + /// + /// Gets the module cover image. + /// + public override BitmapSource Image + { + get + { + return ResourceHelper.GetImageFromResources("Images/backup-big.png"); + } + } + + /// + /// Gets the module entry point view type. + /// + public override Type MainViewType + { + get + { + return typeof(MainView); + } + } + + /// + /// Gets the permission required to see and load this module. + /// + public override Permissions Permission + { + get + { + return Permissions.RunPPC; + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public override void Dispose() + { + //Dispose module here... + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.png new file mode 100644 index 000000000..3a712af49 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.png new file mode 100644 index 000000000..15be3b163 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.png new file mode 100644 index 000000000..e60aaf425 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ac385e0ba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango Backup & Restore Module")] +[assembly: AssemblyVersion("2.0.1.1407")] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.Designer.cs new file mode 100644 index 000000000..160bdf95c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.BackupRestore.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.PPC.BackupRestore.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.resx b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.Designer.cs new file mode 100644 index 000000000..087ecdbcd --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.BackupRestore.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.settings b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Tango.PPC.BackupRestore.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Tango.PPC.BackupRestore.csproj new file mode 100644 index 000000000..99ac13ae4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Tango.PPC.BackupRestore.csproj @@ -0,0 +1,246 @@ + + + + + Debug + AnyCPU + {BC2753F8-C0F7-48F5-A85C-149EC7A2F8C7} + library + Tango.PPC.BackupRestore + Tango.PPC.BackupRestore + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + true + full + false + ..\..\..\Build\PPC\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll + True + + + ..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll + + + ..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll + + + + + + ..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + GlobalVersionInfo.cs + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + + + + + + RestoreCompletedView.xaml + + + BackupCompletedView.xaml + + + RestoreErrorView.xaml + + + BackupErrorView.xaml + + + RestoreProgressView.xaml + + + BackupProgressView.xaml + + + BackupView.xaml + + + MainView.xaml + + + RestoreView.xaml + + + WelcomeView.xaml + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {b112d89a-a106-41ae-a0c1-4abc84c477f5} + Tango.DragAndDrop + + + {4399AF76-DB52-4CFB-8020-6F85BDB29FD5} + Tango.Explorer + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + + + {e4927038-348d-4295-aaf4-861c58cb3943} + Tango.PMR + + + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} + Tango.Settings + + + {8491d07b-c1f6-4b62-a412-41b9fd2d6538} + Tango.SharedUI + + + {fd86424c-6e84-491b-8df9-3d0f5c236a2a} + Tango.Touch + + + {74e700b0-1156-4126-be40-ee450d3c3026} + Tango.Transport + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + + + {04FEBB02-F782-4B96-B47D-F6902AFA43BE} + Tango.PPC.Storage + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModelLocator.cs new file mode 100644 index 000000000..698a70cd7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModelLocator.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.PPC.BackupRestore.ViewModels; + +namespace Tango.PPC.BackupRestore +{ + public static class ViewModelLocator + { + /// + /// Initializes a new instance of the ViewModelLocator class. + /// + static ViewModelLocator() + { + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + } + + /// + /// Gets the main view VM. + /// + public static MainViewVM MainViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static WelcomeViewVM WelcomeViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static BackupViewVM BackupViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static RestoreViewVM RestoreViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static BackupErrorViewVM BackupErrorViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static BackupCompletedViewVM BackupCompletedViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static RestoreErrorViewVM RestoreErrorViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static RestoreCompletedViewVM RestoreCompletedViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupCompletedViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupCompletedViewVM.cs new file mode 100644 index 000000000..8c40bf288 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupCompletedViewVM.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Common.Navigation; +using static Tango.PPC.BackupRestore.ViewModels.BackupCompletedViewVM; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class BackupCompletedViewVM : PPCViewModel + { + public override void OnApplicationStarted() + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupErrorViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupErrorViewVM.cs new file mode 100644 index 000000000..42f2c9e51 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupErrorViewVM.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Common.Navigation; +using static Tango.PPC.BackupRestore.ViewModels.BackupErrorViewVM; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class BackupErrorViewVM : PPCViewModel, INavigationObjectReceiver + { + public class BackupErrorNavigationObject + { + public String Error { get; set; } + } + + private String _error; + public String Error + { + get { return _error; } + set { _error = value; RaisePropertyChangedAuto(); } + } + + public override void OnApplicationStarted() + { + + } + + public void OnNavigatedToWithObject(BackupErrorNavigationObject obj) + { + Error = obj.Error; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupViewVM.cs new file mode 100644 index 000000000..ef5b3810c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupViewVM.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Explorer; +using Tango.PPC.BackupRestore.Views; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Storage; +using static Tango.PPC.BackupRestore.ViewModels.BackupErrorViewVM; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class BackupViewVM : PPCViewModel + { + private String _backupFileName; + + [TangoInject] + public IBackupManager BackupManager { get; set; } + + private BackupRestoreProgressEventArgs _currentBackupProgress; + public BackupRestoreProgressEventArgs CurrentBackupProgress + { + get { return _currentBackupProgress; } + set { _currentBackupProgress = value; RaisePropertyChangedAuto(); } + } + + private bool _isBackupJobs; + public bool IsBackupJobs + { + get { return _isBackupJobs; } + set + { + if (value) + { + _isBackupJobs = value; + RaisePropertyChangedAuto(); + _isBackupFull = false; + RaisePropertyChanged(nameof(IsBackupFull)); + } + else + { + RaisePropertyChangedAuto(); + } + } + } + + private bool _isBackupFull; + public bool IsBackupFull + { + get { return _isBackupFull; } + set + { + if (value) + { + _isBackupFull = value; + RaisePropertyChangedAuto(); + _isBackupJobs = false; + RaisePropertyChanged(nameof(IsBackupJobs)); + } + else + { + RaisePropertyChangedAuto(); + } + } + } + + private String _backupLocation; + public String BackupLocation + { + get { return _backupLocation; } + set { _backupLocation = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _backupName; + public String BackupName + { + get { return _backupName; } + set { _backupName = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + public RelayCommand BackupCommand { get; set; } + + public RelayCommand BrowseBackupLocationCommand { get; set; } + + public BackupViewVM() + { + BrowseBackupLocationCommand = new RelayCommand(BrowseBackupLocation); + BackupCommand = new RelayCommand(StartBackup, () => !String.IsNullOrWhiteSpace(BackupName) && BackupLocation != null); + IsBackupJobs = true; + } + + private async void StartBackup() + { + await NavigationManager.NavigateTo(nameof(BackupProgressView), false); + + try + { + IsFree = false; + NavigationManager.IsBackEnabled = false; + await BackupManager.CreateBackup(_backupFileName, BackupName, new BackupSettings() + { + Mode = IsBackupFull ? BackupMode.Full : BackupMode.Jobs, + }); + await NavigationManager.NavigateTo(nameof(BackupCompletedView), false); + } + catch (Exception ex) + { + LogManager.Log(ex, "The backup operation failed."); + + await NavigationManager.NavigateWithObject(new BackupErrorNavigationObject() + { + Error = ex.FlattenMessage(), + }, false); + } + finally + { + IsFree = true; + NavigationManager.IsBackEnabled = true; + } + } + + public override void OnApplicationStarted() + { + + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + BackupManager.Progress += BackupManager_Progress; + } + + private void BackupManager_Progress(object sender, BackupRestoreProgressEventArgs e) + { + CurrentBackupProgress = e; + } + + private async void BrowseBackupLocation() + { + var result = await NavigationManager. + NavigateForResult( + new Storage.Models.StorageNavigationRequest() + { + Intent = Storage.Models.StorageNavigationIntent.SaveFile, + DefaultFileName = $"Tango-Backup-{DateTime.Now.ToFileName()}", + Filter = ExplorerFileDefinition.Backup.Extension, + Title = "Select Destination Backup File", + }); + + if (result != null) + { + _backupFileName = result.Path + ExplorerFileDefinition.Backup.Extension; + BackupLocation = result.Path + ExplorerFileDefinition.Backup.Extension; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..989f8a6ee --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/MainViewVM.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Explorer; +using Tango.PPC.BackupRestore.Views; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Storage; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class MainViewVM : PPCViewModel + { + public override void OnNavigatedFrom() + { + base.OnNavigatedFrom(); + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + NavigationManager.NavigateTo(nameof(WelcomeView), false); + } + + public override void OnApplicationStarted() + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreCompletedViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreCompletedViewVM.cs new file mode 100644 index 000000000..d773aa5d4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreCompletedViewVM.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.Helpers; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Common.Navigation; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class RestoreCompletedViewVM : PPCViewModel, INavigationObjectReceiver + { + private RestoreResult _restoreResult; + + public RelayCommand RestartCommand { get; set; } + + public RestoreCompletedViewVM() + { + RestartCommand = new RelayCommand(Restart); + } + + private void Restart() + { + if (_restoreResult.BackupFile.Settings.Mode == BackupMode.Jobs) + { + //Perform normal restart. + ApplicationManager.Restart(); + } + else + { + //Perform update restart using the result path. + String updater_exe = Path.Combine(_restoreResult.FolderPath, "Tango.PPC.Updater.exe"); + ApplicationManager.UpdateApplication(updater_exe, PathHelper.GetStartupPath()); + } + } + + public override void OnApplicationStarted() + { + + } + + public void OnNavigatedToWithObject(RestoreResult restoreResult) + { + _restoreResult = restoreResult; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreErrorViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreErrorViewVM.cs new file mode 100644 index 000000000..b6df53318 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreErrorViewVM.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.BackupRestore.Views; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Common.Navigation; +using static Tango.PPC.BackupRestore.ViewModels.RestoreErrorViewVM; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class RestoreErrorViewVM : PPCViewModel, INavigationObjectReceiver + { + public class RestoreErrorNavigationObject + { + public String Error { get; set; } + } + + private String _error; + public String Error + { + get { return _error; } + set { _error = value; RaisePropertyChangedAuto(); } + } + + public override void OnApplicationStarted() + { + + } + + public void OnNavigatedToWithObject(RestoreErrorNavigationObject obj) + { + Error = obj.Error; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreViewVM.cs new file mode 100644 index 000000000..d925ebad1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreViewVM.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Explorer; +using Tango.PPC.BackupRestore.Views; +using Tango.PPC.Common; +using Tango.PPC.Common.BackupRestore; +using Tango.PPC.Storage; +using static Tango.PPC.BackupRestore.ViewModels.RestoreErrorViewVM; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class RestoreViewVM : PPCViewModel + { + private string _backupFileLocation; + private bool _isBrowsing; + + [TangoInject] + public IBackupManager BackupManager { get; set; } + + private String _backupFileName; + public String BackupFileName + { + get { return _backupFileName; } + set { _backupFileName = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private RestoreSettings _restoreSettings; + public RestoreSettings RestoreSettings + { + get { return _restoreSettings; } + set { _restoreSettings = value; RaisePropertyChangedAuto(); } + } + + private BackupFile _backupFile; + public BackupFile BackupFile + { + get { return _backupFile; } + set { _backupFile = value; RaisePropertyChangedAuto(); } + } + + private BackupRestoreProgressEventArgs _currentRestoreProgress; + public BackupRestoreProgressEventArgs CurrentRestoreProgress + { + get { return _currentRestoreProgress; } + set { _currentRestoreProgress = value; RaisePropertyChangedAuto(); } + } + + private long _backupSize; + public long BackupSize + { + get { return _backupSize; } + set { _backupSize = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand BrowseForBackupCommand { get; set; } + + public RelayCommand RestoreCommand { get; set; } + + public RestoreViewVM() + { + RestoreSettings = new RestoreSettings(); + RestoreCommand = new RelayCommand(StartRestore, () => BackupFileName != null); + BrowseForBackupCommand = new RelayCommand(BrowseForBackup); + } + + private async void StartRestore() + { + await NavigationManager.NavigateTo(nameof(RestoreProgressView), false); + + try + { + IsFree = false; + NavigationManager.IsBackEnabled = false; + var result = await BackupManager.Restore(_backupFileLocation, RestoreSettings); + await NavigationManager.NavigateWithObject(result, false); + } + catch (Exception ex) + { + LogManager.Log(ex, "The restore operation failed."); + + await NavigationManager.NavigateWithObject(new RestoreErrorNavigationObject() + { + Error = ex.FlattenMessage(), + }, false); + + NavigationManager.IsBackEnabled = true; + } + finally + { + IsFree = true; + } + } + + private async void BrowseForBackup() + { + _isBrowsing = true; + + var result = await NavigationManager. + NavigateForResult( + new Storage.Models.StorageNavigationRequest() + { + Intent = Storage.Models.StorageNavigationIntent.LoadFile, + Filter = ExplorerFileDefinition.Backup.Extension, + Title = "Select Backup File", + }); + + _isBrowsing = false; + + if (result != null) + { + _backupFileLocation = result.Path; + + try + { + BackupFile = await BackupManager.ExtractBackupConfiguration(_backupFileLocation); + BackupFileName = Path.GetFileName(result.Path); + BackupSize = new System.IO.FileInfo(_backupFileLocation).Length; + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error extracting backup configuration from file '{_backupFileLocation}'."); + await NotificationProvider.ShowError($"Error occurred while trying to extract the backup file information\n{ex.FlattenMessage()}"); + } + } + } + + public override Task OnNavigateBackRequest() + { + return Task.FromResult(IsFree); + } + + public override void OnNavigatedFrom() + { + base.OnNavigatedFrom(); + + if (!_isBrowsing) + { + BackupFileName = null; + BackupFile = null; + _backupFileLocation = null; + } + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + BackupManager.Progress += BackupManager_Progress; + } + + private void BackupManager_Progress(object sender, BackupRestoreProgressEventArgs e) + { + CurrentRestoreProgress = e; + } + + public override void OnApplicationStarted() + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/WelcomeViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/WelcomeViewVM.cs new file mode 100644 index 000000000..4fbac321e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/WelcomeViewVM.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.PPC.BackupRestore.Views; +using Tango.PPC.Common; + +namespace Tango.PPC.BackupRestore.ViewModels +{ + public class WelcomeViewVM : PPCViewModel + { + public RelayCommand NavigateToBackupCommand { get; set; } + + public RelayCommand NavigateToRestoreCommand { get; set; } + + public WelcomeViewVM() + { + NavigateToBackupCommand = new RelayCommand(() => + { + NavigationManager.NavigateTo(nameof(BackupView)); + }); + + NavigateToRestoreCommand = new RelayCommand(() => + { + NavigationManager.NavigateTo(nameof(RestoreView)); + }); + } + + public override void OnApplicationStarted() + { + + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + NotificationProvider.NotificationsVisible = false; + } + + public override Task OnNavigateBackRequest() + { + NotificationProvider.NotificationsVisible = true; + return base.OnNavigateBackRequest(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml new file mode 100644 index 000000000..470c16256 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml @@ -0,0 +1,37 @@ + + + + + + + + Backup completed + + + The backup operation was completed successfully. + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml.cs new file mode 100644 index 000000000..2a9779ed1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class BackupCompletedView : UserControl + { + public BackupCompletedView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml new file mode 100644 index 000000000..b54694a50 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml @@ -0,0 +1,39 @@ + + + + + + + + Backup failed + + + The backup operation has failed due to the following reason. + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml.cs new file mode 100644 index 000000000..cf050140d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class BackupErrorView : UserControl + { + public BackupErrorView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml new file mode 100644 index 000000000..7785c1c0f --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml @@ -0,0 +1,38 @@ + + + + + + + + Backing up your system + + + This process may take several minutes, please wait. + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml.cs new file mode 100644 index 000000000..dd650f750 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class BackupProgressView : UserControl + { + public BackupProgressView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml new file mode 100644 index 000000000..2a72f9788 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + Backup your system + + + Please specify the location and settings of your backup and press 'START'. + + + + + + Backup Mode + + + + + + + + + + + + Jobs + (create a backup of all your jobs) + + + + + + + Full Backup + (backup the entire state of the system) + + + + + + + + + + + Location + + + + + Please select the destination of your backup file + + SELECT + + + + + + + + + + Name + + + + Please enter the name of your backup + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml.cs new file mode 100644 index 000000000..adc951f87 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class BackupView : UserControl + { + public BackupView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml new file mode 100644 index 000000000..0caabd0e1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml.cs new file mode 100644 index 000000000..e21bec0cb --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.Core.DI; +using static Tango.PPC.BackupRestore.ViewModels.MainViewVM; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for MainView.xaml + /// + public partial class MainView : UserControl + { + public MainView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml new file mode 100644 index 000000000..6352797e7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml @@ -0,0 +1,37 @@ + + + + + + + + System restored + + + Your system was successfully restored. The system needs to restart in order apply the changes. + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml.cs new file mode 100644 index 000000000..5c3fbeaec --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class RestoreCompletedView : UserControl + { + public RestoreCompletedView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml new file mode 100644 index 000000000..2d09326ea --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml @@ -0,0 +1,39 @@ + + + + + + + + Restore failed + + + The restore operation has failed due to the following reason. + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml.cs new file mode 100644 index 000000000..c0268d020 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class RestoreErrorView : UserControl + { + public RestoreErrorView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml new file mode 100644 index 000000000..65c1678c5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml @@ -0,0 +1,38 @@ + + + + + + + + Restoring your system + + + This process may take several minutes, please wait. + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml.cs new file mode 100644 index 000000000..3b8b19fa9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for BackupView.xaml + /// + public partial class RestoreProgressView : UserControl + { + public RestoreProgressView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml new file mode 100644 index 000000000..fca7a668e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml @@ -0,0 +1,160 @@ + + + + + + + + + + + + Restore your system + + + Please specify the location of your backup file and other options. Press 'START' when you are ready. + + + + + + Location + + + + + Please insert a storage device and select your backup file + + SELECT + + + + + + + + + + Information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Options + + + + + + + + + + + + Overwrite existing jobs + (existing jobs will change if there are conflicts) + + + + + + + Do not remove existing jobs + (existing jobs will not be deleted) + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml.cs new file mode 100644 index 000000000..4df9146bb --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for RestoreView.xaml + /// + public partial class RestoreView : UserControl + { + public RestoreView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml new file mode 100644 index 000000000..cf64b5bea --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml @@ -0,0 +1,72 @@ + + + + + + + + + + Welcome to the backup/restore wizard + + + This wizard allows you to create a complete backup of your current machine state including software, firmware, data and user settings. + + + + For creating a complete backup of your system please press 'Backup'. + + In case you want to restore your system to a previous state, please press 'Restore'. + + + + + + + + + Backup + + Create a complete backup of your system state and save it to a storage device. + + + + + + + + + + Restore + + Restore your system from a previously saved backup file. + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml.cs new file mode 100644 index 000000000..a7c347016 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.BackupRestore.Views +{ + /// + /// Interaction logic for WelcomeView.xaml + /// + public partial class WelcomeView : UserControl + { + public WelcomeView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/app.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/app.config new file mode 100644 index 000000000..1e22e6a88 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/app.config @@ -0,0 +1,61 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/packages.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/packages.config new file mode 100644 index 000000000..80367fdd2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/App.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/App.xaml new file mode 100644 index 000000000..576597134 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/App.xaml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Attributes/BoundObjectAttribute.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Attributes/BoundObjectAttribute.cs new file mode 100644 index 000000000..b4e822f1e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Attributes/BoundObjectAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Browser.Attributes +{ + public class BoundObjectAttribute : Attribute + { + public String Name { get; set; } + public String ScriptFile { get; set; } + + public BoundObjectAttribute(String name,String scriptFile) + { + Name = name; + ScriptFile = scriptFile; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BoundsObjects/KeyboardHandler.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BoundsObjects/KeyboardHandler.cs new file mode 100644 index 000000000..3c608a518 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BoundsObjects/KeyboardHandler.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.PPC.Browser.Attributes; +using Tango.PPC.Browser.Views; +using Tango.PPC.Common.Helpers; +using Tango.Touch.Keyboard; + +namespace Tango.PPC.Browser.BoundsObjects +{ + [BoundObject("keyboard", "keyboard.js")] + public class KeyboardHandler + { + private DateTime _lastTime; + + public KeyboardHandler() + { + _lastTime = DateTime.Now; + } + + public void openKeyboard(String inputType) + { + if (DateTime.Now > _lastTime.AddMilliseconds(1000)) + { + _lastTime = DateTime.Now; + + Application.Current.Dispatcher.BeginInvoke(new Action(async () => + { + switch (inputType) + { + case "search": + KeyboardHelper.OpenKeyboard(KeyboardActionKeyMode.Go); + break; + default: + KeyboardHelper.OpenKeyboard(KeyboardActionKeyMode.Next); + break; + } + + + await Task.Delay(50); + BrowserView.Instance.btnGo.Focus(); + await Task.Delay(50); + BrowserView.Instance.Browser.Focus(); + Debug.WriteLine("Focus"); + })); + } + } + + public void closeKeyboard() + { + if (DateTime.Now > _lastTime.AddMilliseconds(1000)) + { + _lastTime = DateTime.Now; + + Application.Current.Dispatcher.BeginInvoke(new Action(() => + { + KeyboardHelper.CloseKeyboard(); + })); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BrowserModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BrowserModule.cs new file mode 100644 index 000000000..dc7b294d5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BrowserModule.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.BL.Enumerations; +using Tango.PPC.Common; +using Tango.PPC.Browser.Views; +using Tango.SharedUI.Helpers; +using Tango.Core.DI; +using Tango.PPC.Common.Application; +using System.IO; +using Tango.Core.Helpers; + +namespace Tango.PPC.Browser +{ + /// + /// Represents a PPC . + /// + /// + [PPCModule(10)] + public class BrowserModule : PPCModuleBase + { + /// + /// Initializes a new instance of the class. + /// + public BrowserModule() + { + IsVisibleInMenu = false; + } + + /// + /// Gets the module name. + /// + public override string Name + { + get + { + return "Browser"; + } + } + + /// + /// Gets the module description. + /// + public override string Description + { + get + { + return "Browser module"; + } + } + + /// + /// Gets the module cover image. + /// + public override BitmapSource Image + { + get + { + return ResourceHelper.GetImageFromResources("Images/browser.png"); + } + } + + /// + /// Gets the module entry point view type. + /// + public override Type MainViewType + { + get + { + return IsCefAvailable() ? typeof(BrowserView) : typeof(ErrorView); + } + } + + /// + /// Gets the permission required to see and load this module. + /// + public override Permissions Permission + { + get + { + return Permissions.RunPPC; + } + } + + private bool IsCefAvailable() + { + return File.Exists(Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "x86", "CefSharp.Core.dll")); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public override void Dispose() + { + //Dispose module here... + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zip b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zip new file mode 100644 index 000000000..8c68cedb7 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zip differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Helpers/BoundObjectsHelper.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Helpers/BoundObjectsHelper.cs new file mode 100644 index 000000000..fe68ee848 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Helpers/BoundObjectsHelper.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reflection; +using Tango.PPC.Browser.Attributes; +using CefSharp; +using CefSharp.Wpf; +using Tango.Core.Helpers; +using System.Windows.Threading; + +namespace Tango.PPC.Browser.Helpers +{ + public static class BoundObjectsHelper + { + private static DispatcherTimer _timer; + private static Dispatcher _dispatcher; + private static ChromiumWebBrowser _browser; + + private static List _scripts = new List(); + + public static void RegisterAllBoundObjects(ChromiumWebBrowser browser, Dispatcher dispatcher) + { + _dispatcher = dispatcher; + _browser = browser; + + _timer = new DispatcherTimer(DispatcherPriority.Background, dispatcher); + _timer.Tick += _timer_Tick; + _timer.Interval = TimeSpan.FromSeconds(2); + _timer.Stop(); + + foreach (var type in typeof(BoundObjectsHelper).Assembly.GetTypes().Where(x => x.GetCustomAttribute() != null)) + { + var att = type.GetCustomAttribute(); + + var script = EmbeddedResourceHelper.GetEmbeddedResourceText($"Tango.PPC.Browser.Scripts.{att.ScriptFile}"); + _scripts.Add(script); + + browser.JavascriptObjectRepository.Register(att.Name, Activator.CreateInstance(type), true); + + browser.FrameLoadEnd += Browser_FrameLoadEnd; + } + } + + private static void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e) + { + _timer.Stop(); + _timer.Start(); + } + + private static void _timer_Tick(object sender, EventArgs e) + { + try + { + _timer.Stop(); + + _dispatcher.BeginInvoke(new Action(() => + { + foreach (var script in _scripts) + { + _browser.GetMainFrame().ExecuteJavaScriptAsync(script); + } + })); + } + catch + { + _timer.Start(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.png new file mode 100644 index 000000000..ebb975b6f Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Navigation/BrowserNavigationRequest.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Navigation/BrowserNavigationRequest.cs new file mode 100644 index 000000000..a8becf251 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Navigation/BrowserNavigationRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Browser.Navigation +{ + public class BrowserNavigationRequest + { + public String Address { get; set; } + public bool DisplayAddressBar { get; set; } + + public BrowserNavigationRequest() + { + DisplayAddressBar = true; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..70edee491 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango Web Browser Module")] +[assembly: AssemblyVersion("2.0.1.1407")] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.Designer.cs new file mode 100644 index 000000000..01c0a8851 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Browser.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.PPC.Browser.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.resx b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.Designer.cs new file mode 100644 index 000000000..f464e258d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Browser.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.settings b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/RequestHandlers/ChromiumRequestHandler.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/RequestHandlers/ChromiumRequestHandler.cs new file mode 100644 index 000000000..fc6cb119c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/RequestHandlers/ChromiumRequestHandler.cs @@ -0,0 +1,114 @@ +using CefSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Browser.RequestHandlers +{ + public class ChromiumRequestHandler : IRequestHandler + { + public event EventHandler AddressChanged; + + public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) + { + return false; + } + + public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect) + { + // You can check the Request object for the URL Here + return false; + } + + public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback) + { + // You can also check the URL here + callback.Dispose(); + return CefReturnValue.Continue; + } + + public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback) + { + callback.Dispose(); + return false; + } + + public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture) + { + return false; + } + + public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath) + { + } + + public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url) + { + return false; + } + + public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback) + { + callback.Dispose(); + return false; + } + + public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status) + { + } + + public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser) + { + } + + public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength) + { + // You can also check the request URL here + } + + public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, ref string newUrl) + { + } + + public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response) + { + return false; + } + + + public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response) + { + return null; + } + + + public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl) + { + } + + public bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, System.Security.Cryptography.X509Certificates.X509Certificate2Collection certificates, ISelectClientCertificateCallback callback) + { + callback.Dispose(); + return false; + } + + public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect) + { + AddressChanged?.Invoke(this, request.Url); + return false; + } + + public IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling) + { + return null; + } + + public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) + { + callback.Dispose(); + return false; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Scripts/keyboard.js b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Scripts/keyboard.js new file mode 100644 index 000000000..21771eb8e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Scripts/keyboard.js @@ -0,0 +1,21 @@ +(async function () { + await CefSharp.BindObjectAsync("keyboard", "bound"); + + var inputs = document.getElementsByTagName('input'); + var i = 0; + + do { + + var type = inputs[i].type; + + if (type == 'text' || type == 'email' || type == 'password' || type == 'search' || type == 'date' || type == 'url' || type == 'time' || type == 'tel' || type == 'number') { + inputs[i].onfocus = function () { + keyboard.openKeyboard(type); + } + inputs[i].onblur = function () { + keyboard.closeKeyboard(); + } + } + } + while (inputs[++i]) +})(); \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Tango.PPC.Browser.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Tango.PPC.Browser.csproj new file mode 100644 index 000000000..b742d4d75 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Tango.PPC.Browser.csproj @@ -0,0 +1,199 @@ + + + + + + + + + true + Debug + AnyCPU + {F02EAA84-AD59-465B-99A2-4422C13BFB72} + library + Tango.PPC.Browser + Tango.PPC.Browser + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + + + true + full + false + ..\..\..\Build\PPC\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll + True + + + ..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll + + + ..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll + + + + + + ..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + GlobalVersionInfo.cs + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + BrowserView.xaml + + + ErrorView.xaml + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {b112d89a-a106-41ae-a0c1-4abc84c477f5} + Tango.DragAndDrop + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + + + {e4927038-348d-4295-aaf4-861c58cb3943} + Tango.PMR + + + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} + Tango.Settings + + + {8491d07b-c1f6-4b62-a412-41b9fd2d6538} + Tango.SharedUI + + + {fd86424c-6e84-491b-8df9-3d0f5c236a2a} + Tango.Touch + + + {74e700b0-1156-4126-be40-ee450d3c3026} + Tango.Transport + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewContracts/IBrowserView.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewContracts/IBrowserView.cs new file mode 100644 index 000000000..8369209a3 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewContracts/IBrowserView.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; +using Tango.SharedUI; + +namespace Tango.PPC.Browser.ViewContracts +{ + public interface IBrowserView : IPPCView + { + event EventHandler AddressChanged; + bool CanGoBack(); + void NavigateTo(String address); + void GoBack(); + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModelLocator.cs new file mode 100644 index 000000000..054310e99 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModelLocator.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.PPC.Browser.ViewModels; + +namespace Tango.PPC.Browser +{ + public static class ViewModelLocator + { + /// + /// Initializes a new instance of the ViewModelLocator class. + /// + static ViewModelLocator() + { + TangoIOC.Default.Register(); + } + + /// + /// Gets the main view VM. + /// + public static BrowserViewVM BrowserViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModels/BrowserViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModels/BrowserViewVM.cs new file mode 100644 index 000000000..0f5a49639 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModels/BrowserViewVM.cs @@ -0,0 +1,134 @@ +using CefSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.PPC.Browser.Navigation; +using Tango.PPC.Browser.ViewContracts; +using Tango.PPC.Common; +using Tango.PPC.Common.Navigation; +using Tango.Touch.Keyboard; + +namespace Tango.PPC.Browser.ViewModels +{ + /// + /// Represents the main view VM and entry point for . + /// + /// + public class BrowserViewVM : PPCViewModel, INavigationObjectReceiver + { + private bool _isFromObject; + + private String _address; + public String Address + { + get { return _address; } + set { _address = value; RaisePropertyChangedAuto(); } + } + + private bool _displayAddressBar; + public bool DisplayAddressBar + { + get { return _displayAddressBar; } + set { _displayAddressBar = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand GoCommand { get; set; } + + public BrowserViewVM() + { + DisplayAddressBar = true; + + GoCommand = new RelayCommand(Go); + } + + public override void OnViewAttached() + { + base.OnViewAttached(); + View.AddressChanged += View_AddressChanged; + } + + private void View_AddressChanged(object sender, string address) + { + Address = address; + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + KeyboardView.Default.OutputMode = KeyboardOutputMode.Windows; + + if (!_isFromObject) + { + DisplayAddressBar = true; + } + + _isFromObject = false; + } + + public override void OnNavigatedFrom() + { + base.OnNavigatedFrom(); + KeyboardView.Default.OutputMode = KeyboardOutputMode.Wpf; + } + + public override Task OnNavigateBackRequest() + { + if (View != null && View.CanGoBack()) + { + View.GoBack(); + return Task.FromResult(false); + } + else + { + return Task.FromResult(true); + } + } + + /// + /// Called when the application has been started + /// + public override void OnApplicationStarted() + { + + } + + public override void OnApplicationShuttingDown() + { + base.OnApplicationShuttingDown(); + + try + { + Cef.Shutdown(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error shutting down cef."); + } + } + + private void Go() + { + if (View != null) + { + View.NavigateTo(Address); + } + } + + public void OnNavigatedToWithObject(BrowserNavigationRequest obj) + { + _isFromObject = true; + + DisplayAddressBar = obj.DisplayAddressBar; + + if (obj.Address != null) + { + Address = obj.Address; + Go(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml new file mode 100644 index 000000000..ce28d660e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page Not Found + + The page at '' + could not be reached. + + Please check your internet connection. + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml.cs new file mode 100644 index 000000000..e7fe1ca27 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using CefSharp; +using CefSharp.Wpf; +using Tango.Core.DI; +using Tango.Core.Helpers; +using Tango.Logging; +using Tango.PPC.Browser.BoundsObjects; +using Tango.PPC.Browser.ViewContracts; +using Tango.PPC.Common.Helpers; +using Tango.Touch.Keyboard; + +namespace Tango.PPC.Browser.Views +{ + /// + /// Interaction logic for MainView.xaml + /// + public partial class BrowserView : UserControl, IBrowserView + { + public event EventHandler AddressChanged; + + public static BrowserView Instance { get; set; } + + public BrowserView() + { + try + { + var settings = new CefSettings(); + settings.BrowserSubprocessPath = @"x86\CefSharp.BrowserSubprocess.exe"; + settings.UserAgent = "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"; + + Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null); + } + catch (Exception ex) + { + LogManager.Default.Log(ex, "Error loading cef."); + } + + InitializeComponent(); + + Instance = this; + + TangoIOC.Default.Register(this); + + Helpers.BoundObjectsHelper.RegisterAllBoundObjects(Browser, Dispatcher); + + KeyboardView.Default.KeyboardOpened += Default_KeyboardOpened; + KeyboardView.Default.KeyboardClosed += Default_KeyboardClosed; + + var handler = new RequestHandlers.ChromiumRequestHandler(); + handler.AddressChanged += Handler_AddressChanged; + Browser.RequestHandler = handler; + Browser.LoadError += Browser_LoadError; + Browser.LoadingStateChanged += Browser_LoadingStateChanged; + } + + private void Browser_LoadError(object sender, LoadErrorEventArgs e) + { + //if (e.ErrorCode == CefErrorCode.ConnectionTimedOut || e.ErrorCode == CefErrorCode.NameNotResolved) + //{ + InvokeUI(() => + { + runError.Text = e.ErrorText; + gridError.Visibility = Visibility.Visible; + }); + //} + } + + private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) + { + if (!e.IsLoading) + { + InvokeUI(() => + { + KeyboardHelper.CloseKeyboard(); + }); + } + else + { + InvokeUI(() => + { + gridError.Visibility = Visibility.Hidden; + }); + } + } + + private void Handler_AddressChanged(object sender, string address) + { + InvokeUI(() => + { + AddressChanged?.Invoke(this, address); + }); + } + + private void Default_KeyboardClosed(object sender, EventArgs e) + { + Browser.VerticalAlignment = VerticalAlignment.Stretch; + Browser.Height = double.NaN; + } + + private void Default_KeyboardOpened(object sender, EventArgs e) + { + Browser.VerticalAlignment = VerticalAlignment.Top; + Browser.Height = 780; + } + + public bool CanGoBack() + { + return Browser.CanGoBack; + } + + public void NavigateTo(string address) + { + if (Browser.Address != address) + { + String uri; + + if (ValidHttpURL(address, out uri)) + { + Browser.Address = uri; + } + else + { + Browser.Address = $"google.com/search?q={address.Replace(" ", "+")}"; + } + } + else + { + Browser.Reload(); + } + } + + public static bool ValidHttpURL(string s, out string result) + { + if (Uri.IsWellFormedUriString(s, UriKind.Absolute)) + { + result = s; + return true; + } + else if (s.StartsWith("www.")) + { + result = "http://" + s; + return true; + } + + result = s; + return false; + } + + public void GoBack() + { + if (Browser.CanGoBack) + { + Browser.Back(); + } + } + + private async void TxtAddress_GotFocus(object sender, RoutedEventArgs e) + { + KeyboardHelper.OpenKeyboard(KeyboardActionKeyMode.Go); + await Task.Delay(100); + txtAddress.SelectAll(); + } + + private void TxtAddress_LostFocus(object sender, RoutedEventArgs e) + { + KeyboardHelper.CloseKeyboard(); + } + + private void TxtAddress_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Return) + { + KeyboardHelper.CloseKeyboard(); + NavigateTo(txtAddress.Text); + } + } + + private void TxtAddress_MouseUp(object sender, MouseButtonEventArgs e) + { + KeyboardHelper.OpenKeyboard(KeyboardActionKeyMode.Go); + } + + private async void TxtAddress_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) + { + KeyboardHelper.OpenKeyboard(KeyboardActionKeyMode.Go); + await Task.Delay(100); + txtAddress.SelectAll(); + } + + private void InvokeUI(Action action) + { + Dispatcher.BeginInvoke(action); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml new file mode 100644 index 000000000..25e3381ba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml @@ -0,0 +1,23 @@ + + + + + + Browser Not Loaded + + The browser module was not loaded properly or has caused some error. + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml.cs new file mode 100644 index 000000000..0d59b80f0 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.PPC.Browser.ViewContracts; + +namespace Tango.PPC.Browser.Views +{ + /// + /// Interaction logic for ErrorView.xaml + /// + public partial class ErrorView : UserControl + { + public ErrorView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/app.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/app.config new file mode 100644 index 000000000..cf33970a7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/app.config @@ -0,0 +1,90 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/packages.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/packages.config new file mode 100644 index 000000000..f7fe1b9a2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/BugReportingModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/BugReportingModule.cs index e65b44698..659ffe732 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/BugReportingModule.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/BugReportingModule.cs @@ -17,7 +17,7 @@ namespace Tango.PPC.BugReporting /// Represents a PPC . /// /// - [PPCModule(5)] + [PPCModule(6)] public class BugReportingModule : PPCModuleBase { /// diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/TFS/TeamFoundationServicePPCClient.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/TFS/TeamFoundationServicePPCClient.cs index 26d6425bf..b84d11c37 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/TFS/TeamFoundationServicePPCClient.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/TFS/TeamFoundationServicePPCClient.cs @@ -13,6 +13,8 @@ using Tango.PPC.Common.Connection; using Tango.TFS; using Tango.Core.ExtensionMethods; using Tango.Core.Helpers; +using Tango.Settings; +using Tango.PPC.Common; namespace Tango.PPC.BugReporting.TFS { @@ -53,6 +55,21 @@ namespace Tango.PPC.BugReporting.TFS } } + private string[] GetLogFiles(FileLogger logger) + { + string[] fileEntries = new string[1]; + fileEntries[0] = logger.LogFile; + string fileName = Path.GetFileNameWithoutExtension(logger.LogFile); + int indexPos = fileName.IndexOf(FileLogger.FILE_SET_EXTENSION); + if (indexPos > 0) + { + string extension = Path.GetExtension(logger.LogFile); + fileName = fileName.Substring(0, indexPos); + fileEntries = Directory.GetFiles(logger.Folder, $"{fileName}*{extension}").Where(x => Path.GetFileName(x).StartsWith(logger.Tag)).OrderBy(x => x.Length).ThenBy(x => x).ToArray(); + } + return fileEntries; + } + public async Task SubmitBug(String title, String steps, TeamMember createdBy, TeamMember assignedTo, Severity severity) { LogManager.Log("Submitting bug report..."); @@ -80,6 +97,7 @@ namespace Tango.PPC.BugReporting.TFS item.Severity = severity; item.State = State.New; item.Type = WorkItemType.Bug; + item.Environment = SettingsManager.Default.GetOrCreate().DeploymentSlot.ToDescription(); FileLogger appFileLogger = LogManager.Default.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; FileLogger embeddedFileLogger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; @@ -87,31 +105,54 @@ namespace Tango.PPC.BugReporting.TFS if (appFileLogger != null) { LogManager.Log($"Attaching application log file ${appFileLogger.LogFile}"); - - var appLogFile = tempFolder.CreateImaginaryFile(); - File.Copy(appFileLogger.LogFile, appLogFile.Path); - - item.Attachments.Add(new Attachment() + string[] logFiles = GetLogFiles(appFileLogger); + foreach (string file in logFiles) { - Description = "Application Log File", - FilePath = appLogFile.Path, - Name = Path.GetFileName(appFileLogger.LogFile), - }); + var appLogFile = tempFolder.CreateImaginaryFile(); + File.Copy(file, appLogFile.Path); + item.Attachments.Add(new Attachment() + { + Description = "Application Log File", + FilePath = appLogFile.Path, + Name = Path.GetFileName(file), + }); + } } if (embeddedFileLogger != null && File.Exists(embeddedFileLogger.LogFile)) { LogManager.Log($"Attaching embedded log file ${embeddedFileLogger.LogFile}"); - var embeddedLogFile = tempFolder.CreateImaginaryFile(); - File.Copy(embeddedFileLogger.LogFile, embeddedLogFile.Path); + string[] logFiles = GetLogFiles(embeddedFileLogger); + foreach (string file in logFiles) + { + var embeddedLogFile = tempFolder.CreateImaginaryFile(); + File.Copy(file, embeddedLogFile.Path); + item.Attachments.Add(new Attachment() + { + Description = "Embedded Log File", + FilePath = embeddedLogFile.Path, + Name = Path.GetFileName(file), + }); + } + } - item.Attachments.Add(new Attachment() + //Add session log file.. + if (MachineOperator.EnableSessionLogFile) + { + var file = MachineOperator.SessionLogger.LogFile; + + if (file != null && File.Exists(file)) { - Description = "Embedded Log File", - FilePath = embeddedLogFile.Path, - Name = Path.GetFileName(embeddedFileLogger.LogFile), - }); + var sessionLogFile = tempFolder.CreateImaginaryFile(); + File.Copy(file, sessionLogFile.Path); + item.Attachments.Add(new Attachment() + { + Description = "Session Log File", + FilePath = sessionLogFile.Path, + Name = Path.GetFileName(file), + }); + } } SystemInformationModel sysModel = new SystemInformationModel(); diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj new file mode 100644 index 000000000..3b897aa71 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj @@ -0,0 +1,235 @@ + + + + + Debug + AnyCPU + {8146FA0A-0725-4A1A-82E6-696C58F33A2B} + library + Tango.PPC.BugReporting + Tango.PPC.BugReporting + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + true + full + false + ..\..\..\Build\PPC\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\ + TRACE + prompt + 4 + + + + + + + + GlobalVersionInfo.cs + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + MainView.xaml + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {caedae94-11ed-473c-888a-268a6d38cd20} + Tango.CodeGeneration + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {b112d89a-a106-41ae-a0c1-4abc84c477f5} + Tango.DragAndDrop + + + {4206ac58-3b57-4699-8835-90bf6db01a61} + Tango.Integration + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + + + {e4927038-348d-4295-aaf4-861c58cb3943} + Tango.PMR + + + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} + Tango.Settings + + + {8491d07b-c1f6-4b62-a412-41b9fd2d6538} + Tango.SharedUI + + + {998f8471-dc1b-41b6-9d96-354e1b4e7a32} + Tango.TFS + + + {fd86424c-6e84-491b-8df9-3d0f5c236a2a} + Tango.Touch + + + {74e700b0-1156-4126-be40-ee450d3c3026} + Tango.Transport + + + {5001990f-977b-48ff-b217-0236a5022ad8} + Tango.Web + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/ViewModelLocator.cs index 1f71ca2c1..24b222370 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/ViewModelLocator.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/ViewModelLocator.cs @@ -16,7 +16,7 @@ namespace Tango.PPC.BugReporting /// static ViewModelLocator() { - TangoIOC.Default.Register(new TeamFoundationServicePPCClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); + TangoIOC.Default.Register(new TeamFoundationServicePPCClient("https://twinetfs.visualstudio.com", String.Empty, "pyulwgs7m3v7pizz3oxusypdkdfw43txggo5mjwu2ouyv2qwprhq")); TangoIOC.Default.Register(); } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Converters/MachineEventToViewConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Converters/MachineEventToViewConverter.cs index 47c9e0ddf..56d7149d3 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Converters/MachineEventToViewConverter.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Converters/MachineEventToViewConverter.cs @@ -18,10 +18,17 @@ namespace Tango.PPC.Events.Converters static MachineEventToViewConverter() { + //Jobs _eventViews.Add(EventTypes.JOB_STARTED, typeof(JobEventView)); _eventViews.Add(EventTypes.JOB_ABORTED, typeof(JobEventView)); _eventViews.Add(EventTypes.JOB_COMPLETED, typeof(JobEventView)); _eventViews.Add(EventTypes.JOB_FAILED, typeof(JobEventView)); + + //Thread Break + _eventViews.Add(EventTypes.THREAD_BREAK, typeof(ThreadBreakView)); + _eventViews.Add(EventTypes.THREAD_TENSION_CONTROL_FAILURE_FEEDER_DANCER, typeof(ThreadBreakView)); + _eventViews.Add(EventTypes.THREAD_TENSION_CONTROL_FAILURE_PULLER_DANCER, typeof(ThreadBreakView)); + _eventViews.Add(EventTypes.THREAD_TENSION_CONTROL_FAILURE_WINDER_DANCER, typeof(ThreadBreakView)); } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml new file mode 100644 index 000000000..71c4ced07 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + LOAD THREAD BREAK WIZARD + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml.cs new file mode 100644 index 000000000..7e8337514 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.Core.DI; +using Tango.PPC.Common.ThreadLoading; + +namespace Tango.PPC.Events.EventsViews +{ + /// + /// Interaction logic for ThreadBreakView.xaml + /// + public partial class ThreadBreakView : UserControl + { + public ThreadBreakView() + { + InitializeComponent(); + + btnLoadThreadBreakWizard.Click += BtnLoadThreadBreakWizard_Click; + } + + private void BtnLoadThreadBreakWizard_Click(object sender, RoutedEventArgs e) + { + try + { + var threadLoadingService = TangoIOC.Default.GetInstance(); + + if (threadLoadingService != null) + { + threadLoadingService.StartThreadBreakWizard(); + } + } + catch (Exception ex) + { + Logging.LogManager.Default.Log(ex, "Error loading the thread break wizard."); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Resources/Styles.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Resources/Styles.xaml index 53102d8ec..eaf621571 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Resources/Styles.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Resources/Styles.xaml @@ -18,11 +18,11 @@ - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppBarItems/JobProgressAppBarItemView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppBarItems/JobProgressAppBarItemView.xaml index cdc28335d..16c6a42be 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppBarItems/JobProgressAppBarItemView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppBarItems/JobProgressAppBarItemView.xaml @@ -5,11 +5,12 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" xmlns:local="clr-namespace:Tango.PPC.Jobs.AppBarItems" - mc:Ignorable="d" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:JobProgressAppBarItem, IsDesignTimeCreatable=False}"> + mc:Ignorable="d" + d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:JobProgressAppBarItem, IsDesignTimeCreatable=False}"> - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppButtons/StartPrintingButton.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppButtons/StartPrintingButton.cs index 001888c92..4d6050639 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppButtons/StartPrintingButton.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppButtons/StartPrintingButton.cs @@ -15,12 +15,12 @@ namespace Tango.PPC.Jobs.AppButtons { op.StatusChanged += Op_StatusChanged; - Op_StatusChanged(this, op.Status); + Op_StatusChanged(op, op.Status); } private void Op_StatusChanged(object sender, MachineStatuses status) { - IsEnabled = status == MachineStatuses.ReadyToDye; + IsEnabled = (sender as IMachineOperator).CanPrint; } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobOutlineControl.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobOutlineControl.cs new file mode 100644 index 000000000..78f8c90a1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobOutlineControl.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Shapes; +using Tango.PMR.Printing; +using Tango.Touch.Controls; + +namespace Tango.PPC.Jobs +{ + public class JobOutlineControl : Control + { + #region Members + + private Size _sizeControl = new Size(0, 0); + ScrollViewer _parentScrollViewer = null; + public struct LevelOffset + { + public const double level_0 = 0.0; + public const double level_1 = 10.0; + public const double level_2 = 20.0; + public const double level_3 = 37.0; + public const double level_4 = 50.0; + public const double level_5 = 60.0; + public const double level_6 = 77.0; + public const double level_7 = 90.0; + public const double level_8 = 100.0; + } + private double _verticalOffset = 0; + private double _viewportHeight = 0; + private const double HEADER_FONT_HEIGHT = 35; + private const double TITLE_FONT_HEIGHT = 22; + private const double SUB_TITLE_FONT_HEIGHT = 19; + private const double NORMAL_FONT_HEIGHT = 17; + private const double WIDTH = 330; + + #endregion members + + public JobOutlineControl() : base() + { + Unloaded += JobOutlineControl_Unloaded; + DataContextChanged += JobOutlineControl_DataContextChanged; + Width = WIDTH; + } + + private void JobOutlineControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) + { + if (DataContext == null) + { + return; + } + + if (_parentScrollViewer != null) + { + _parentScrollViewer.ScrollToTop(); + } + + InvalidateVisual(); + } + + #region events + private void JobOutlineControl_Unloaded(object sender, RoutedEventArgs e) + { + if (_parentScrollViewer != null) + { + _parentScrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged; + } + } + + private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) + { + if (e.VerticalChange == 0.0) + return; + + _verticalOffset = _parentScrollViewer.VerticalOffset; + _viewportHeight = _parentScrollViewer.ViewportHeight; + InvalidateVisual(); + } + #endregion events + + #region render + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); + + if (!(DataContext is JobTicket job)) return; + if (_parentScrollViewer == null) + { + _parentScrollViewer = this.FindAncestor(); + _parentScrollViewer.ScrollChanged += ScrollViewer_ScrollChanged; + } + else if (_viewportHeight == 0) + { + _viewportHeight = _parentScrollViewer.ActualHeight; + } + _sizeControl = new Size(); + _sizeControl.Height += 10; + DrawHeaderText(drawingContext, "JOB OUTLINE", 30, LevelOffset.level_0); + _sizeControl.Height += HEADER_FONT_HEIGHT; + + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "BASIC", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 5.0; + var basicProps = GetNameValueList(job); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_1, TouchIconKind.Pencil); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + //JobTicket.Spool + if (job.Spool != null) + { + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "SPOOL", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 5.0; + basicProps = GetNameValueList(job.Spool); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_1, TouchIconKind.Pencil); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } + //JobTicket.ProcessParameters + if (job.ProcessParameters != null) + { + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "PROCESS PARAMETERS", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 5.0; + basicProps = GetNameValueList(job.ProcessParameters); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_1, TouchIconKind.Settings); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } + //JobTicket.ThreadParameters + if (job.ThreadParameters != null) + { + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "THREAD PARAMETERS", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 5.0; + basicProps = GetNameValueList(job.ThreadParameters); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_1, TouchIconKind.Settings); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } + //JobTicket.HeadCleaningParameters + if (job.HeadCleaningParameters != null) + { + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "HEAD CLEANING PARAMETERS", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 5.0; + basicProps = GetNameValueList(job.HeadCleaningParameters); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_1, TouchIconKind.Settings); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } + //JobTicket.Segments + if (job.Segments != null) + { + _sizeControl.Height += 20; + DrawHeaderText(drawingContext, "SEGMENTS", 17, LevelOffset.level_0); + _sizeControl.Height += TITLE_FONT_HEIGHT; + _sizeControl.Height += 10.0; + int index = 0; + foreach (JobSegment seg in job.Segments) + { + DrawHeaderText(drawingContext, string.Format("#{0} SEGMENT", ++index), 14, LevelOffset.level_1); + _sizeControl.Height += SUB_TITLE_FONT_HEIGHT; + basicProps = GetNameValueList(seg); + foreach (var prop in basicProps) + { + DrawNameValueText(drawingContext, prop, LevelOffset.level_2, TouchIconKind.Pencil); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + //BrushStops + DrawHeaderText(drawingContext, "BRUSH STOPS", 12, LevelOffset.level_3); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + int indexBrush = 0; + foreach (JobBrushStop brushstop in seg.BrushStops) + { + _sizeControl.Height += 5.0; + DrawHeaderText(drawingContext, string.Format("#{0} STOP", ++indexBrush), 11, LevelOffset.level_4); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + var brushStops = GetNameValueList(brushstop); + foreach (var brushstopprop in brushStops) + { + DrawNameValueText(drawingContext, brushstopprop, LevelOffset.level_5, TouchIconKind.Pencil); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + DrawHeaderText(drawingContext, "DISPENSERS", 12, LevelOffset.level_6); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + _sizeControl.Height += 5.0; + int indexDispenser = 0; + foreach (JobDispenser disp in brushstop.Dispensers) + { + DrawHeaderText(drawingContext, string.Format("#{0} DISPENSER", ++indexDispenser), 11, LevelOffset.level_6); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + var dispProperties = GetNameValueList(disp); + foreach (var dispprop in dispProperties) + { + DrawNameValueText(drawingContext, dispprop, LevelOffset.level_7, TouchIconKind.ArrowRightBoldCircle); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } + } + } + } + + if (Height != _sizeControl.Height) + { + Height = _sizeControl.Height; + } + } + public IEnumerable> GetNameValueList(object value) + { + if (value != null) + { + var properties = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => (!x.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(x.PropertyType)) || x.PropertyType == typeof(String)).ToList(); + return properties.Select(x => new Tuple(x.Name, x.GetValue(value).ToString())); + } + else + { + return null; + } + } + #endregion render + + #region drawing + protected void DrawNameValueText(DrawingContext drawingContext, Tuple text, double levelOfOffset, TouchIconKind? icon) + { + if (IsInViewPort()) + { + FormattedText formattedName = new FormattedText(text.Item1 + ": ", System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), + 12, Foreground); + DrawIconTextIfVisible(drawingContext, levelOfOffset, formattedName, icon); + double widthOfNameText = formattedName.WidthIncludingTrailingWhitespace + 17 + levelOfOffset;//17 pix for draw icon before text + + FormattedText formattedValue = new FormattedText(text.Item2, System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.SemiBold, FontStretches.Normal), + 12, Foreground); + DrawIconTextIfVisible(drawingContext, widthOfNameText, formattedValue); + _sizeControl.Width = Math.Max(_sizeControl.Width, (widthOfNameText + formattedValue.WidthIncludingTrailingWhitespace)); + } + } + + private bool IsInViewPort() + { + return (_sizeControl.Height >= _verticalOffset && _sizeControl.Height <= (_verticalOffset + _viewportHeight + 5)); + } + + protected void DrawHeaderText(DrawingContext drawingContext, string text, int fontSize, double levelOfOffset) + { + if (IsInViewPort()) + { + FormattedText formattedtext = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.SemiBold, FontStretches.Normal), + fontSize, Foreground); + DrawIconTextIfVisible(drawingContext, levelOfOffset, formattedtext); + _sizeControl.Width = Math.Max(_sizeControl.Width, (formattedtext.Width + levelOfOffset)); + } + } + + private void DrawIconTextIfVisible(DrawingContext drawingContext, double levelOfOffset, FormattedText formattedText, TouchIconKind? icon = null) + { + if (icon is TouchIconKind) + { + DrawIcon(drawingContext, (TouchIconKind)icon, new Point(levelOfOffset, _sizeControl.Height)); + levelOfOffset += 17; + } + drawingContext.DrawText(formattedText, new Point(levelOfOffset, _sizeControl.Height)); + } + private void DrawIcon(DrawingContext drawingContext, TouchIconKind kind, Point point) + { + GeometryGroup group = GetGeometryByIcon(kind); + SetGeometryPosition(group, point); + drawingContext.DrawGeometry(Foreground, new Pen(Brushes.White, 1), group); + + } + private GeometryGroup GetGeometryByIcon(TouchIconKind kind) + { + Geometry geometry = Geometry.Parse(TouchIcon.Icons[kind]); + GeometryGroup group = new GeometryGroup(); + group.Children.Add(geometry); + + TransformGroup tg = new TransformGroup(); + tg.Children.Add(new ScaleTransform() + { + ScaleX = 10d / geometry.Bounds.Width, + ScaleY = 10d / geometry.Bounds.Height, + }); + tg.Children.Add(new TranslateTransform() { }); + + group.Transform = tg; + return group; + } + private void SetGeometryPosition(GeometryGroup group, Point point) + { + TransformGroup tg = group.Transform as TransformGroup; + (tg.Children[1] as TranslateTransform).X = point.X; + (tg.Children[1] as TranslateTransform).Y = point.Y + 1; + } + #endregion drawing + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml index ba6c13e91..afe331145 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml @@ -66,6 +66,9 @@ + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/RunningJobViewer.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/RunningJobViewer.xaml index 97aedcf89..5d3f3f1fc 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/RunningJobViewer.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/RunningJobViewer.xaml @@ -57,6 +57,9 @@ + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Converters/ColorSpaceToVisibilityConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Converters/ColorSpaceToVisibilityConverter.cs index a8ba66eda..b1be93793 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Converters/ColorSpaceToVisibilityConverter.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Converters/ColorSpaceToVisibilityConverter.cs @@ -18,9 +18,17 @@ namespace Tango.PPC.Jobs.Converters if (colorSpace != null) { - if (colorSpace.Space == BL.Enumerations.ColorSpaces.Catalog) + if (String.IsNullOrWhiteSpace(parameter.ToStringSafe())) { - return Visibility.Collapsed; + if (colorSpace.Space == BL.Enumerations.ColorSpaces.Catalog) + { + return Visibility.Collapsed; + } + } + else + { + String[] spaces = parameter.ToString().Split(','); + return spaces.Contains(colorSpace.Space.ToString()) ? Visibility.Visible : Visibility.Collapsed; } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionView.xaml index 69eb1fd72..da6989ff6 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionView.xaml @@ -19,23 +19,85 @@ - Color is out of range + + + + + - + + + + , , + + + + + , + , + + + + + + + - Please select the best alternative + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionViewVM.cs index 887e62dd7..db8573322 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionViewVM.cs @@ -14,6 +14,6 @@ namespace Tango.PPC.Jobs.Dialogs /// public class AdvancedColorCorrectionViewVM : BasicColorCorrectionViewVM { - + public bool IsOutOfGamut { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/BasicColorCorrectionView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/BasicColorCorrectionView.xaml index 4c100c2fc..bd31b88ce 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/BasicColorCorrectionView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/BasicColorCorrectionView.xaml @@ -59,7 +59,7 @@ - Please select an alternative + Please use the closest alternative @@ -81,7 +81,7 @@ - + @@ -147,7 +147,10 @@ - More Options + + + More Options + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/CatalogSelectionView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/CatalogSelectionView.xaml index ded395e08..128a93548 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/CatalogSelectionView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/CatalogSelectionView.xaml @@ -56,7 +56,7 @@ - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/ImportJobView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/ImportJobView.xaml index ac27cc00d..da51bba27 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/ImportJobView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/ImportJobView.xaml @@ -18,7 +18,7 @@ IMPORT JOB A job file has been selected from the storage device. press 'IMPORT' to add the job to your job list. - Edit this job after import + Edit this job after import diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpg b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpg new file mode 100644 index 000000000..cf1d94d12 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpg differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpg b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpg new file mode 100644 index 000000000..c682a4c7e Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpg differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.png new file mode 100644 index 000000000..d8d6f8470 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.png new file mode 100644 index 000000000..46059c5c0 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png new file mode 100644 index 000000000..4e46ee447 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItem.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItem.cs new file mode 100644 index 000000000..4e3137e1c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItem.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common.Notifications; + +namespace Tango.PPC.Jobs.NotificationItems +{ + /// + /// Represents a simple text message notification item which can be inserted into the application notifications panel. + /// + /// + public class NewSynchronizardJobsNotificationItem : NotificationItem + { + /// + /// Initializes a new instance of the class. + /// + public NewSynchronizardJobsNotificationItem() + { + CanClose = true; + } + + /// + /// Gets or sets the view type. + /// + public override Type ViewType + { + get { return typeof(NewSynchronizardJobsNotificationItemView); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml new file mode 100644 index 000000000..5a57e3db7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + New job definitions were synchronized with your machine. Tap to refresh your job list. + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml.cs new file mode 100644 index 000000000..33db09386 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Jobs.NotificationItems +{ + /// + /// Represents the view. + /// + /// + /// + public partial class NewSynchronizardJobsNotificationItemView : UserControl + { + public NewSynchronizardJobsNotificationItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj index aedf09ce7..33b9de808 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj @@ -124,6 +124,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -163,6 +167,7 @@ + RunningJobViewer.xaml @@ -227,6 +232,10 @@ + + + NewSynchronizardJobsNotificationItemView.xaml + Code @@ -482,10 +491,25 @@ + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs index 103a10b28..8d5bd284d 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs @@ -6,8 +6,10 @@ using System.Threading.Tasks; using Tango.BL.Entities; using Tango.Core.Commands; using Tango.Integration.Operation; +using Tango.PMR.Printing; using Tango.PPC.Common; using Tango.PPC.Common.Navigation; +using Tango.PPC.Common.Notifications; using Tango.PPC.Jobs.AppBarItems; using Tango.PPC.Jobs.AppButtons; using Tango.PPC.Jobs.Dialogs; @@ -47,6 +49,26 @@ namespace Tango.PPC.Jobs.ViewModels set { _runningJobStatus = value; RaisePropertyChangedAuto(); } } + private bool _isDisplayJobOutline; + /// + /// Gets or sets a value indicating whether to display the job outline. + /// + public bool IsDisplayJobOutline + { + get { return _isDisplayJobOutline; } + set { _isDisplayJobOutline = value; RaisePropertyChangedAuto(); } + } + + private JobTicket _jobOutlineTicket; + /// + /// Gets or sets the job outline ticket. + /// + public JobTicket JobOutlineTicket + { + get { return _jobOutlineTicket; } + set { _jobOutlineTicket = value; RaisePropertyChangedAuto(); } + } + #endregion #region Commands @@ -59,6 +81,16 @@ namespace Tango.PPC.Jobs.ViewModels /// public RelayCommand GoToJobCommand { get; set; } + /// + /// Gets or sets the display job outline command. + /// + public RelayCommand DisplayJobOutlineCommand { get; set; } + + /// + /// Gets or sets the hide job outline command. + /// + public RelayCommand HideJobOutlineCommand { get; set; } + #endregion public JobProgressViewVM() @@ -67,14 +99,21 @@ namespace Tango.PPC.Jobs.ViewModels _stop_job_btn.Pressed += _stop_job_btn_Pressed; GoToJobCommand = new RelayCommand(GoToJob); + DisplayJobOutlineCommand = new RelayCommand(DisplayJobOutline); + HideJobOutlineCommand = new RelayCommand(HideJobOutline); } - private void _stop_job_btn_Pressed() + #region Private Methods + + private void HideJobOutline() { - if (_handler != null) - { - _handler.Cancel(); - } + IsDisplayJobOutline = false; + } + + private void DisplayJobOutline() + { + JobOutlineTicket = _handler.JobTicket; + IsDisplayJobOutline = true; } private void GoToJob() @@ -83,6 +122,8 @@ namespace Tango.PPC.Jobs.ViewModels NavigationManager.ClearHistoryExcept(); } + #endregion + #region Override Methods /// @@ -93,23 +134,6 @@ namespace Tango.PPC.Jobs.ViewModels MachineProvider.MachineOperator.PrintingStarted += MachineOperator_PrintingStarted; } - /// - /// Called when the navigation system has navigated from this VM view. - /// - public override void OnNavigatedFrom() - { - base.OnNavigatedFrom(); - - if (MachineProvider.MachineOperator.IsPrinting && _handler != null && !_handler.IsCanceled) - { - NotificationProvider.PushAppBarItem().Pressed += (_, __) => - { - NotificationProvider.CurrentAppBarItem.Close(); - NavigationManager.NavigateTo(nameof(JobProgressView)); - }; - } - } - /// /// Called when the navigation system has navigated to this VM view. /// @@ -117,18 +141,26 @@ namespace Tango.PPC.Jobs.ViewModels { base.OnNavigatedTo(); - if (NotificationProvider.HasAppBarItem && NotificationProvider.CurrentAppBarItem is JobProgressAppBarItem) + IsDisplayJobOutline = false; + + if (_handler != null && !_handler.Status.IsFailed) { - NotificationProvider.CurrentAppBarItem.Close(); + _stop_job_btn.Push(); } - - _stop_job_btn.Push(); } #endregion #region Event Handlers + private void _stop_job_btn_Pressed() + { + if (_handler != null) + { + _handler.Cancel(); + } + } + /// /// Handles the PrintingStarted event of the MachineOperator. /// @@ -141,8 +173,10 @@ namespace Tango.PPC.Jobs.ViewModels e.JobHandler.StatusChanged += JobHandler_StatusChanged; e.JobHandler.SpoolChangeRequired += JobHandler_SpoolChangeRequired; e.JobHandler.Stopped += JobHandler_Stopped; + e.JobHandler.CanCancelChanged += JobHandler_CanCancelChanged; _stop_job_btn.Push(); + _stop_job_btn.IsEnabled = true; } /// @@ -172,12 +206,18 @@ namespace Tango.PPC.Jobs.ViewModels /// The instance containing the event data. private void JobHandler_Stopped(object sender, EventArgs e) { - if (NotificationProvider.HasAppBarItem && NotificationProvider.CurrentAppBarItem is JobProgressAppBarItem) + if (_stop_job_btn != null) { - NotificationProvider.CurrentAppBarItem.Close(); + _stop_job_btn.Pop(); } - _stop_job_btn.Pop(); + if (_handler != null) + { + _handler.StatusChanged -= JobHandler_StatusChanged; + _handler.SpoolChangeRequired -= JobHandler_SpoolChangeRequired; + _handler.Stopped -= JobHandler_Stopped; + _handler.CanCancelChanged -= JobHandler_CanCancelChanged; + } } /// @@ -193,6 +233,16 @@ namespace Tango.PPC.Jobs.ViewModels }); } + /// + /// Handles the CanCancelChanged event of the JobHandler control. + /// + /// The source of the event. + /// The instance containing the event data. + private void JobHandler_CanCancelChanged(object sender, EventArgs e) + { + _stop_job_btn.IsEnabled = _handler.CanCancel; + } + #endregion } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs index bff6beff5..a2acf5893 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs @@ -26,6 +26,7 @@ namespace Tango.PPC.Jobs.ViewModels { private ObservablesContext _context; private bool _canStartJob; + private bool _startingJob; private bool _isPreparingJob; /// @@ -59,7 +60,6 @@ namespace Tango.PPC.Jobs.ViewModels set { _estimatedDuration = value; RaisePropertyChangedAuto(); } } - /// /// Gets or sets the dye command. /// @@ -96,12 +96,20 @@ namespace Tango.PPC.Jobs.ViewModels /// private async void StartJob() { + if (_startingJob) return; + + _startingJob = true; + _canStartJob = false; + InvalidateRelayCommands(); + NavigationManager.IsBackEnabled = false; + try { LogManager.Log("Start job command pressed. Starting job and navigating to job progress view..."); await PrintingManager.Print(Job, _context); await NavigationManager.NavigateTo(false, nameof(JobProgressView)); + _startingJob = false; } catch (InsufficientLiquidQuantityException) { @@ -112,6 +120,13 @@ namespace Tango.PPC.Jobs.ViewModels LogManager.Log(ex, "Could not start the current job."); await NotificationProvider.ShowError($"{ex.Message}"); } + finally + { + _startingJob = false; + _canStartJob = true; + NavigationManager.IsBackEnabled = true; + InvalidateRelayCommands(); + } } /// @@ -130,16 +145,6 @@ namespace Tango.PPC.Jobs.ViewModels _context = obj.Context; Job = obj.Job; - if (Job.ColorSpace.Space == BL.Enumerations.ColorSpaces.Catalog) - { - if (_context.ColorCatalogs.SingleOrDefault(x => x.Guid == Job.ColorCatalogGuid) == null) - { - await NotificationProvider.ShowError("The selected color catalog for this job could not be found.\nCannot load job."); - await NavigationManager.NavigateBack(); - return; - } - } - IsPreparingJob = true; Job = await new JobBuilder(_context).Set(Job.Guid) @@ -150,7 +155,15 @@ namespace Tango.PPC.Jobs.ViewModels .WithBrushStops() .BuildAsync(); - await Task.Delay(2000); + if (Job.ColorSpace.Space == BL.Enumerations.ColorSpaces.Catalog) + { + if (_context.ColorCatalogs.SingleOrDefault(x => x.Guid == Job.ColorCatalogGuid) == null) + { + await NotificationProvider.ShowError("The selected color catalog for this job could not be found.\nCannot load job."); + await NavigationManager.NavigateBack(); + return; + } + } await Task.Factory.StartNew(() => { diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs index 4e1e58dba..5e90d3b5b 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs @@ -56,6 +56,7 @@ namespace Tango.PPC.Jobs.ViewModels private ActionTimer _volumeConversionTimer; private IColorConverter _converter; private string _current_job_string; + private bool startingJob = false; #region Properties @@ -412,7 +413,7 @@ namespace Tango.PPC.Jobs.ViewModels RepeatSampleDyeCommand = new RelayCommand(RepeatSampleDye); AnotherSampleCommand = new RelayCommand(DyeAnotherSample); InvokeFineTuningPaletteCommand = new RelayCommand(InvokeFineTuningPalette); - ResetFineTuningCommand = new RelayCommand(ResetFineTuning); + ResetFineTuningCommand = new RelayCommand(() => ResetFineTuning(true)); StartFineTuningCommand = new RelayCommand(StartFineTuning, () => FineTuneItems.Any(x => x.IsSelected) && CanStartJob()); RepeatFineTuningCommand = new RelayCommand(RepeatFineTuning); ApproveFineTuningCommand = new RelayCommand(ApproveFineTuning); @@ -468,7 +469,7 @@ namespace Tango.PPC.Jobs.ViewModels Job.ValidateOnPropertyChanged = true; LogManager.Log("Loading RMLS..."); - Rmls = (await new RmlsCollectionBuilder(_db).SetAll().WithActiveParametersGroup().WithCAT(Job.MachineGuid).WithCCT().WithLiquidFactors().BuildAsync()).ToList(); + Rmls = (await new RmlsCollectionBuilder(_db).SetAll().WithActiveParametersGroup().WithCAT(Job.MachineGuid).WithCCT().WithLiquidFactors().WithSpools().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).BuildAsync()).ToList(); LogManager.Log("Loading Color Spaces..."); ColorSpaces = await _db.ColorSpaces.ToListAsync(); LogManager.Log("Loading Spool Types..."); @@ -478,7 +479,7 @@ namespace Tango.PPC.Jobs.ViewModels if (Job.ColorSpace.Space == BL.Enumerations.ColorSpaces.Catalog) { - SelectedCatalog = await new ColorCatalogBuilder(_db).Set(Job.ColorCatalogGuid).WithGroups().WithItems().BuildAsync(); + SelectedCatalog = await new CatalogBuilder(_db).Set(Job.ColorCatalogGuid).WithGroups().WithItems().BuildAsync(); if (SelectedCatalog != null) { @@ -545,18 +546,15 @@ namespace Tango.PPC.Jobs.ViewModels } catch (Exception ex) { - LogManager.Log(ex, $"Error loading job '{_job_to_load.Name}'"); + IsFree = true; + LogManager.Log(ex, $"Error loading job '{(_job_to_load != null ? _job_to_load.Name : "null")}'"); await NotificationProvider.ShowError("An error occurred while trying to load the selected job."); _can_navigate_back = true; await NavigationManager.NavigateBack(); } finally { - InvokeUI(() => - { - IsFree = true; - //NotificationProvider.ReleaseGlobalBusyMessage(); - }); + IsFree = true; } } @@ -593,7 +591,9 @@ namespace Tango.PPC.Jobs.ViewModels } Job.LastUpdated = DateTime.UtcNow; + Job.IsSynchronized = false; Job.JobStatus = BL.Enumerations.JobStatuses.Draft; + Job.MarkModified(_db); await _db.SaveChangesAsync(); _current_job_string = Job.ToJobFileWhenLoaded().ToString(); @@ -645,11 +645,16 @@ namespace Tango.PPC.Jobs.ViewModels /// private async void StartJob() { + if (startingJob) return; + try { + Debug.WriteLine("Job Starting..."); + startingJob = true; LogManager.Log("Start job command pressed. Starting job and navigating to job progress view..."); - await PrintingManager.Print(Job, _db); + var handler = await PrintingManager.Print(Job, _db); await NavigationManager.NavigateTo(nameof(JobProgressView)); + startingJob = false; } catch (InsufficientLiquidQuantityException) { @@ -660,6 +665,10 @@ namespace Tango.PPC.Jobs.ViewModels LogManager.Log(ex, "Could not start the current job."); await NotificationProvider.ShowError($"{ex.Message}."); } + finally + { + startingJob = false; + } } /// @@ -668,8 +677,7 @@ namespace Tango.PPC.Jobs.ViewModels private bool CanStartJob() { return - Job != null && Job.Validate(_db) && - !Job.Segments.SelectMany(x => x.BrushStops).ToList().Exists(x => x.IsOutOfGamut); + Job != null && Job.Validate(_db) && !Job.Segments.SelectMany(x => x.BrushStops).Where(x => !x.IsTransparent && !x.IsWhite).ToList().Exists(x => x.IsOutOfGamut || x.IsLiquidVolumesOutOfRange); } #endregion @@ -709,7 +717,7 @@ namespace Tango.PPC.Jobs.ViewModels try { LogManager.Log("Adding new solid segment..."); - var s = Job.AddSolidSegment(MachineProvider.Machine.DefaultSegmentLength > 0 ? MachineProvider.Machine.DefaultSegmentLength : 10); + var s = Job.AddSolidSegment(Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 10); SetSegmentLiquidVolumesIfVolume(s); return s; } @@ -729,7 +737,7 @@ namespace Tango.PPC.Jobs.ViewModels try { LogManager.Log("Adding new gradient segment..."); - var s = Job.AddGradientSegment(MachineProvider.Machine.DefaultSegmentLength > 0 ? MachineProvider.Machine.DefaultSegmentLength : 10); + var s = Job.AddGradientSegment(Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 10); SetSegmentLiquidVolumesIfVolume(s); return s; } @@ -759,14 +767,7 @@ namespace Tango.PPC.Jobs.ViewModels draggedSegment.SegmentIndex = droppedSegment.SegmentIndex + 1; } - int index = 1; - - foreach (var segment in Job.Segments.OrderBy(x => x.SegmentIndex)) - { - segment.SegmentIndex = index++; - } - - SegmentsCollectionView.Refresh(); + ArrangeSegmentsIndices(); } /// @@ -829,10 +830,14 @@ namespace Tango.PPC.Jobs.ViewModels private void ArrangeSegmentsIndices() { - for (int i = 0; i < Job.Segments.Count; i++) + int index = 1; + + foreach (var segment in Job.Segments.OrderBy(x => x.SegmentIndex)) { - Job.Segments[i].SegmentIndex = i + 1; + segment.SegmentIndex = index++; } + + SegmentsCollectionView.Refresh(); } #endregion @@ -880,23 +885,55 @@ namespace Tango.PPC.Jobs.ViewModels LogManager.Log($"Invoking triplet color adjustment dialog for brush stop {brushStop.StopIndex} at segment {brushStop.Segment.SegmentIndex}."); LogManager.Log("Retrieving color conversion suggestions for brush stop..."); - var conversionOutput = _converter.Convert(brushStop, true); + PMR.ColorLab.ConversionOutput conversionOutput = null; + + if (brushStop.IsOutOfGamut) + { + conversionOutput = _converter.Convert(brushStop, false); + } BasicColorCorrectionViewVM vm = null; + List suggestions = null; - vm = await NotificationProvider.ShowDialog(new BasicColorCorrectionViewVM() + if (brushStop.IsOutOfGamut) { - InvalidBrushStop = brushStop, - Suggestions = conversionOutput.CreateTrippletSuggestions(), - }); + vm = await NotificationProvider.ShowDialog(new BasicColorCorrectionViewVM() + { + InvalidBrushStop = brushStop, + Suggestions = new List() { new ColorConversionSuggestion(conversionOutput.SingleCoordinates, 0, 0) }, + }); + } - if (vm.Result == BasicColorCorrectionViewVM.ColorCorrectionDialogResult.MoreOptions) + if (vm == null || vm.Result == BasicColorCorrectionViewVM.ColorCorrectionDialogResult.MoreOptions) { + NotificationProvider.SetGlobalBusyMessage("Generating color hive..."); + + await Task.Factory.StartNew(() => + { + conversionOutput = _converter.Convert(brushStop, true); + + suggestions = conversionOutput.CreateHiveSuggestions(); + + if (vm == null) + { + var center = suggestions.GetCenterSuggestion(); + center.Coordinates.Red = brushStop.Red; + center.Coordinates.Green = brushStop.Green; + center.Coordinates.Blue = brushStop.Blue; + + center.Coordinates.L = brushStop.L; + center.Coordinates.A = brushStop.A; + center.Coordinates.B = brushStop.B; + } + }); + + NotificationProvider.ReleaseGlobalBusyMessage(); LogManager.Log("Invoking hive color conversion dialog..."); vm = await NotificationProvider.ShowDialog(new AdvancedColorCorrectionViewVM() { InvalidBrushStop = brushStop, - Suggestions = conversionOutput.CreateHiveSuggestions(), + Suggestions = suggestions, + IsOutOfGamut = brushStop.IsOutOfGamut, }); } @@ -916,6 +953,13 @@ namespace Tango.PPC.Jobs.ViewModels brushStop.A = vm.SelectedSuggestion.Coordinates.A; brushStop.B = vm.SelectedSuggestion.Coordinates.B; } + else if (brushStop.BrushColorSpace == BL.Enumerations.ColorSpaces.Volume) + { + if (vm.SelectedSuggestion != suggestions.GetCenterSuggestion()) + { + vm.SelectedSuggestion.ApplyOnBrushStop(brushStop); + } + } brushStop.Corrected = true; brushStop.IsOutOfGamut = false; @@ -927,6 +971,11 @@ namespace Tango.PPC.Jobs.ViewModels LogManager.Log(ex, "Error while invoking color adjustment dialog."); await NotificationProvider.ShowError("An error occurred while trying to convert the selected color."); } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + DyeCommand.RaiseCanExecuteChanged(); + } } /// @@ -936,7 +985,7 @@ namespace Tango.PPC.Jobs.ViewModels [HandleProcessCorruptedStateExceptions] public void OnBrushStopFieldValueChanged(BrushStop stop) { - if (stop != null) + if (stop != null && stop.ColorSpace != null) { stop.Corrected = false; stop.OutOfGamutChecked = false; @@ -954,6 +1003,11 @@ namespace Tango.PPC.Jobs.ViewModels stop.Blue = output.SingleCoordinates.Blue; stop.Corrected = true; stop.IsOutOfGamut = false; + + InvokeUI(() => + { + DyeCommand.RaiseCanExecuteChanged(); + }); } catch (Exception ex) { @@ -1074,7 +1128,7 @@ namespace Tango.PPC.Jobs.ViewModels /// /// Synchronizes the fine tune items to brush stops. /// - private void SyncFineTuneItemsToBrushStops() + private async void SyncFineTuneItemsToBrushStops(bool displayBusy = false) { try { @@ -1086,18 +1140,27 @@ namespace Tango.PPC.Jobs.ViewModels } else { + if (displayBusy) + { + NotificationProvider.SetGlobalBusyMessage("Generating suggestions..."); + } + FineTuneItems.Clear(); - foreach (var stop in Job.Segments.SelectMany(x => x.BrushStops).Where(x => x.ColorSpace.Space == BL.Enumerations.ColorSpaces.RGB || x.ColorSpace.Space == BL.Enumerations.ColorSpaces.LAB).DistinctBy(x => x.Color)) + foreach (var stop in Job.Segments.SelectMany(x => x.BrushStops).Where(x => !x.IsTransparent).Where(x => x.ColorSpace.Space == BL.Enumerations.ColorSpaces.RGB || x.ColorSpace.Space == BL.Enumerations.ColorSpaces.LAB).DistinctBy(x => x.Color)) { - FineTuneItem item = new FineTuneItem(_converter.Convert(stop, true)); + var conversionoutput = await _converter.ConvertAsync(stop, true); + FineTuneItem item = new FineTuneItem(conversionoutput); + item.BrushStop = stop; item.BrushStops = Job.Segments.SelectMany(x => x.BrushStops).Where(x => x.Color == stop.Color).ToList(); - item.SelectedSuggestion = item.Suggestions[item.Suggestions.Count / 2]; + item.SelectedSuggestion = item.Suggestions.GetCenterSuggestion(); item.SelectedChanged += () => StartFineTuningCommand.RaiseCanExecuteChanged(); FineTuneItems.Add(item); } _jobs_fine_tune_items[Job.Guid] = FineTuneItems.ToList(); + + NotificationProvider.ReleaseGlobalBusyMessage(); } ApprovalFineTuneItems = FineTuneItems.Where(x => x.IsSelected).ToObservableCollection(); @@ -1109,6 +1172,10 @@ namespace Tango.PPC.Jobs.ViewModels { LogManager.Log(ex, "Error while trying to synchronize fine tuning items with brush stops."); } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + } } /// @@ -1135,19 +1202,23 @@ namespace Tango.PPC.Jobs.ViewModels LogManager.Log(ex, "Error invoking the fine tunning palette"); await NotificationProvider.ShowError("An error occurred while trying to display the fine tunning palette."); } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + } } /// /// Resets the fine tuning. /// - private void ResetFineTuning() + private void ResetFineTuning(bool displayBusy = false) { if (Job != null && _jobs_fine_tune_items.ContainsKey(Job.Guid)) { _jobs_fine_tune_items.Remove(Job.Guid); } - SyncFineTuneItemsToBrushStops(); + SyncFineTuneItemsToBrushStops(displayBusy); } /// @@ -1357,6 +1428,8 @@ namespace Tango.PPC.Jobs.ViewModels { bool result = true; + if (!IsFree) return false; + if (!_can_navigate_back) { bool jobChainged = false; diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobsViewVM.cs index a7b06f6eb..64931cbe3 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobsViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobsViewVM.cs @@ -36,6 +36,9 @@ using System.Windows.Media.Imaging; using Tango.Touch.Components; using Tango.PPC.Jobs.ViewContracts; using Tango.Core.ExtensionMethods; +using Tango.PPC.Common.Synchronization; +using Tango.PPC.Jobs.NotificationItems; +using Tango.PPC.Storage.Models; namespace Tango.PPC.Jobs.ViewModels { @@ -46,7 +49,10 @@ namespace Tango.PPC.Jobs.ViewModels public class JobsViewVM : PPCViewModel { private ObservablesContext _db; //Holds the db context for the job list. - private ObservableCollection _catalogs; //Holds the available color catalogs. + private ObservableCollection _catalogs; //Holds the available color catalogs for the site. + private ObservableCollection _rmls; //Holds the available RML for the site. + private List _colorSpaces; //Holds the available color spaces. + private bool _isJobsSynchronizationNotificationActive; public enum JobsCategory { @@ -318,7 +324,7 @@ namespace Tango.PPC.Jobs.ViewModels RaiseMessage(new JobSelectedMessage() { Job = job, Context = _db }); - if (!directlyToEdit && MachineProvider.MachineOperator.Status == Integration.Operation.MachineStatuses.ReadyToDye) + if (!directlyToEdit && MachineProvider.MachineOperator.CanPrint) { await NavigationManager.NavigateWithObject(new JobSummeryNavigationObject() { @@ -349,6 +355,8 @@ namespace Tango.PPC.Jobs.ViewModels _db = ObservablesContext.CreateDefault(); + _colorSpaces = _db.ColorSpaces.ToList(); + var jobs = new JobsCollectionBuilder(_db).Set(x => x.MachineGuid == MachineProvider.Machine.Guid).WithSegments().WithBrushStops().WithCustomer().WithColorSpace().Build(); InvokeUI(() => @@ -407,10 +415,15 @@ namespace Tango.PPC.Jobs.ViewModels var machine = MachineProvider.Machine; JobCreationViewVM vm = new JobCreationViewVM( - machine.SupportedJobTypes.Count > 0 ? machine.SupportedJobTypes : Enum.GetValues(typeof(JobTypes)).Cast().ToList(), - machine.SupportedColorSpaces.Count > 0 ? machine.SupportedColorSpaces : Enum.GetValues(typeof(ColorSpaces)).Cast().Where(x => x.IsUserSpace() || (ApplicationManager.IsInTechnicianMode && x == ColorSpaces.Volume)).ToList() + Settings.SupportedJobTypes.Count > 0 ? Settings.SupportedJobTypes : Enum.GetValues(typeof(JobTypes)).Cast().ToList(), + Settings.SupportedColorSpaces.Count > 0 ? Settings.SupportedColorSpaces : Enum.GetValues(typeof(ColorSpaces)).Cast().Where(x => x.IsUserSpace() || (ApplicationManager.IsInTechnicianMode && x == ColorSpaces.Volume)).ToList() ); + if (_catalogs.Count == 0) + { + vm.SupportedColorSpaces.Remove(ColorSpaces.Catalog); + } + CatalogSelectionViewVM catalogVM = new CatalogSelectionViewVM(_catalogs.ToList(), _catalogs.ToList().SingleOrDefault(x => x.Guid == settings.LastSelectedCatalogGuid)); if (settings.LastJobType != null) @@ -419,7 +432,7 @@ namespace Tango.PPC.Jobs.ViewModels } else { - vm.SelectedJobType = machine.SupportedJobTypes.FirstOrDefault(); + vm.SelectedJobType = Settings.SupportedJobTypes.FirstOrDefault(); } if (settings.LastJobColorSpace != null) @@ -428,7 +441,7 @@ namespace Tango.PPC.Jobs.ViewModels } else { - var space = machine.SupportedColorSpaces.FirstOrDefault(); + var space = Settings.SupportedColorSpaces.FirstOrDefault(); vm.SelectedColorSpace = space.IsUserSpace() ? space : ColorSpaces.Catalog; } @@ -446,7 +459,7 @@ namespace Tango.PPC.Jobs.ViewModels if (twnFile == null) { - if (machine.SupportedJobTypes.Count != 1 || machine.SupportedColorSpaces.Count != 1) + if (Settings.SupportedJobTypes.Count != 1 || Settings.SupportedColorSpaces.Count != 1) { vm = await NotificationProvider.ShowDialog(vm); if (!vm.DialogResult) return; @@ -476,14 +489,14 @@ namespace Tango.PPC.Jobs.ViewModels } else { - vm.SelectedJobType = machine.SupportedJobTypes.First(); - vm.SelectedColorSpace = machine.SupportedColorSpaces.First(); + vm.SelectedJobType = Settings.SupportedJobTypes.First(); + vm.SelectedColorSpace = Settings.SupportedColorSpaces.First(); } } settings.LastJobType = vm.SelectedJobType; settings.LastJobColorSpace = vm.SelectedColorSpace; - + if (vm.SelectedColorSpace == ColorSpaces.Catalog) { settings.LastSelectedCatalogGuid = catalogVM.SelectedCatalog.Guid; @@ -492,6 +505,8 @@ namespace Tango.PPC.Jobs.ViewModels settings.Save(); Job job = new Job(); + job.LastUpdated = DateTime.UtcNow; + job.JobSource = JobSource.Local; job.Name = "untitled"; job.NumberOfHeads = 1; job.NumberOfUnits = 1; @@ -501,11 +516,12 @@ namespace Tango.PPC.Jobs.ViewModels job.JobType = vm.SelectedJobType; job.EnableLubrication = true; job.ColorSpaceGuid = Adapter.ColorSpaces.FirstOrDefault(x => x.Code == vm.SelectedColorSpace.ToInt32()).Guid; + job.ColorSpace = _colorSpaces.SingleOrDefault(x => x.Guid == job.ColorSpaceGuid); job.MachineGuid = MachineProvider.Machine.Guid; - job.UserGuid = AuthenticationProvider.CurrentUser.Guid; - job.RmlGuid = machine.DefaultRml != null ? machine.DefaultRmlGuid : Adapter.Rmls.FirstOrDefault().Guid; + job.UserGuid = null; + job.RmlGuid = (Settings.DefaultRmlGuid != null && _rmls.Select(x => x.Guid).Contains(Settings.DefaultRmlGuid)) ? Settings.DefaultRmlGuid : _rmls.FirstOrDefault().Guid; job.WindingMethodGuid = Adapter.WindingMethods.FirstOrDefault().Guid; - job.SpoolTypeGuid = machine.DefaultSpoolType != null ? machine.DefaultSpoolTypeGuid : Adapter.SpoolTypes.FirstOrDefault().Guid; + job.SpoolTypeGuid = Settings.DefaultSpoolTypeGuid != null ? Settings.DefaultSpoolTypeGuid : Adapter.SpoolTypes.FirstOrDefault().Guid; if (vm.SelectedColorSpace == ColorSpaces.Catalog) { @@ -519,11 +535,11 @@ namespace Tango.PPC.Jobs.ViewModels if (colorProfile == null) { - job.AddSolidSegment(machine.DefaultSegmentLength > 0 ? machine.DefaultSegmentLength : 100); + job.AddSolidSegment(Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 100); } else { - job.AddSolidSegment(colorProfile.Value, machine.DefaultSegmentLength > 0 ? machine.DefaultSegmentLength : 100); + job.AddSolidSegment(colorProfile.Value, Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 100); job.Name = $"SnapMatch {colorProfile.Value.R}, {colorProfile.Value.G}, {colorProfile.Value.B}"; } @@ -724,10 +740,13 @@ namespace Tango.PPC.Jobs.ViewModels StorageProvider.RegisterFileHandler(ExplorerFileDefinition.Pulse.Extension, HandlePulseFileLoaded); //Load catalogs. - using (ObservablesContext c = ObservablesContext.CreateDefault()) + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - _catalogs = (await c.ColorCatalogs.ToListAsync()).ToObservableCollection(); + _catalogs = await new CatalogsCollectionBuilder(db).SetAll().ForSite(MachineProvider.Machine.SiteGuid).BuildAsync(); + _rmls = await new RmlsCollectionBuilder(db).SetAll().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).BuildAsync(); } + + MachineDataSynchronizer.SynchronizationEnded += MachineDataSynchronizer_SynchronizationEnded; } public override void OnNavigatedTo() @@ -745,37 +764,64 @@ namespace Tango.PPC.Jobs.ViewModels var selected_job = SelectedJobs.FirstOrDefault(); if (selected_job == null) return; + var selectedJobs = SelectedJobs.ToList(); + ClearSelection(); var result = await NavigationManager. NavigateForResult( - new Storage.Models.StorageNavigationRequest() + StorageNavigationRequest>( + new StorageNavigationRequest() { - Intent = Storage.Models.StorageNavigationIntent.SaveFile, + Intent = selectedJobs.Count == 1 ? StorageNavigationIntent.SaveFile : StorageNavigationIntent.SaveFiles, DefaultFileName = selected_job.Name, Filter = ExplorerFileDefinition.Job.Extension, - Title = "Save Job File", + Title = selectedJobs.Count == 1 ? "Save Job File" : "Save Job Files", }); if (result != null) { - try + if (selectedJobs.Count == 1) { - var jobFile = await selected_job.ToJobFile(); + try + { + var jobFile = await selected_job.ToJobFile(); - using (FileStream fs = new FileStream(result.Path + ExplorerFileDefinition.Job.Extension, FileMode.Create)) + using (FileStream fs = new FileStream(result.Path + ExplorerFileDefinition.Job.Extension, FileMode.Create)) + { + jobFile.WriteTo(fs); + } + + await NotificationProvider.ShowSuccess("Job saved successfully."); + } + catch (Exception ex) { - jobFile.WriteTo(fs); + LogManager.Log(ex, $"Error saving job {selected_job.Name} to file."); + await NotificationProvider.ShowError($"An error occurred while trying to save the job.\n{ex.Message}"); } - - await NotificationProvider.ShowSuccess("Job saved successfully."); } - catch (Exception ex) + else { - LogManager.Log(ex, $"Error saving job {selected_job.Name} to file."); - await NotificationProvider.ShowError($"An error occurred while trying to save the job.\n{ex.Message}"); + foreach (var job in selectedJobs) + { + try + { + var jobFile = await job.ToJobFile(); + + using (FileStream fs = new FileStream(Path.Combine(result.Path, jobFile.Name.ToValidFileName()) + ExplorerFileDefinition.Job.Extension, FileMode.Create)) + { + jobFile.WriteTo(fs); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error saving job {job.Name} to file."); + await NotificationProvider.ShowError($"An error occurred while trying to save the job.\n{ex.Message}"); + } + } + + await NotificationProvider.ShowSuccess("Jobs saved successfully."); } } } @@ -784,7 +830,7 @@ namespace Tango.PPC.Jobs.ViewModels #region Handle Job File Loading From Storage - private async void HandleJobFileLoaded(ExplorerFileItem jobFile) + private async void HandleJobFileLoaded(List jobFiles) { var vm = await NotificationProvider.ShowDialog(); @@ -792,29 +838,35 @@ namespace Tango.PPC.Jobs.ViewModels { using (ObservablesContext jobContext = ObservablesContext.CreateDefault()) { - try + foreach (var jobFile in jobFiles) { - JobFile jFile = JobFile.Parser.ParseFrom(File.ReadAllBytes(jobFile.Path)); - var job = await Job.FromJobFile(jFile, MachineProvider.Machine.Guid, AuthenticationProvider.CurrentUser.Guid); - jobContext.Jobs.Add(job); - await jobContext.SaveChangesAsync(); - LoadJobs(() => + try { - if (vm.ImportAndEdit) - { - var postJob = Jobs.SingleOrDefault(x => x.Guid == job.Guid); - if (postJob != null) - { - SelectJob(postJob, true); - } - } - }); + JobFile jFile = JobFile.Parser.ParseFrom(File.ReadAllBytes(jobFile.Path)); + var job = await Job.FromJobFile(jFile, MachineProvider.Machine.Guid, null); + job.JobSource = JobSource.Local; + jobContext.Jobs.Add(job); + await jobContext.SaveChangesAsync(); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error occurred while trying to import job from file {jobFile.Path}."); + await NotificationProvider.ShowError($"An error occurred while trying to import the selected job file.\n{ex.Message}"); + } } - catch (Exception ex) + + LoadJobs(() => { - LogManager.Log(ex, $"Error occurred while trying to import job from file {jobFile.Path}."); - await NotificationProvider.ShowError($"An error occurred while trying to import the selected job file.\n{ex.Message}"); - } + //Editing of a job is currently deprecated due to enabling multiple job imports. + //if (vm.ImportAndEdit) + //{ + // var postJob = Jobs.SingleOrDefault(x => x.Guid == job.Guid); + // if (postJob != null) + // { + // SelectJob(postJob, true); + // } + //} + }); } } } @@ -823,8 +875,10 @@ namespace Tango.PPC.Jobs.ViewModels #region Handle TCC File Loading From Storage - private async void HandleColorProfileFileLoaded(ExplorerFileItem tccFile) + private async void HandleColorProfileFileLoaded(List tccFiles) { + var tccFile = tccFiles.FirstOrDefault(); + try { DetectionColorFile tcc = DetectionColorFile.Parser.ParseFrom(File.ReadAllBytes(tccFile.Path)); @@ -853,8 +907,10 @@ namespace Tango.PPC.Jobs.ViewModels #region Handle Pulse TWN Loading From Storage - private async void HandlePulseFileLoaded(ExplorerFileItem twnFile) + private async void HandlePulseFileLoaded(List twnFiles) { + var twnFile = twnFiles.FirstOrDefault(); + TwnFile twn = TwnFile.FromFile(twnFile.Path); BitmapSource preview = twn.Thumbnail.ToBitmapSource(); @@ -871,6 +927,32 @@ namespace Tango.PPC.Jobs.ViewModels #endregion + #region Handle New Synchronized Jobs + + private void MachineDataSynchronizer_SynchronizationEnded(object sender, SynchronizationEndedEventArgs e) + { + if (e.NewChangedJobs > 0 && !_isJobsSynchronizationNotificationActive) + { + _isJobsSynchronizationNotificationActive = true; + + var item = NotificationProvider.PushNotification(); + item.Pressed += (_, __) => + { + _isJobsSynchronizationNotificationActive = false; + LoadJobs(() => + { + NotificationProvider.ShowSuccess("Your job list is now synchronized."); + }); + }; + item.Closed += (_, __) => + { + _isJobsSynchronizationNotificationActive = false; + }; + } + } + + #endregion + #region Color Profile Request private void ExternalBridgeService_ColorProfileRequest(object sender, ColorProfileRequestEventArgs e) diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/MainViewVM.cs index ed1e28f55..579e1e2f7 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/MainViewVM.cs @@ -11,6 +11,7 @@ using Tango.Integration.Operation; using Tango.PPC.Common; using Tango.PPC.Common.Notifications; using Tango.PPC.Common.Notifications.NotificationItems; +using Tango.PPC.Jobs.AppBarItems; using Tango.PPC.Jobs.Messages; using Tango.PPC.Jobs.NavigationObjects; using Tango.PPC.Jobs.Views; @@ -24,6 +25,9 @@ namespace Tango.PPC.Jobs.ViewModels public class MainViewVM : PPCViewModel { private NotificationItem _last_failed_job_notification; + private JobHandler _handler; + private bool resuming; + private JobProgressAppBarItem _appBarItem; /// /// Called when the application has been started. @@ -33,23 +37,42 @@ namespace Tango.PPC.Jobs.ViewModels MachineProvider.MachineOperator.PrintingCompleted += MachineOperator_PrintingCompleted; MachineProvider.MachineOperator.PrintingFailed += MachineOperator_PrintingFailed; MachineProvider.MachineOperator.ResumingJob += MachineOperator_ResumingJob; + MachineProvider.MachineOperator.PrintingStarted += MachineOperator_PrintingStarted; + MachineProvider.MachineOperator.PrintingEnded += MachineOperator_PrintingEnded; + NavigationManager.CurrentVMChanged += NavigationManager_CurrentVMChanged; } - private async void MachineOperator_ResumingJob(object sender, ResumingJobEventArgs e) + private void MachineOperator_PrintingEnded(object sender, PrintingEventArgs e) { - LogManager.Log($"Trying to resume job '{e.JobGuid}'..."); + _appBarItem?.Close(); + _appBarItem = null; + } - try + private void NavigationManager_CurrentVMChanged(object sender, PPCViewModel vm) + { + if (vm.GetType() == typeof(JobProgressViewVM)) { - var job = await new JobBuilder(ObservablesContext.CreateDefault()).Set(e.JobGuid) - .WithConfiguration() - .WithRML() - .WithUser() - .WithSegments() - .WithBrushStops() - .BuildAsync(); + _appBarItem?.Close(); + _appBarItem = null; + } + else if (vm.GetType() != typeof(JobSummeryViewVM) && _appBarItem == null && MachineProvider.MachineOperator.IsPrinting && _handler != null && !_handler.IsCanceled) + { + _appBarItem = NotificationProvider.PushAppBarItem(); + _appBarItem.Pressed += (_, __) => + { + _appBarItem?.Close(); + NavigationManager.NavigateTo(nameof(JobProgressView)); + }; + } + } - e.Approve(job); + private void MachineOperator_PrintingStarted(object sender, PrintingEventArgs e) + { + _handler = e.JobHandler; + + if (resuming) + { + resuming = false; InvokeUI(() => { @@ -62,6 +85,17 @@ namespace Tango.PPC.Jobs.ViewModels } }); } + } + + private void MachineOperator_ResumingJob(object sender, ResumingJobEventArgs e) + { + LogManager.Log($"Job resume request '{e.JobGuid}' approving..."); + + try + { + e.Approve(); + resuming = true; + } catch (Exception ex) { LogManager.Log(ex, "An error occurred while trying to resume the job."); @@ -79,13 +113,15 @@ namespace Tango.PPC.Jobs.ViewModels /// The instance containing the event data. private void MachineOperator_PrintingFailed(object sender, PrintingFailedEventArgs e) { + String message = $"{e.Exception.FlattenMessage()}"; + _last_failed_job_notification = NotificationProvider.PushNotification(new MessageNotificationItem( - String.Format("'{0}' failed.", e.Job.Name), - String.Format("The job '{1}' has failed due to unexpected error.{0}{2}{0}{0}Tap to view this job details.", Environment.NewLine, e.Job.Name, e.Exception), MessageNotificationItem.MessageNotificationItemTypes.Error, () => + $"'{e.Job.Name}' failed at position {e.JobHandler.Status.ProgressMinusSettingUp.ToString("0.0")} out of {e.JobHandler.Status.TotalProgressMinusSettingUp.ToString("0.0")} meters.", + message, MessageNotificationItem.MessageNotificationItemTypes.Error, () => { NavigationManager.NavigateWithObject(e.Job); NavigationManager.ClearHistoryExcept(); - })); + }, NotificationItem.NotificationPriority.VeryHigh)); } /// @@ -119,7 +155,7 @@ namespace Tango.PPC.Jobs.ViewModels { NavigationManager.NavigateWithObject(new JobNavigationObject() { Job = e.Job }); NavigationManager.ClearHistoryExcept(); - })); + }, NotificationItem.NotificationPriority.VeryHigh)); } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobProgressView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobProgressView.xaml index 3b92581bc..40cfc40f9 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobProgressView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobProgressView.xaml @@ -19,7 +19,7 @@ - + (Sample) (Fine Tuning) @@ -38,6 +38,8 @@ + + @@ -98,7 +100,7 @@ - Getting ready... + Getting Ready... @@ -117,8 +119,8 @@ - - + + - - - - - - - - - - - - - - - - job canceled - - - - - - - - - - job failed - - - - - - - - - - job completed - - - - - - - - - + + + + + + + + + + + + + + + @@ -214,5 +210,23 @@ Go to job + + + Display Job Outline + + + + + + + + + + + + + Hide Job Outline + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobSummeryView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobSummeryView.xaml index 80a427714..4785805a6 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobSummeryView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobSummeryView.xaml @@ -54,7 +54,7 @@ - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml index 57101569a..6a94034db 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml @@ -26,6 +26,8 @@ + + + @@ -147,6 +164,17 @@ + + + + + + Transparent + + + + + @@ -172,7 +200,10 @@ - + + + + @@ -214,7 +245,11 @@ - + + + + + + + + + + @@ -247,77 +302,90 @@ - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + Transparent + + + + + + + + + + + + + + + + + + + + + + + + @@ -334,23 +402,27 @@ - - - - - + + + + + + @@ -454,9 +526,9 @@ Comment: - + - + @@ -559,7 +631,6 @@ @@ -647,63 +718,61 @@ - - - - - - Job Summary - + + + + + Job Summary + - - - - + + + + - + - - + + - - - - - + + + + + (+%) - - + + - - + + - + - + - % + % - - - - + + + - - + + - + Additional Tools - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs index 880aa8a3a..86a8d2a37 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs @@ -54,16 +54,16 @@ namespace Tango.PPC.Jobs.Views public async void DisplaySampleDye() { - expander_sample_dye.IsExpanded = true; - await Task.Delay(500); - scrollViewer.ScrollToElement(expander_sample_dye); + //expander_sample_dye.IsExpanded = true; + //await Task.Delay(500); + //scrollViewer.ScrollToElement(expander_sample_dye); } public async void DisplayFineTuning() { - expander_fine_tuning.IsExpanded = true; - await Task.Delay(500); - scrollViewer.ScrollToElement(expander_fine_tuning); + //expander_fine_tuning.IsExpanded = true; + //await Task.Delay(500); + //scrollViewer.ScrollToElement(expander_fine_tuning); } public void OnNavigatedFrom() @@ -94,6 +94,10 @@ namespace Tango.PPC.Jobs.Views borderEditDock.Visibility = Visibility.Collapsed; } } + else if (_is_edit_docked) + { + FloatEditing(); + } } private void DockEditing() diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml index c615583bc..94abe6b83 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml @@ -214,14 +214,14 @@ - + - + @@ -235,7 +235,7 @@ - + @@ -314,21 +314,21 @@ - + - + - + @@ -342,7 +342,7 @@ - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/MachineSettingsModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/MachineSettingsModule.cs index 477340357..807a70b10 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/MachineSettingsModule.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/MachineSettingsModule.cs @@ -15,7 +15,7 @@ namespace Tango.PPC.MachineSettings /// Represents a PPC . /// /// - [PPCModule(2)] + [PPCModule(4)] public class MachineSettingsModule : PPCModuleBase { /// diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/ViewModels/MainViewVM.cs index 8ed512670..20cfd6bf4 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/ViewModels/MainViewVM.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Data; using Tango.BL; +using Tango.BL.Builders; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Commands; @@ -18,6 +19,8 @@ using Tango.PPC.Common; using Tango.PPC.Common.Connection; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Common.Messages; +using Tango.PPC.Common.OS; +using Tango.PPC.Common.UWF; using Tango.SharedUI.Components; using Tango.WiFi; @@ -29,8 +32,17 @@ namespace Tango.PPC.MachineSettings.ViewModels /// public class MainViewVM : PPCViewModel { + private TimeZoneInfo _previousTimeZone; + private bool _previousEnableUWF; + #region Properties + [TangoInject] + private IOperationSystemManager OperationSystemManager { get; set; } + + [TangoInject] + private IUnifiedWriteFilterManager UnifiedWriteFilterManager { get; set; } + private Machine _machine; public Machine Machine { @@ -52,6 +64,13 @@ namespace Tango.PPC.MachineSettings.ViewModels set { _selectedColorSpaces = value; RaisePropertyChangedAuto(); } } + private ObservableCollection _rmls; + public ObservableCollection Rmls + { + get { return _rmls; } + set { _rmls = value; RaisePropertyChangedAuto(); } + } + private bool _enableHotSpot; public bool EnableHotSpot { @@ -108,6 +127,69 @@ namespace Tango.PPC.MachineSettings.ViewModels set { _lockScreenPassword = value; RaisePropertyChangedAuto(); } } + private Rml _defaultRML; + public Rml DefaultRML + { + get { return _defaultRML; } + set { _defaultRML = value; RaisePropertyChangedAuto(); } + } + + private SpoolType _defaultSpoolType; + public SpoolType DefaultSpoolType + { + get { return _defaultSpoolType; } + set { _defaultSpoolType = value; RaisePropertyChangedAuto(); } + } + + private bool _synchronizeJobs; + public bool SynchronizeJobs + { + get { return _synchronizeJobs; } + set { _synchronizeJobs = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _synchronizeDiagnostics; + public bool SynchronizeDiagnostics + { + get { return _synchronizeDiagnostics; } + set { _synchronizeDiagnostics = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _autoCheckForUpdates; + public bool AutoCheckForUpdates + { + get { return _autoCheckForUpdates; } + set { _autoCheckForUpdates = value; RaisePropertyChangedAuto(); } + } + + private List _timeZones; + /// + /// Gets or sets the available time zones. + /// + public List TimeZones + { + get { return _timeZones; } + set { _timeZones = value; RaisePropertyChangedAuto(); } + } + + private TimeZoneInfo _selectedTimeZone; + /// + /// Gets or sets the selected time zone. + /// + public TimeZoneInfo SelectedTimeZone + { + get { return _selectedTimeZone; } + set { _selectedTimeZone = value; RaisePropertyChangedAuto(); } + } + + private bool _enableUWF; + public bool EnableUWF + { + get { return _enableUWF; } + set { _enableUWF = value; RaisePropertyChangedAuto(); } + } + + #endregion #region Commands @@ -122,12 +204,18 @@ namespace Tango.PPC.MachineSettings.ViewModels /// public RelayCommand DiscardCommand { get; set; } + /// + /// Gets or sets the synchronize command. + /// + public RelayCommand SynchronizeCommand { get; set; } + #endregion public MainViewVM() { SaveCommand = new RelayCommand(Save); DiscardCommand = new RelayCommand(Discard); + SynchronizeCommand = new RelayCommand(Synchronize, () => !MachineDataSynchronizer.IsSynchronizing && IsFree); } private void Discard() @@ -139,9 +227,9 @@ namespace Tango.PPC.MachineSettings.ViewModels { if (Validate()) { - Machine.SupportedJobTypes = SelectedJobTypes.SynchedSource.ToList(); - Machine.SupportedColorSpaces = SelectedColorSpaces.SynchedSource.ToList(); - Machine.MapPrimitivesWithStrings(MachineProvider.Machine); + Settings.SupportedJobTypes = SelectedJobTypes.SynchedSource.ToList(); + Settings.SupportedColorSpaces = SelectedColorSpaces.SynchedSource.ToList(); + Machine.MapPropertiesTo(MachineProvider.Machine, MappingFlags.NoReferenceTypes); Settings.EnableHotSpot = EnableHotSpot; Settings.HotSpotPassword = HotSpotPassword; @@ -150,10 +238,73 @@ namespace Tango.PPC.MachineSettings.ViewModels Settings.EnableLockScreen = EnableLockScreen; Settings.LockScreenTimeout = TimeSpan.FromMinutes(LockScreenTimeoutMinutes); Settings.LockScreenPassword = LockScreenPassword; + Settings.DefaultRmlGuid = DefaultRML?.Guid; + Settings.DefaultSpoolTypeGuid = DefaultSpoolType?.Guid; + Settings.SynchronizeJobs = SynchronizeJobs; + Settings.SynchronizeDiagnostics = SynchronizeDiagnostics; + Settings.AutoCheckForUpdates = AutoCheckForUpdates; + + MachineDataSynchronizer.IsEnabled = SynchronizeJobs || SynchronizeDiagnostics; + Settings.Save(); await MachineProvider.SaveMachine(); - await NavigationManager.NavigateBack(); + + bool isRestarting = false; + + if (_previousTimeZone.ToStringSafe() != SelectedTimeZone.ToStringSafe()) + { + if (await NotificationProvider.ShowQuestion("Changing the time zone requires the application to restart. Do you wish to restart the application?")) + { + try + { + LogManager.Log($"Setting new time zone to '{SelectedTimeZone.ToString()}'."); + NotificationProvider.SetGlobalBusyMessage("Setting new time zone..."); + await OperationSystemManager.ChangeTimeZone(SelectedTimeZone); + NotificationProvider.ReleaseGlobalBusyMessage(); + isRestarting = true; + ApplicationManager.Restart(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error changing the time zone."); + NotificationProvider.ReleaseGlobalBusyMessage(); + await NotificationProvider.ShowError($"Error setting timezone.\n{ex.FlattenMessage()}"); + } + } + } + + if (_previousEnableUWF != EnableUWF) + { + await NotificationProvider.ShowWarning("Changes to disk protection (UWF) will take effect only after a full system restart."); + + try + { + LogManager.Log($"Changing UWF mode to '{EnableUWF}'."); + if (EnableUWF) + { + NotificationProvider.SetGlobalBusyMessage("Enabling disk protection (UWF)..."); + await UnifiedWriteFilterManager.Enable(); + } + else + { + NotificationProvider.SetGlobalBusyMessage("Disabling disk protection (UWF)..."); + await UnifiedWriteFilterManager.Disable(); + } + NotificationProvider.ReleaseGlobalBusyMessage(); + } + catch (Exception ex) + { + NotificationProvider.ReleaseGlobalBusyMessage(); + LogManager.Log(ex, "Error setting UWF mode."); + await NotificationProvider.ShowError($"Could not change the disk protection mode\n{ex.FlattenMessage()}"); + } + } + + if (!isRestarting) + { + await NavigationManager.NavigateBack(); + } } } @@ -167,10 +318,29 @@ namespace Tango.PPC.MachineSettings.ViewModels /// public override void OnApplicationStarted() { + try + { + TimeZones = OperationSystemManager.GetAvailableTimeZones().ToList(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error retrieving available time zones."); + } + } + public async override void OnApplicationReady() + { + base.OnApplicationReady(); + MachineDataSynchronizer.SynchronizationStarted += (_, __) => InvalidateRelayCommands(); + MachineDataSynchronizer.SynchronizationEnded += (_, __) => InvalidateRelayCommands(); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + Rmls = await new RmlsCollectionBuilder(db).SetAll().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).BuildAsync(); + } } - public override void OnNavigatedTo() + public async override void OnNavigatedTo() { base.OnNavigatedTo(); @@ -195,8 +365,29 @@ namespace Tango.PPC.MachineSettings.ViewModels LockScreenTimeoutMinutes = (int)Settings.LockScreenTimeout.TotalMinutes; LockScreenPassword = Settings.LockScreenPassword; - SelectedJobTypes = new SelectedObjectCollection(Enum.GetValues(typeof(JobTypes)).Cast().ToObservableCollection(), Machine.SupportedJobTypes.ToObservableCollection()); - SelectedColorSpaces = new SelectedObjectCollection(Enum.GetValues(typeof(ColorSpaces)).Cast().Where(x => x.IsUserSpace()).ToObservableCollection(), Machine.SupportedColorSpaces.ToObservableCollection()); + SelectedJobTypes = new SelectedObjectCollection(Enum.GetValues(typeof(JobTypes)).Cast().ToObservableCollection(), Settings.SupportedJobTypes.ToObservableCollection()); + SelectedColorSpaces = new SelectedObjectCollection(Enum.GetValues(typeof(ColorSpaces)).Cast().Where(x => x.IsUserSpace()).ToObservableCollection(), Settings.SupportedColorSpaces.ToObservableCollection()); + + DefaultRML = Adapter.Rmls.SingleOrDefault(x => x.Guid == Settings.DefaultRmlGuid); + DefaultSpoolType = Adapter.SpoolTypes.SingleOrDefault(x => x.Guid == Settings.DefaultSpoolTypeGuid); + + SynchronizeJobs = Settings.SynchronizeJobs; + SynchronizeDiagnostics = Settings.SynchronizeDiagnostics; + + AutoCheckForUpdates = Settings.AutoCheckForUpdates; + + SelectedTimeZone = TimeZones.SingleOrDefault(x => x.StandardName == TimeZone.CurrentTimeZone.StandardName); + _previousTimeZone = SelectedTimeZone; + + try + { + EnableUWF = await UnifiedWriteFilterManager.IsEnabled(); + _previousEnableUWF = EnableUWF; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error getting UWF status."); + } } private async void OnEnableRemoteAssistanceChanged() @@ -271,5 +462,29 @@ namespace Tango.PPC.MachineSettings.ViewModels { ExternalBridgeService.Enabled = EnableExternalBridge; } + + private async void Synchronize() + { + try + { + IsFree = false; + NotificationProvider.SetGlobalBusyMessage("Synchronizing..."); + + await MachineDataSynchronizer.Synchronize(); + + NotificationProvider.ReleaseGlobalBusyMessage(); + await NotificationProvider.ShowSuccess("Synchronization completed successfully."); + } + catch (Exception ex) + { + NotificationProvider.ReleaseGlobalBusyMessage(); + await NotificationProvider.ShowError($"Error occurred while trying to synchronize.\n{ex.FlattenMessage()}"); + } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + IsFree = true; + } + } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml index dd5f89bb2..ba3516be4 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml @@ -5,15 +5,19 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" + xmlns:keyboard="clr-namespace:Tango.Touch.Keyboard;assembly=Tango.Touch" + xmlns:sys="clr-namespace:System.Collections;assembly=mscorlib" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:vm="clr-namespace:Tango.PPC.MachineSettings.ViewModels" xmlns:connectivity="clr-namespace:Tango.PPC.Common.Connectivity;assembly=Tango.PPC.Common" + xmlns:adapters="clr-namespace:Tango.Transport.Adapters;assembly=Tango.Transport" xmlns:global="clr-namespace:Tango.PPC.MachineSettings" + xmlns:integrationPMR="clr-namespace:Tango.PMR.Integration;assembly=Tango.PMR" xmlns:local="clr-namespace:Tango.PPC.MachineSettings.Views" mc:Ignorable="d" - d:DesignHeight="2500" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + d:DesignHeight="4500" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - + @@ -83,7 +87,7 @@ - + Supported Job Types @@ -136,14 +140,14 @@ - Default Thread Type - + Default Thread + - + Default Spool + Default Segment Length - + @@ -195,6 +199,172 @@ + + + + + + + + Auto Update Check + + + + Automatically check for software and database updates. + + + + + + + + + Synchronize Jobs + + + + Synchronize your jobs with twine's cloud services. + + + + + + + + + Synchronize Diagnostics Data + + + + Help us improve your experience using this system. + + + + + + + + + + Once enabled, synchronization occurs automatically in the background. you can choose to synchronize right now. + + + Synchronize Now + + + + + + + + + + Time Zone + + + + + + + + + + + + + + Embedded COM Port + + + + + Emergency COM Port + + + + + Enable Emergency Screen + + + + + Enable Embedded Debug Logs + + + + + Enable Automatic Thread Loading Support + + + + + Display PowerUp Screen + + + + + Enable Job Liquid Quantity Validation + + + + + Always Start in Technician Mode + + + + + Enable External Bridge SignalR + + + + + Auto Update Check Interval Minutes + + + + + Bypass Internet Connectivity Checks + + + + + Gradient Resolution CM + + + + + Enable Insights + + + + + Insights Sampling Interval (sec) + + + + + Insights Storage Cleanup Interval (min) + + + + + Insights Max Storage Duration (days) + + + + + Enable UWF (Disk Protection) + + + + + + + Please restart the application for advanced settings to take effect. + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/App.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/App.xaml new file mode 100644 index 000000000..cb7592abd --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/App.xaml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/HomingMotorCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/HomingMotorCommand.cs new file mode 100644 index 000000000..d3f44fe7e --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/HomingMotorCommand.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public abstract class HomingMotorCommand : MaintenanceCommand + { + public HardwareMotorType Motor { get; set; } + + public MotorDirection Direction { get; set; } + + public double Speed { get; set; } + + public String HomingMessage { get; set; } + + public String ErrorMessage { get; set; } + + public String SuccessMessage { get; set; } + + public HomingMotorCommand(HardwareMotorType motor, + MotorDirection direction, + double speed, + string homingMessage, + string errorMessage, + string successMessage) + { + Motor = motor; + Direction = direction; + Speed = speed; + HomingMessage = homingMessage; + ErrorMessage = errorMessage; + SuccessMessage = successMessage; + } + + protected override void OnExecute() + { + IsEnabled = false; + + try + { + NotificationProvider.SetGlobalBusyMessage(HomingMessage); + + MachineProvider.MachineOperator.StartMotorHoming(new PMR.Diagnostics.MotorHomingRequest() + { + Direction = Direction, + MotorType = Motor, + Speed = Speed, + }).Subscribe((response) => + { + //Next + }, (ex) => + { + //Error + IsEnabled = true; + NotificationProvider.ReleaseGlobalBusyMessage(); + LogManager.Log(ex, ErrorMessage); + NotificationProvider.ShowError(ex.FlattenMessage()); + }, () => + { + //Complete + IsEnabled = true; + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowSuccess(SuccessMessage); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, ErrorMessage); + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowError(ex.FlattenMessage()); + IsEnabled = true; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseDyeingHeadCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseDyeingHeadCommand.cs new file mode 100644 index 000000000..5c482e04c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseDyeingHeadCommand.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.Operation; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public class OpenCloseDyeingHeadCommand : OpenCloseMotorCommand + { + public OpenCloseDyeingHeadCommand() : base( + HardwareMotorType.MotoDhLid, + MotorDirection.Backward, + 400, + 400, + MotorState.Closed, + "Opening dyeing head lid...", + "Closing dyeing head lid...", + "Error opening dyeing head lid.", + "Error closing dyeing head lid.", + "The dyeing head lid is now opened.", + "The dyeing head lid is now closed." + ) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseLeftLeadingWheelsCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseLeftLeadingWheelsCommand.cs new file mode 100644 index 000000000..b0d8c1dc5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseLeftLeadingWheelsCommand.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public class OpenCloseLeftLeadingWheelsCommand : OpenCloseMotorCommand + { + public OpenCloseLeftLeadingWheelsCommand() : base( + HardwareMotorType.MotoLloading, + MotorDirection.Backward, + 250, + 250, + MotorState.Closed, + "Opening left leading wheels...", + "Closing left leading wheels...", + "Error opening left leading wheels.", + "Error closing left leading wheels.", + "The left leading wheels are now opened.", + "The left leading wheels are now closed." + ) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseMotorCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseMotorCommand.cs new file mode 100644 index 000000000..149c3675d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseMotorCommand.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public abstract class OpenCloseMotorCommand : MaintenanceCommand + { + public enum MotorState + { + Closed, + Opened, + } + + public HardwareMotorType Motor { get; set; } + + public MotorDirection OpenDirection { get; set; } + + public MotorDirection CloseDirection + { + get + { + return OpenDirection == MotorDirection.Forward ? MotorDirection.Backward : MotorDirection.Forward; + } + } + + public double OpeningSpeed { get; set; } + + public double ClosingSpeed { get; set; } + + public String OpeningMessage { get; set; } + + public String ClosingMessage { get; set; } + + public String OpeningErrorMessage { get; set; } + + public String ClosingErrorMessage { get; set; } + + public String OpeningSuccessMessage { get; set; } + + public String ClosingSuccessMessage { get; set; } + + public OpenCloseMotorCommand( + HardwareMotorType motor, + MotorDirection openDirection, + double openingSpeed, + double closingSpeed, + MotorState defaultState, + String openingMessage, + String closingMessage, + String openingErrorMessage, + String closingErrorMessage, + String openingSuccessMessage, + String closingSuccessMessage) + { + + Motor = motor; + OpenDirection = openDirection; + OpeningSpeed = openingSpeed; + ClosingSpeed = closingSpeed; + State = defaultState; + OpeningMessage = openingMessage; + ClosingMessage = closingMessage; + OpeningErrorMessage = openingErrorMessage; + ClosingErrorMessage = closingErrorMessage; + OpeningSuccessMessage = openingSuccessMessage; + ClosingSuccessMessage = closingSuccessMessage; + } + + protected override void OnExecute() + { + if (State == MotorState.Closed) + { + IsEnabled = false; + + try + { + NotificationProvider.SetGlobalBusyMessage(OpeningMessage); + + MachineProvider.MachineOperator.StartMotorHoming(new PMR.Diagnostics.MotorHomingRequest() + { + Direction = OpenDirection, + MotorType = Motor, + Speed = OpeningSpeed, + }).Subscribe((response) => + { + //Next + }, (ex) => + { + //Error + IsEnabled = true; + NotificationProvider.ReleaseGlobalBusyMessage(); + LogManager.Log(ex, OpeningErrorMessage); + NotificationProvider.ShowError(ex.FlattenMessage()); + }, () => + { + //Complete + IsEnabled = true; + State = MotorState.Opened; + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowSuccess(OpeningSuccessMessage); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, OpeningErrorMessage); + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowError(ex.FlattenMessage()); + IsEnabled = true; + } + } + else + { + IsEnabled = false; + + try + { + NotificationProvider.SetGlobalBusyMessage(ClosingMessage); + + MachineProvider.MachineOperator.StartMotorHoming(new PMR.Diagnostics.MotorHomingRequest() + { + Direction = CloseDirection, + MotorType = Motor, + Speed = ClosingSpeed, + }).Subscribe((response) => + { + //Next + }, (ex) => + { + //Error + IsEnabled = true; + NotificationProvider.ReleaseGlobalBusyMessage(); + LogManager.Log(ex, ClosingErrorMessage); + NotificationProvider.ShowError(ex.FlattenMessage()); + }, () => + { + //Complete + IsEnabled = true; + State = MotorState.Closed; + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowSuccess(ClosingSuccessMessage); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, ClosingErrorMessage); + NotificationProvider.ReleaseGlobalBusyMessage(); + NotificationProvider.ShowError(ex.FlattenMessage()); + IsEnabled = true; + } + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseRightLeadingWheelsCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseRightLeadingWheelsCommand.cs new file mode 100644 index 000000000..ced9eea60 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseRightLeadingWheelsCommand.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public class OpenCloseRightLeadingWheelsCommand : OpenCloseMotorCommand + { + public OpenCloseRightLeadingWheelsCommand() : base( + HardwareMotorType.MotoRloading, + MotorDirection.Backward, + 250, + 250, + MotorState.Closed, + "Opening right leading wheels...", + "Closing right leading wheels...", + "Error opening right leading wheels.", + "Error closing right leading wheels.", + "The right leading wheels are now opened.", + "The right leading wheels are now closed." + ) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/ResetThreadLoadingCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/ResetThreadLoadingCommand.cs new file mode 100644 index 000000000..0078cd546 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/ResetThreadLoadingCommand.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; +using Tango.PMR.Hardware; + +namespace Tango.PPC.Maintenance.Commands +{ + public class ResetThreadLoadingCommand : HomingMotorCommand + { + public ResetThreadLoadingCommand() : base( + HardwareMotorType.MotoDryerLoadarm, + MotorDirection.Backward, + 200, + "Resetting thread loading arm...", + "Error resetting thread loading arm.", + "Thread loading arm in now in place.") + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Controls/StateTouchButton.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Controls/StateTouchButton.cs new file mode 100644 index 000000000..9a259482b --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Controls/StateTouchButton.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.Touch.Controls; + +namespace Tango.PPC.Maintenance.Controls +{ + public class ButtonState : DependencyObject + { + public Object Value + { + get { return (Object)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + public static readonly DependencyProperty ValueProperty = + DependencyProperty.Register("Value", typeof(Object), typeof(ButtonState), new PropertyMetadata(null)); + + public Object Content + { + get { return (Object)GetValue(ContentProperty); } + set { SetValue(ContentProperty, value); } + } + public static readonly DependencyProperty ContentProperty = + DependencyProperty.Register("Content", typeof(Object), typeof(ButtonState), new PropertyMetadata(null)); + } + + [ContentProperty(nameof(States))] + public class StateTouchButton : TouchButton + { + public ObservableCollection States + { + get { return (ObservableCollection)GetValue(StatesProperty); } + set { SetValue(StatesProperty, value); } + } + public static readonly DependencyProperty StatesProperty = + DependencyProperty.Register("States", typeof(ObservableCollection), typeof(StateTouchButton), new PropertyMetadata(null, (d, e) => (d as StateTouchButton).OnStatesChanged())); + + public Object SelectedState + { + get { return (Object)GetValue(SelectedStateProperty); } + set { SetValue(SelectedStateProperty, value); } + } + public static readonly DependencyProperty SelectedStateProperty = + DependencyProperty.Register("SelectedState", typeof(Object), typeof(StateTouchButton), new PropertyMetadata(null, (d, e) => (d as StateTouchButton).OnSelectedStateChanged())); + + public StateTouchButton() + { + States = new ObservableCollection(); + } + + private void OnStatesChanged() + { + if (States != null) + { + States.CollectionChanged -= States_CollectionChanged; + States.CollectionChanged += States_CollectionChanged; + OnSelectedStateChanged(); + } + } + + private void OnSelectedStateChanged() + { + if (SelectedState == null) + { + Content = null; + return; + } + + if (States != null) + { + var converter = TypeDescriptor.GetConverter(SelectedState.GetType()); + var matchingState = States.OfType().ToList().FirstOrDefault(x => x.Value != null && converter.ConvertFrom(x.Value).Equals(SelectedState)); + if (matchingState != null) + { + Content = matchingState.Content; + } + else + { + Content = null; + } + } + else + { + Content = null; + } + } + + private void States_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + OnSelectedStateChanged(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToBrushConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToBrushConverter.cs new file mode 100644 index 000000000..c33efdca6 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToBrushConverter.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Tango.BL.Entities; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Converters +{ + public class LiquidTypeToBrushConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is LiquidType) + { + LiquidType type = value as LiquidType; + switch (type.Type) + { + case BL.Enumerations.LiquidTypes.Lubricant: + { + + ImageBrush lubricantBrush = new ImageBrush() { Stretch = Stretch.None, TileMode = TileMode.Tile, ViewportUnits = BrushMappingMode.Absolute }; + + BitmapSource bit_source = ResourceHelper.GetImageFromResources(@"Images/lubricant2.png"); + var targetBitmap = new WriteableBitmap(new TransformedBitmap(bit_source, new ScaleTransform(0.2, 0.2))); + lubricantBrush.ImageSource = targetBitmap; + lubricantBrush.Viewport = new System.Windows.Rect(2, 2, targetBitmap.Width, targetBitmap.Height); + return lubricantBrush; + } + case BL.Enumerations.LiquidTypes.Cleaner: + { + ImageBrush cleanerBrush = new ImageBrush() { Stretch = Stretch.None, TileMode = TileMode.Tile, ViewportUnits = BrushMappingMode.Absolute }; + BitmapSource bit_source = ResourceHelper.GetImageFromResources(@"Images/cl-full.png"); + var targetBitmap = new WriteableBitmap(new TransformedBitmap(bit_source, new ScaleTransform(0.3, 0.3))); + + cleanerBrush.ImageSource = targetBitmap; + cleanerBrush.Viewport = new System.Windows.Rect(0, 0, targetBitmap.Width, targetBitmap.Height); + return cleanerBrush; + } + case BL.Enumerations.LiquidTypes.Yellow: + { + return new SolidColorBrush(Color.FromRgb(232, 225, 12)); + } + case BL.Enumerations.LiquidTypes.Cyan: + { + return new SolidColorBrush(Color.FromRgb(22, 98, 235)); + } + case BL.Enumerations.LiquidTypes.Magenta: + { + return new SolidColorBrush(Color.FromRgb(237, 0, 140)); + } + } + + + return new SolidColorBrush(type.LiquidTypeColor); + } + return null; + + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + } +} + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToShortNameConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToShortNameConverter.cs new file mode 100644 index 000000000..15041bf17 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToShortNameConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.BL.Entities; + +namespace Tango.PPC.Maintenance.Converters +{ + class LiquidTypeToShortNameConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is LiquidType) + { + LiquidType type = value as LiquidType; + switch (type.Type) + { + case BL.Enumerations.LiquidTypes.Cleaner: + return "CL"; + case BL.Enumerations.LiquidTypes.TransparentInk: + return "TI"; + case BL.Enumerations.LiquidTypes.Black: + return "K"; + } + return type.Name.First().ToString(); + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/MidTankLevelToElementHeightConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/MidTankLevelToElementHeightConverter.cs new file mode 100644 index 000000000..94d1ed8b8 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/MidTankLevelToElementHeightConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Integration.Operation; + +namespace Tango.PPC.Maintenance.Converters +{ + public class MidTankLevelToElementHeightConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + double parentActualHeight = (double)values[0]; + double midTankLevel = Math.Min((double)values[1], MachineOperator.MAX_MIDTANK_LITERS); + //var test = (parentActualHeight - (midTankLevel / MachineOperator.MAX_MIDTANK_LITERS) * parentActualHeight); + return (parentActualHeight - (midTankLevel / MachineOperator.MAX_MIDTANK_LITERS) * parentActualHeight); + } + catch + { + return 0d; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/StringToFirstLetterConverter.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/StringToFirstLetterConverter.cs new file mode 100644 index 000000000..0922af78d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/StringToFirstLetterConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.PPC.Maintenance.Converters +{ + public class StringToFirstLetterConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value != null && value.ToString().Length > 1) + { + return value.ToString().First().ToString(); + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml new file mode 100644 index 000000000..98be45608 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml @@ -0,0 +1,66 @@ + + + + + Dispense Cleaning Liquid + + + + + Please put on safety glasses + + + + + + START + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml.cs new file mode 100644 index 000000000..6f1ebb4ed --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Maintenance.Dialogs +{ + /// + /// Interaction logic for PowerUpView.xaml + /// + public partial class CleanerDispensingView : UserControl + { + public CleanerDispensingView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingViewVM.cs new file mode 100644 index 000000000..e37be417f --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingViewVM.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Integration.Operation; +using Tango.PMR.Printing; +using Tango.PPC.Common; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.Settings; +using Tango.SharedUI; + +namespace Tango.PPC.Maintenance.Dialogs +{ + public class CleanerDispensingViewVM : DialogViewVM + { + private const int JOGGING_TIME_SEC = 10; + private const int JOGGING_SPEED = 400; + + [TangoInject] + public IMachineProvider MachineProvider { get; set; } + + [TangoInject] + private INotificationProvider NotificationProvider { get; set; } + + private bool _isStarted; + public bool IsStarted + { + get { return _isStarted; } + set { _isStarted = value; RaisePropertyChangedAuto(); } + } + + private bool _isCompleted; + public bool IsCompleted + { + get { return _isCompleted; } + set { _isCompleted = value; RaisePropertyChangedAuto(); } + } + + private bool _isFailed; + public bool IsFailed + { + get { return _isFailed; } + set { _isFailed = value; RaisePropertyChangedAuto(); } + } + + private String _status; + public String Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand StartCommand { get; set; } + + public CleanerDispensingViewVM() + { + Status = "Ready..."; + CanClose = true; + TangoIOC.Default.Inject(this); + StartCommand = new RelayCommand(Start, () => !IsStarted); + } + + private async void Start() + { + try + { + CanClose = false; + IsStarted = true; + IsCompleted = false; + IsFailed = false; + InvalidateRelayCommands(); + + Status = "Dispensing cleaner liquid..."; + + var cleanerPack = MachineProvider.Machine.Configuration.NoneEmptyIdsPacks.FirstOrDefault(x => x.LiquidType.Type == BL.Enumerations.LiquidTypes.Cleaner); + + if (cleanerPack == null) + { + throw new InvalidOperationException("'Cleaner' liquid type was not found on the machine configuration."); + } + + var cleanerIndex = cleanerPack.PackIndex; + + await MachineProvider.MachineOperator.StartDispenserJogging(new PMR.Diagnostics.DispenserJoggingRequest() + { + Direction = PMR.Diagnostics.MotorDirection.Forward, + Speed = JOGGING_SPEED, + Index = cleanerIndex + }); + + await Task.Delay(TimeSpan.FromSeconds(JOGGING_TIME_SEC)); + + await MachineProvider.MachineOperator.StopDispenserJogging(new PMR.Diagnostics.DispenserAbortJoggingRequest() + { + Index = cleanerIndex + }); + + IsCompleted = true; + Status = "Cleaner liquid dispensing completed."; + } + catch (Exception ex) + { + Status = "Cleaner liquid dispensing failed."; + IsFailed = true; + await NotificationProvider.ShowError($"Error occurred while trying to perform the cleaner liquid dispensing.\n{ex.FlattenMessage()}"); + } + finally + { + CanClose = true; + IsStarted = false; + } + } + + protected override void Cancel() + { + if (CanClose) + { + base.Cancel(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml new file mode 100644 index 000000000..f640d5cec --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml @@ -0,0 +1,56 @@ + + + + + Head Cleaning + + + + + + + + + START + ABORT + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml.cs new file mode 100644 index 000000000..c715bf5cf --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Maintenance.Dialogs +{ + /// + /// Interaction logic for PowerUpView.xaml + /// + public partial class HeadCleaningView : UserControl + { + public HeadCleaningView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningViewVM.cs new file mode 100644 index 000000000..59d119f21 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningViewVM.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Integration.Operation; +using Tango.PMR.Printing; +using Tango.PPC.Common; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.Settings; +using Tango.SharedUI; + +namespace Tango.PPC.Maintenance.Dialogs +{ + public class HeadCleaningViewVM : DialogViewVM + { + private HeadCleaningHandler _handler; + + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + [TangoInject] + private INotificationProvider NotificationProvider { get; set; } + + private bool _isStarted; + public bool IsStarted + { + get { return _isStarted; } + set { _isStarted = value; RaisePropertyChangedAuto(); } + } + + private bool _isCompleted; + public bool IsCompleted + { + get { return _isCompleted; } + set { _isCompleted = value; RaisePropertyChangedAuto(); } + } + + private bool _isAborting; + public bool IsAborting + { + get { return _isAborting; } + set { _isAborting = value; RaisePropertyChangedAuto(); } + } + + private bool _isFailed; + public bool IsFailed + { + get { return _isFailed; } + set { _isFailed = value; RaisePropertyChangedAuto(); } + } + + private StartHeadCleaningResponse _status; + public StartHeadCleaningResponse Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand StartCommand { get; set; } + public RelayCommand AbortCommand { get; set; } + + public HeadCleaningViewVM() + { + CanClose = true; + TangoIOC.Default.Inject(this); + StartCommand = new RelayCommand(Start); + AbortCommand = new RelayCommand(Abort); + } + + private async void Start() + { + try + { + CanClose = false; + IsStarted = true; + _handler = await MachineProvider.MachineOperator.PerformHeadCleaning(); + _handler.Completed += _handler_Completed; + _handler.Failed += _handler_Failed; + _handler.StatusChanged += _handler_StatusChanged; + } + catch (Exception ex) + { + _handler_Failed(this, ex); + } + } + + private void _handler_StatusChanged(object sender, HeadCleaningStatusChangedEventArgs e) + { + Status = e.Status; + } + + private void _handler_Failed(object sender, Exception e) + { + IsStarted = false; + IsFailed = true; + InvokeUI(() => + { + CanClose = true; + Cancel(); + NotificationProvider.ShowError($"Error occurred while trying to perform the head cleaning.\n{e.FlattenMessage()}"); + }); + } + + private void _handler_Completed(object sender, EventArgs e) + { + IsStarted = false; + IsCompleted = true; + InvokeUI(() => + { + Accept(); + NotificationProvider.ShowSuccess("Head cleaning completed successfully."); + }); + } + + protected override void Cancel() + { + if (CanClose) + { + base.Cancel(); + } + } + + private async void Abort() + { + IsAborting = true; + try + { + await _handler.Abort(); + CanClose = true; + Cancel(); + await NotificationProvider.ShowInfo("Head cleaning aborted."); + } + catch (Exception ex) + { + if (!IsCompleted) + { + CanClose = true; + IsAborting = false; + await NotificationProvider.ShowError($"Error occurred while trying to abort the head cleaning.\n{ex.FlattenMessage()}"); + } + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs new file mode 100644 index 000000000..438375c72 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; + +namespace Tango.PPC.Maintenance +{ + public abstract class GuideBase + { + public abstract String Name { get; } + public abstract BitmapSource Icon { get; } + public abstract String Image { get; } + public abstract List Steps { get; } + + protected virtual List GetStepsFromResource(String key) + { + List list = new List(); + + var arr = (Application.Current.Resources[key] as Array); + + foreach (var item in arr) + { + list.Add(new GuideStep() + { + Text = item + }); + } + + return list; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs new file mode 100644 index 000000000..71a70d9db --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Maintenance +{ + public class GuideStep : ExtendedObject + { + public Object Text { get; set; } + + private bool _isChecked; + public bool IsChecked + { + get { return _isChecked; } + set { _isChecked = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/HandleWasteCartridgeGuide.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/HandleWasteCartridgeGuide.cs new file mode 100644 index 000000000..a4820e349 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/HandleWasteCartridgeGuide.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Guides +{ + public class HandleWasteCartridgeGuide : GuideBase + { + public override string Name => "Handling the Waste Cartridges"; + public override String Image => "../Images/Guides/Residue-Cartridges-A.gif"; + + private BitmapSource _icon; + public override BitmapSource Icon + { + get + { + if (_icon == null) + { + _icon = ResourceHelper.GetImageFromResources("Images/Guides/handling-the-waste-cartridges.png"); + } + return _icon; + } + } + + private List _steps; + public override List Steps + { + get + { + if (_steps == null) + { + _steps = GetStepsFromResource("HandleWasteCartridge"); + } + return _steps; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadInkCartridgeGuide.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadInkCartridgeGuide.cs new file mode 100644 index 000000000..1a6ed8321 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadInkCartridgeGuide.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Guides +{ + public class LoadInkCartridgeGuide : GuideBase + { + public override string Name => "Loading an Ink Cartridge"; + public override String Image => "../Images/Guides/Loading-an-Ink-Cartridge.gif"; + + private BitmapSource _icon; + public override BitmapSource Icon + { + get + { + if (_icon == null) + { + _icon = ResourceHelper.GetImageFromResources("Images/Guides/loading-an-ink-cartridge.png"); + } + return _icon; + } + } + + private List _steps; + public override List Steps + { + get + { + if (_steps == null) + { + _steps = GetStepsFromResource("LoadInkCartridge"); + } + return _steps; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadNewThreadGuide.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadNewThreadGuide.cs new file mode 100644 index 000000000..d5115a748 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadNewThreadGuide.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Guides +{ + public class LoadNewThreadGuide : GuideBase + { + public override string Name => "Loading New Thread"; + public override String Image => "../Images/Guides/Loading-New-Thread.gif"; + + private BitmapSource _icon; + public override BitmapSource Icon + { + get + { + if (_icon == null) + { + _icon = ResourceHelper.GetImageFromResources("Images/Guides/loading-new-thread.png"); + } + return _icon; + } + } + + private List _steps; + public override List Steps + { + get + { + if (_steps == null) + { + _steps = GetStepsFromResource("LoadNewThread"); + } + return _steps; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceAirFilterGuide.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceAirFilterGuide.cs new file mode 100644 index 000000000..d335867ca --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceAirFilterGuide.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Guides +{ + public class ReplaceAirFilterGuide : GuideBase + { + public override string Name => "Replacing the Air Filter"; + public override String Image => "../Images/Guides/Replacing-the-Air-Filter.gif"; + + private BitmapSource _icon; + public override BitmapSource Icon + { + get + { + if (_icon == null) + { + _icon = ResourceHelper.GetImageFromResources("Images/Guides/replacing-the-air-filter.png"); + } + return _icon; + } + } + + private List _steps; + public override List Steps + { + get + { + if (_steps == null) + { + _steps = GetStepsFromResource("ReplaceAirFilter"); + } + return _steps; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceThreadGuide.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceThreadGuide.cs new file mode 100644 index 000000000..ecc3f6026 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceThreadGuide.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance.Guides +{ + public class ReplaceThreadGuide : GuideBase + { + public override string Name => "Replacing the Thread"; + public override String Image => "../Images/Guides/Replacing-the-Thread.gif"; + + private BitmapSource _icon; + public override BitmapSource Icon + { + get + { + if (_icon == null) + { + _icon = ResourceHelper.GetImageFromResources("Images/Guides/replacing-the-thread.png"); + } + return _icon; + } + } + + private List _steps; + public override List Steps + { + get + { + if (_steps == null) + { + _steps = GetStepsFromResource("ReplaceThread"); + } + return _steps; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Helpers/GuideHelper.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Helpers/GuideHelper.cs new file mode 100644 index 000000000..32518974d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Helpers/GuideHelper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.PPC.Maintenance.Helpers +{ + public static class GuideHelper + { + public static List CreateAllGuides() + { + var resource = new ResourceDictionary + { + Source = new Uri("/Tango.PPC.Maintenance;component/Resources/Guides.xaml", UriKind.RelativeOrAbsolute) + }; + + Application.Current.Resources.MergedDictionaries.Add(resource); + + List guides = new List(); + + var callingAssembly = typeof(GuideHelper).Assembly; + + foreach (var guideType in callingAssembly.DefinedTypes.Where(x => x.Namespace == "Tango.PPC.Maintenance.Guides")) + { + guides.Add(Activator.CreateInstance(guideType) as GuideBase); + } + + return guides; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gif b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gif new file mode 100644 index 000000000..b6a974084 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gif differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gif b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gif new file mode 100644 index 000000000..7087ebc64 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gif differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gif b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gif new file mode 100644 index 000000000..023adb4a9 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gif differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gif b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gif new file mode 100644 index 000000000..8ab544d8b Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gif differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gif b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gif new file mode 100644 index 000000000..c310820b4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gif differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.png new file mode 100644 index 000000000..188e881bb Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.png new file mode 100644 index 000000000..4f4dfc375 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.png new file mode 100644 index 000000000..1f508261b Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.png new file mode 100644 index 000000000..277599070 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.png new file mode 100644 index 000000000..eb8f518a3 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.png new file mode 100644 index 000000000..e858c3075 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.png new file mode 100644 index 000000000..8fc4e1b33 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.png new file mode 100644 index 000000000..ff2411eb5 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.png new file mode 100644 index 000000000..08b9a7076 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.png new file mode 100644 index 000000000..a39b6f073 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.png new file mode 100644 index 000000000..6d14ec5dc Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.png new file mode 100644 index 000000000..5aaea8e6c Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.png new file mode 100644 index 000000000..17c3225ed Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.png new file mode 100644 index 000000000..b4ed45d1e Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.png new file mode 100644 index 000000000..13b9013d7 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.png new file mode 100644 index 000000000..373cb78c1 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.png new file mode 100644 index 000000000..3872a77e4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.png new file mode 100644 index 000000000..2607f4a26 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.png new file mode 100644 index 000000000..554c16305 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.png new file mode 100644 index 000000000..526284750 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.png new file mode 100644 index 000000000..0cc205a6c Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.png new file mode 100644 index 000000000..f67323dde Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.png new file mode 100644 index 000000000..5e6b505a3 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.png new file mode 100644 index 000000000..359e93d6d Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.png new file mode 100644 index 000000000..5d536e7ae Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceCommand.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceCommand.cs new file mode 100644 index 000000000..5c74d92cd --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceCommand.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Integration.Operation; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; + +namespace Tango.PPC.Maintenance +{ + public abstract class MaintenanceCommand : ExtendedObject + { + private IMachineProvider _machineProvider; + [TangoInject(Mode = TangoInjectMode.WhenAvailable)] + protected IMachineProvider MachineProvider + { + get { return _machineProvider; } + set + { + _machineProvider = value; RaisePropertyChangedAuto(); + _machineProvider.MachineOperator.StatusChanged += MachineOperator_StatusChanged; + } + } + + [TangoInject(Mode = TangoInjectMode.WhenAvailable)] + protected INotificationProvider NotificationProvider { get; set; } + + private RelayCommand _command; + public RelayCommand Command + { + get { return _command; } + set { _command = value; RaisePropertyChangedAuto(); } + } + + private bool _isEnabled; + public bool IsEnabled + { + get { return _isEnabled; } + set { _isEnabled = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private T _state; + public T State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private void MachineOperator_StatusChanged(object sender, MachineStatuses e) + { + InvalidateRelayCommands(); + } + + public MaintenanceCommand() + { + TangoIOC.Default.Inject(this); + IsEnabled = true; + Command = new RelayCommand(Execute, CanExecute); + } + + protected virtual bool CanExecute() + { + if (!IsEnabled) return false; + if (MachineProvider == null) return false; + if (!MachineProvider.MachineOperator.CanPrint) return false; + + return true; + } + + private void Execute() + { + OnExecute(); + } + + protected abstract void OnExecute(); + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceModule.cs new file mode 100644 index 000000000..18871ac78 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceModule.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.BL.Enumerations; +using Tango.PPC.Common; +using Tango.PPC.Maintenance.Views; +using Tango.SharedUI.Helpers; + +namespace Tango.PPC.Maintenance +{ + /// + /// Represents a PPC . + /// + /// + [PPCModule(3)] + public class MaintenanceModule : PPCModuleBase + { + /// + /// Gets the module name. + /// + public override string Name + { + get + { + return "Maintenance"; + } + } + + /// + /// Gets the module description. + /// + public override string Description + { + get + { + return "PPC maintenance module."; + } + } + + /// + /// Gets the module cover image. + /// + public override BitmapSource Image + { + get + { + return ResourceHelper.GetImageFromResources("Images/maintenance.png"); + } + } + + /// + /// Gets the module entry point view type. + /// + public override Type MainViewType + { + get + { + return typeof(MainView); + } + } + + /// + /// Gets the permission required to see and load this module. + /// + public override Permissions Permission + { + get + { + return Permissions.RunPPC; + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public override void Dispose() + { + //Dispose module here... + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/MidTankLevelModel.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/MidTankLevelModel.cs new file mode 100644 index 000000000..93af310ba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/MidTankLevelModel.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core; +using Tango.Integration.Operation; + +namespace Tango.PPC.Maintenance.Models +{ + public class MidTankLevelModel : ExtendedObject + { + public double Max { get; set; } + + private double _level; + public double Level + { + get { return _level; } + set { _level = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsLow)); RaisePropertyChanged(nameof(IsEmpty)); } + } + + public bool IsLow + { + get { return Level <= MachineOperator.LOW_MIDTANK_LITERS; } + } + + public bool IsEmpty + { + get { return Level <= MachineOperator.EMPTY_MIDTANK_LITERS; } + } + + public IdsPack IDSPack { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/OverallTemperatureModel.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/OverallTemperatureModel.cs new file mode 100644 index 000000000..694071d0d --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/OverallTemperatureModel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Integration.Operation; + +namespace Tango.PPC.Maintenance.Models +{ + public class OverallTemperatureModel : ExtendedObject + { + private double _temperature; + public double Temperature + { + get { return _temperature; } + set { _temperature = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsWarning)); RaisePropertyChanged(nameof(IsError)); } + } + + public bool IsWarning + { + get { return Temperature > MachineOperator.OVERALL_TEMPERATURE_WARNING; } + } + + public bool IsError + { + get { return Temperature >= MachineOperator.OVERALL_TEMPERATURE_ERROR; } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..52774bee8 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango Module")] +[assembly: AssemblyVersion("2.0.1.1407")] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.Designer.cs new file mode 100644 index 000000000..003dc17e5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Maintenance.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.PPC.Maintenance.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.resx b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.Designer.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.Designer.cs new file mode 100644 index 000000000..7b549e7b7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Maintenance.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.settings b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Resources/Guides.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Resources/Guides.xaml new file mode 100644 index 000000000..24e1e0d71 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Resources/Guides.xaml @@ -0,0 +1,60 @@ + + + + 1. Loading New Thread + 2. Wait for a message indicating the system is ready to load the thread + 3. Place a cone with un-dyed thread into the thread feeding unit + 4. Feed the thread along the thread groove to the winder + 5. Place an empty collecting cone into the thread winder + 6. Insert the end of the thread into the empty collecting cone + 7. On the TS-1800 panel, press LOAD again + + + + 1. On the TS-1800 panel, press LOAD + 2. Wait for a message indicating the system is ready to load the thread + 3. Place a cone with un-dyed thread into the thread feeding unit + 4. Feed the tread along the feeding path up to the top cover + 5. Feed the thread along the thread groove to the winder + 6. Place an empty collecting cone into the thread winder + 7. Insert the end of the thread into the empty collecting cone + 8. On the TS-1800 panel, press LOAD again + + + + 1. Cut the current thread just after the feeding cone + 2. Remove the current feeding cone + 3. Place the new feeding cone into the thread feeding unit + 4. Tie the new thread to the current thread + 5. Cut off the ends of the thread leaving a small knot + 6. On the TS-1800 panel, press and hold the JOG button + 7. Hold the JOG button until the knot appears at the collecting cone + 8. Cut the thread at the collecting cone after the knot + 9. Remove the collecting cone + 10. Place an empty collecting cone into the winder + 11. Insert the end of the new thread into the empty collecting cone + + + + 1. Open the air filter cover + 2. Remove the old air filter + 3. Insert a new air filter + 4. Close the air filter cover + + + + 1. Open the cartridge cover + 2. Insert a full ink cartridge into the ink-loading slot + 3. Close the cartridge cover + 4. When ink loading is complete, open the cartridge cover + 5. Remove the empty ink cartridge + 6. Remove the stopper from the residue-filling opening + 7. Place the stopper into its allocated position on the top side of the empty ink cartridge + 8. Put the empty ink cartridge into storage. Optional: if an empty recycling slot is available + 9. Insert the empty ink cartridge into the slot for ink recycling + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Tango.PPC.Maintenance.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Tango.PPC.Maintenance.csproj new file mode 100644 index 000000000..9dd45add4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Tango.PPC.Maintenance.csproj @@ -0,0 +1,320 @@ + + + + + Debug + AnyCPU + {011470AC-6BD6-4366-B5F2-C82C065D4A84} + library + Tango.PPC.Maintenance + Tango.PPC.Maintenance + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + true + full + false + ..\..\..\Build\PPC\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll + + + ..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll + + + ..\..\..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll + + + + + + ..\..\..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll + + + ..\..\..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll + + + ..\..\..\packages\System.Reactive.Linq.3.1.1\lib\net46\System.Reactive.Linq.dll + + + ..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + + + GlobalVersionInfo.cs + + + + + + + + + + + + + + CleanerDispensingView.xaml + + + HeadCleaningView.xaml + + + + + + + + + + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + GeneralGuideView.xaml + + + MaintenanceView.xaml + + + MainView.xaml + + + ResXFileCodeGenerator + Resources.Designer.cs + + + Designer + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {b112d89a-a106-41ae-a0c1-4abc84c477f5} + Tango.DragAndDrop + + + {4399af76-db52-4cfb-8020-6f85bdb29fd5} + Tango.Explorer + + + {4206ac58-3b57-4699-8835-90bf6db01a61} + Tango.Integration + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + + + {e4927038-348d-4295-aaf4-861c58cb3943} + Tango.PMR + + + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} + Tango.Settings + + + {8491d07b-c1f6-4b62-a412-41b9fd2d6538} + Tango.SharedUI + + + {fd86424c-6e84-491b-8df9-3d0f5c236a2a} + Tango.Touch + + + {74e700b0-1156-4126-be40-ee450d3c3026} + Tango.Transport + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + + + {04febb02-f782-4b96-b47d-f6902afa43be} + Tango.PPC.Storage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Themes/Generic.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Themes/Generic.xaml new file mode 100644 index 000000000..a77cc2281 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Themes/Generic.xaml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModelLocator.cs new file mode 100644 index 000000000..1db63a9e4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModelLocator.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.PPC.Maintenance.ViewModels; + +namespace Tango.PPC.Maintenance +{ + public static class ViewModelLocator + { + /// + /// Initializes a new instance of the ViewModelLocator class. + /// + static ViewModelLocator() + { + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + } + + /// + /// Gets the main view VM. + /// + public static MainViewVM MainViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + /// + /// Gets the maintenance view VM. + /// + public static MaintenanceViewVM MaintenanceViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + /// + /// Gets the general guide view VM. + /// + public static GeneralGuideViewVM GeneralGuideViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/GeneralGuideViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/GeneralGuideViewVM.cs new file mode 100644 index 000000000..fd0475817 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/GeneralGuideViewVM.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; +using Tango.PPC.Common.Navigation; + +namespace Tango.PPC.Maintenance.ViewModels +{ + public class GeneralGuideViewVM : PPCViewModel, INavigationObjectReceiver + { + private DateTime _lastTime; + + private GuideBase _guide; + public GuideBase Guide + { + get { return _guide; } + set { _guide = value; RaisePropertyChangedAuto(); } + } + + + public override void OnApplicationStarted() + { + _lastTime = DateTime.Now; + } + + public void OnNavigatedToWithObject(GuideBase guide) + { + if (Guide != guide || (DateTime.Now - _lastTime) > TimeSpan.FromHours(1)) + { + guide.Steps.ForEach(x => x.IsChecked = false); + } + + Guide = guide; + + _lastTime = DateTime.Now; + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..a614f7be2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MainViewVM.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; +using Tango.PPC.Maintenance.Views; + +namespace Tango.PPC.Maintenance.ViewModels +{ + /// + /// Represents the main view VM and entry point for . + /// + /// + public class MainViewVM : PPCViewModel + { + /// + /// Called when the application has been started + /// + public override void OnApplicationStarted() + { + //Start initializing here rather then in the constructor. + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + NavigationManager.NavigateTo(nameof(MaintenanceView), false); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MaintenanceViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MaintenanceViewVM.cs new file mode 100644 index 000000000..c0dc61150 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MaintenanceViewVM.cs @@ -0,0 +1,324 @@ +using Ionic.Zip; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Entity; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Explorer; +using Tango.Integration.Operation; +using Tango.Logging; +using Tango.PMR.Diagnostics; +using Tango.PMR.IFS; +using Tango.PMR.MachineStatus; +using Tango.PPC.Common; +using Tango.PPC.Maintenance.Commands; +using Tango.PPC.Maintenance.Dialogs; +using Tango.PPC.Maintenance.Helpers; +using Tango.PPC.Maintenance.Models; +using Tango.PPC.Maintenance.Views; +using Tango.PPC.Storage; + +namespace Tango.PPC.Maintenance.ViewModels +{ + public class MaintenanceViewVM : PPCViewModel + { + public class WasteStateModel : ExtendedObject + { + private CartridgeState _state; + public CartridgeState State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); } + } + + public CartridgeSlot Slot { get; set; } + } + + public ObservableCollection Guides { get; set; } + + public RelayCommand OpenGuideCommand { get; set; } + + private List _midTankLevels; + public List MidTankLevels + { + get { return _midTankLevels; } + set { _midTankLevels = value; RaisePropertyChangedAuto(); } + } + + private OverallTemperatureModel _overallTemperature; + public OverallTemperatureModel OverallTemperature + { + get { return _overallTemperature; } + set { _overallTemperature = value; RaisePropertyChangedAuto(); } + } + + private String _totalDyeTime; + public String TotalDyeTime + { + get { return _totalDyeTime; } + set { _totalDyeTime = value; RaisePropertyChangedAuto(); } + } + + private String _totalDyeMeters; + public String TotalDyeMeters + { + get { return _totalDyeMeters; } + set { _totalDyeMeters = value; RaisePropertyChangedAuto(); } + } + + private SpoolState _spoolState; + public SpoolState SpoolState + { + get { return _spoolState; } + set + { + if (_spoolState != value) + { + _spoolState = value; + RaisePropertyChangedAuto(); + } + } + } + + private List _wasteStates; + public List WasteStates + { + get { return _wasteStates; } + set { _wasteStates = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand ExportLogsCommand { get; set; } + + public OpenCloseDyeingHeadCommand OpenCloseDyeingHeadCommand { get; set; } + + public OpenCloseLeftLeadingWheelsCommand OpenCloseLeftLeadingWheelsCommand { get; set; } + + public OpenCloseRightLeadingWheelsCommand OpenCloseRightLeadingWheelsCommand { get; set; } + + public ResetThreadLoadingCommand ResetThreadLoadingCommand { get; set; } + + public RelayCommand HeadCleaningCommand { get; set; } + + public RelayCommand StartThreadLoadingCommand { get; set; } + + public RelayCommand StartThreadBreakCommand { get; set; } + + public RelayCommand DispenseCleanerLiquidCommand { get; set; } + + public MaintenanceViewVM() + { + Guides = new ObservableCollection(GuideHelper.CreateAllGuides()); + OverallTemperature = new OverallTemperatureModel(); + + OpenGuideCommand = new RelayCommand(OpenGuide); + ExportLogsCommand = new RelayCommand(ExportLogsToStorage); + + OpenCloseDyeingHeadCommand = new OpenCloseDyeingHeadCommand(); + OpenCloseLeftLeadingWheelsCommand = new OpenCloseLeftLeadingWheelsCommand(); + OpenCloseRightLeadingWheelsCommand = new OpenCloseRightLeadingWheelsCommand(); + ResetThreadLoadingCommand = new ResetThreadLoadingCommand(); + HeadCleaningCommand = new RelayCommand(PerformHeadCleaning, () => MachineProvider.MachineOperator.CanPrint); + StartThreadLoadingCommand = new RelayCommand(StartThreadLoadingWizard, () => MachineProvider.MachineOperator.CanPrint); + StartThreadBreakCommand = new RelayCommand(StartThreadBreakWizard, () => MachineProvider.MachineOperator.CanPrint); + + WasteStates = new List() + { + new WasteStateModel() { Slot = CartridgeSlot.WasteMiddle, State = CartridgeState.Absent }, + new WasteStateModel() { Slot = CartridgeSlot.WasteLower, State = CartridgeState.Absent } + }; + } + + public override void OnApplicationStarted() + { + MachineProvider.MachineOperator.InkFillingStatusChanged += MachineOperator_InkFillingStatusChanged; + MachineProvider.MachineOperator.MachineStatusChanged += MachineOperator_MachineStatusChanged; + MachineProvider.MachineOperator.MachineEventsStateProvider.EventsChanged += MachineEventsStateProvider_EventsChanged; + + DispenseCleanerLiquidCommand = new RelayCommand(DispenseCleanerLiquid, () => + { + if (MachineProvider.Machine.MachineHeadType == BL.Enumerations.HeadTypes.Arc) + { + return MachineProvider.MachineOperator.MachineEventsStateProvider.Events.Any(x => x.Type == BL.Enumerations.EventTypes.DYEING_HEAD_ARC_LID_IS_OPEN); + } + else + { + return MachineProvider.MachineOperator.MachineEventsStateProvider.Events.Any(x => x.Type == BL.Enumerations.EventTypes.DYEING_HEAD_COVER_IS_OPEN); + } + }); + + RaisePropertyChanged(nameof(DispenseCleanerLiquidCommand)); + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + + MidTankLevels = MachineProvider.Machine.Configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex).Select(x => new MidTankLevelModel() + { + Max = MachineOperator.MAX_MIDTANK_LITERS, + IDSPack = x, + }).OrderBy(y => y.IDSPack.LiquidType.Code).ToList(); + } + + private void MachineEventsStateProvider_EventsChanged(object sender, IEnumerable e) + { + OpenCloseDyeingHeadCommand.IsEnabled = !e.Any(x => x.Type == BL.Enumerations.EventTypes.DRYER_DOOR_OPEN); + + InvokeUI(() => + { + DispenseCleanerLiquidCommand.RaiseCanExecuteChanged(); + }); + } + + private void MachineOperator_MachineStatusChanged(object sender, MachineStatus status) + { + UpdateMidTankLevels(status); + OverallTemperature.Temperature = status.OverallTemperature; + SpoolState = status.SpoolState; + InvalidateRelayCommands(); + } + + private void MachineOperator_InkFillingStatusChanged(object sender, InkFillingStatusChangedEventArgs e) + { + foreach (var cartridge in e.Status.CartridgesStatuses.Where(x => x.Cartridge.Slot != CartridgeSlot.Ink)) + { + var wasteState = WasteStates.SingleOrDefault(x => x.Slot == cartridge.Cartridge.Slot); + + if (wasteState != null) + { + wasteState.State = cartridge.State; + } + } + } + + public async void OpenGuide(GuideBase guide) + { + await NavigationManager.NavigateWithObject(guide); + } + + private void UpdateMidTankLevels(MachineStatus status) + { + if (IsVisible) + { + foreach (var item in status.IDSPacksLevels) + { + var model = MidTankLevels.SingleOrDefault(x => x.IDSPack.PackIndex == item.Index); + + if (model != null) + { + model.Level = item.MidTankLevel; + } + } + } + } + + private async void ExportLogsToStorage() + { + var result = await NavigationManager. + NavigateForResult( + new Storage.Models.StorageNavigationRequest() + { + Intent = Storage.Models.StorageNavigationIntent.SaveFile, + DefaultFileName = $"Tango-Logs-{DateTime.Now.ToFileName()}", + Filter = "do not display anything", + Title = "Export System Logs", + }); + + if (result != null) + { + String file = result.Path + ".zip"; + + IsFree = false; + + try + { + NotificationProvider.SetGlobalBusyMessage("Exporting system logs..."); + + var appFileLogger = LogManager.RegisteredLoggers.FirstOrDefault(x => x is FileLogger) as FileLogger; + + await Task.Factory.StartNew(() => + { + using (ZipFile zip = new ZipFile(file)) + { + zip.Password = "1Creativity"; + + if (appFileLogger != null) + { + zip.AddDirectory(appFileLogger.Folder); + } + + zip.ParallelDeflateThreshold = -1; + zip.Save(); + } + }); + + NotificationProvider.ReleaseGlobalBusyMessage(); + + await NotificationProvider.ShowSuccess("System logs exported successfully."); + } + catch (Exception ex) + { + NotificationProvider.ReleaseGlobalBusyMessage(); + LogManager.Log(ex, "Error exporting system logs."); + await NotificationProvider.ShowError($"An error occurred while trying to export the system logs.\n{ex.FlattenMessage()}"); + } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + IsFree = true; + } + } + } + + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var jobRuns = await db.JobRuns.Select(x => new { x.StartDate, x.EndDate, x.EndPosition }).ToListAsync(); + + TotalDyeTime = TimeSpan.FromHours(jobRuns.Select(x => x.EndDate - x.StartDate).Sum(x => x.TotalHours)).ToStringUnlimitedHours(); + + int meters = (int)jobRuns.Select(x => x.EndPosition).Sum(); + TotalDyeMeters = $"{meters.ToString("N0")} meters"; + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading machine counters."); + TotalDyeTime = "error!"; + TotalDyeMeters = "error!"; + } + } + + private async void PerformHeadCleaning() + { + await NotificationProvider.ShowDialog(); + } + + private void StartThreadLoadingWizard() + { + ThreadLoadingService.StartThreadLoadingWizard(); + } + + private void StartThreadBreakWizard() + { + ThreadLoadingService.StartThreadBreakWizard(); + } + + private async void DispenseCleanerLiquid() + { + await NotificationProvider.ShowDialog(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml new file mode 100644 index 000000000..ecff03b58 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml.cs new file mode 100644 index 000000000..10b5337ce --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Maintenance.Views +{ + /// + /// Interaction logic for GeneralGuideView.xaml + /// + public partial class GeneralGuideView : UserControl + { + public GeneralGuideView() + { + InitializeComponent(); + } + + private void TouchCheckBox_Loaded(object sender, RoutedEventArgs e) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml new file mode 100644 index 000000000..be6161952 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml.cs new file mode 100644 index 000000000..f859c9524 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Maintenance.Views +{ + /// + /// Interaction logic for MainView.xaml + /// + public partial class MainView : UserControl + { + public MainView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml new file mode 100644 index 000000000..d00b4abb2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Maintenance + + + + + + + + + + + + Current Status + + + + + + + + + + + + + + + + + + + + + + + + º + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Temperature + Inks + Collecting Cone + Waste + + + + + + + + + + + Actions + + + + + + + + + + + + + + + + + + + + + RUN HEAD CLEANING + + DISPENSE CLEANING LIQUID + + EXPORT SYSTEM LOGS + + + + + + + + + + + Thread Loading + + + + + + THREAD BREAK WIZARD + + + This wizard will help you resolve thread breaking issues + + + + + THREAD LOADING WIZARD + + + This wizard will help you load a new thread in to the system + + + + RESET THREAD LOADING + + + + + + + + + + + Guides + + + + + + + + + + + + + + + + + + + + + + + + + Total Dyeing Time: + + + + + Total Dyed Length: + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml.cs new file mode 100644 index 000000000..8fb9bd7ca --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.Integration.Operation; +using Tango.PPC.Maintenance.Models; + +namespace Tango.PPC.Maintenance.Views +{ + /// + /// Interaction logic for MainView.xaml + /// + public partial class MaintenanceView : UserControl + { + public MaintenanceView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/app.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/app.config new file mode 100644 index 000000000..1e22e6a88 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/app.config @@ -0,0 +1,61 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/packages.config b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/packages.config new file mode 100644 index 000000000..468d4f366 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Models/StorageNavigationIntent.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Models/StorageNavigationIntent.cs index 2c2a7f10d..3ec14cc6f 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Models/StorageNavigationIntent.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Models/StorageNavigationIntent.cs @@ -9,6 +9,8 @@ namespace Tango.PPC.Storage.Models public enum StorageNavigationIntent { LoadFile, - SaveFile + LoadFiles, + SaveFile, + SaveFiles } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/StorageModule.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/StorageModule.cs index b3553e666..8bbeb4fe2 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/StorageModule.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/StorageModule.cs @@ -15,7 +15,7 @@ namespace Tango.PPC.Storage /// Represents a PPC . /// /// - [PPCModule(3)] + [PPCModule(5)] public class StorageModule : PPCModuleBase { /// diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/ViewModels/MainViewVM.cs index 4a756e7ea..9b22fcdb5 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/ViewModels/MainViewVM.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -21,7 +22,6 @@ namespace Tango.PPC.Storage.ViewModels { private bool _allow_exit; private ExplorerFileItem _selectedItem; - private static char[] _invalidChars = System.IO.Path.GetInvalidFileNameChars(); private String _currentPath; public String CurrentPath @@ -63,15 +63,28 @@ namespace Tango.PPC.Storage.ViewModels } } + private bool _displayItems; + public bool DisplayItems + { + get { return _displayItems; } + set { _displayItems = value; RaisePropertyChangedAuto(); } + } + public RelayCommand FileSelectedCommand { get; set; } + public ObservableCollection SelectedItems { get; set; } + public RelayCommand SaveCommand { get; set; } + public RelayCommand OpenCommand { get; set; } + public MainViewVM() { + SelectedItems = new ObservableCollection(); FileSelectedCommand = new RelayCommand(OnFileSelected); - SaveCommand = new RelayCommand(OnSaveCommand, (x) => !String.IsNullOrWhiteSpace(FileName)); - Request = new StorageNavigationRequest(); + SaveCommand = new RelayCommand(OnSaveCommand, (x) => !String.IsNullOrWhiteSpace(FileName) || Request.Intent == StorageNavigationIntent.SaveFiles); + Request = new StorageNavigationRequest() { Intent = StorageNavigationIntent.LoadFiles }; + OpenCommand = new RelayCommand(OnOpenCommand, () => Request.Intent == StorageNavigationIntent.LoadFiles); } public override void OnApplicationStarted() @@ -104,6 +117,8 @@ namespace Tango.PPC.Storage.ViewModels { View.EditFileName(); } + + DisplayItems = true; } else { @@ -116,7 +131,9 @@ namespace Tango.PPC.Storage.ViewModels public override void OnNavigatedFrom() { base.OnNavigatedFrom(); - Request = new StorageNavigationRequest(); + DisplayItems = false; + Request = null; + Request = new StorageNavigationRequest() { Intent = StorageNavigationIntent.LoadFiles }; } /// @@ -158,7 +175,6 @@ namespace Tango.PPC.Storage.ViewModels { if (_allow_exit || CurrentPath == StorageProvider.Drive.RootDirectory.FullName) { - Request = null; return Task.FromResult(true); } else @@ -169,10 +185,18 @@ namespace Tango.PPC.Storage.ViewModels } private async void OnFileSelected(ExplorerFileItem fileItem) + { + _selectedItem = fileItem; + _allow_exit = true; + await NavigationManager.NavigateBack(); + StorageProvider.SubmitFileSelection(new List() { fileItem }); + } + + private async void OnOpenCommand() { _allow_exit = true; await NavigationManager.NavigateBack(); - StorageProvider.SubmitFileSelection(fileItem); + StorageProvider.SubmitFileSelection(SelectedItems.ToList()); } public ExplorerFileItem GetNavigationResult() @@ -187,10 +211,23 @@ namespace Tango.PPC.Storage.ViewModels private void OnSaveCommand() { - _selectedItem = new ExplorerFileItem() + _allow_exit = true; + + if (Request.Intent == StorageNavigationIntent.SaveFile) + { + _selectedItem = new ExplorerFileItem() + { + Path = CurrentPath + "\\" + FileName, + }; + } + else if (Request.Intent == StorageNavigationIntent.SaveFiles) { - Path = CurrentPath + "\\" + FileName, - }; + _selectedItem = new ExplorerFileItem() + { + Path = CurrentPath, + }; + } + NavigationManager.NavigateBack(); } @@ -200,10 +237,7 @@ namespace Tango.PPC.Storage.ViewModels if (text != null) { - foreach (var c in _invalidChars) - { - text = text.Replace(c.ToString(), ""); - } + text = text.ToValidFileName(); _fileName = text; RaisePropertyChanged(nameof(FileName)); diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Views/MainView.xaml index 74307c9ce..c57735a7b 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Views/MainView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Views/MainView.xaml @@ -16,7 +16,7 @@ - + @@ -32,31 +32,89 @@ - - + + + + + + + + + + OPEN + + + + + + files selected + + + + + + + + + + + - + SAVE - + + + Select destination folder + - + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml new file mode 100644 index 000000000..25227fc60 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CLOSE + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml.cs new file mode 100644 index 000000000..83ec6d362 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Dialogs +{ + /// + /// Interaction logic for LogItemDetailsView.xaml + /// + public partial class EmbeddedLogItemDetailsView : UserControl + { + public EmbeddedLogItemDetailsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsViewVM.cs new file mode 100644 index 000000000..8dc745263 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsViewVM.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.Logging; +using Tango.Logging; +using Tango.SharedUI; + +namespace Tango.PPC.Technician.Dialogs +{ + public class EmbeddedLogItemDetailsViewVM : DialogViewVM + { + private EmbeddedLogItem _log; + public EmbeddedLogItem Log + { + get { return _log; } + set { _log = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml new file mode 100644 index 000000000..37fa8b05c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CLOSE + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml.cs new file mode 100644 index 000000000..40f7a536c --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Dialogs +{ + /// + /// Interaction logic for LogItemDetailsView.xaml + /// + public partial class SynchronizationDetailsView : UserControl + { + public SynchronizationDetailsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsViewVM.cs new file mode 100644 index 000000000..392c8dd3a --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsViewVM.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Logging; +using Tango.PPC.Common.Synchronization; +using Tango.SharedUI; + +namespace Tango.PPC.Technician.Dialogs +{ + public class SynchronizationDetailsViewVM : DialogViewVM + { + private SynchronizationStatus _status; + public SynchronizationStatus Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml new file mode 100644 index 000000000..ccf2062c1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CLOSE + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml.cs new file mode 100644 index 000000000..f2a06aedf --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Dialogs +{ + /// + /// Interaction logic for LogItemDetailsView.xaml + /// + public partial class UpdateDetailsView : UserControl + { + public UpdateDetailsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsViewVM.cs new file mode 100644 index 000000000..36c0fc6d7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsViewVM.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Logging; +using Tango.SharedUI; + +namespace Tango.PPC.Technician.Dialogs +{ + public class UpdateDetailsViewVM : DialogViewVM + { + private TangoUpdate _update; + public TangoUpdate Update + { + get { return _update; } + set { _update = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.png new file mode 100644 index 000000000..ebb975b6f Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.png new file mode 100644 index 000000000..28b535f54 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.png new file mode 100644 index 000000000..1cd649a88 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.png new file mode 100644 index 000000000..e05db36d4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.png new file mode 100644 index 000000000..ea4e685dc Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.png new file mode 100644 index 000000000..cf0e936d8 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.png new file mode 100644 index 000000000..d9d4a1d45 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.png new file mode 100644 index 000000000..abc4d1a1a Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.png b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.png new file mode 100644 index 000000000..46059c5c0 Binary files /dev/null and b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.png differ diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Tango.PPC.Technician.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Tango.PPC.Technician.csproj index d135142c4..fc00f83d4 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Tango.PPC.Technician.csproj +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Tango.PPC.Technician.csproj @@ -69,9 +69,21 @@ + + EmbeddedLogItemDetailsView.xaml + + + SynchronizationDetailsView.xaml + + + UpdateDetailsView.xaml + LogItemDetailsView.xaml + + + @@ -93,10 +105,22 @@ + + + CatalogView.xaml + + RemoteConnectionsView.xaml + + + UpdatesView.xaml + + + PackagesView.xaml + DispensersView.xaml @@ -161,6 +185,10 @@ {0BE74EEE-22CB-4DBA-B896-793B9E1A3AC0} Tango.PPC.Common + + {208C8BD8-72C6-4E3C-ACAA-351091A2ACC7} + Tango.PPC.Shared + @@ -171,6 +199,18 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -179,6 +219,18 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -208,5 +260,24 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModelLocator.cs index ae4678e60..9a8b63c91 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModelLocator.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModelLocator.cs @@ -20,6 +20,9 @@ namespace Tango.PPC.Technician TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); } /// @@ -76,5 +79,38 @@ namespace Tango.PPC.Technician return TangoIOC.Default.GetInstance(); } } + + /// + /// Gets the system view VM. + /// + public static PackagesViewVM PackagesViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + /// + /// Gets the synchronization view vm. + /// + public static UpdatesViewVM UpdatesViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + /// + /// Gets the remote connections view vm. + /// + public static RemoteConnectionsViewVM RemoteConnectionsViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/CatalogViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/CatalogViewVM.cs index 97bae6f5b..dbc99fa87 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/CatalogViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/CatalogViewVM.cs @@ -4,6 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.Core.Commands; +//using Tango.PPC.Browser; +//using Tango.PPC.Browser.Navigation; +//using Tango.PPC.Browser.Views; using Tango.PPC.Common; namespace Tango.PPC.Technician.ViewModels @@ -15,17 +18,23 @@ namespace Tango.PPC.Technician.ViewModels /// public RelayCommand NavigationCommand { get; set; } + /// + /// Gets or sets the browser command. + /// + public RelayCommand BrowserCommand { get; set; } + /// /// Initializes a new instance of the class. /// public CatalogViewVM() { NavigationCommand = new RelayCommand(NavigateToView); + BrowserCommand = new RelayCommand(OpenBrowserModule); } public override void OnApplicationStarted() { - + } /// @@ -36,5 +45,17 @@ namespace Tango.PPC.Technician.ViewModels { NavigationManager.NavigateTo(view); } + + /// + /// Opens the browser module. + /// + private void OpenBrowserModule() + { + //NavigationManager.NavigateWithObject(new BrowserNavigationRequest() + //{ + // Address = "https://twine-s.com/", + // DisplayAddressBar = true, + //}, true); + } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/LoggingViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/LoggingViewVM.cs index 6ca693af6..2aee7f561 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/LoggingViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/LoggingViewVM.cs @@ -8,8 +8,11 @@ using System.Threading.Tasks; using System.Windows.Data; using Tango.Core; using Tango.Core.Commands; +using Tango.Integration.Logging; +using Tango.Integration.Operation; using Tango.Logging; using Tango.PPC.Common; +using Tango.PPC.Common.Helpers; using Tango.PPC.Technician.Dialogs; namespace Tango.PPC.Technician.ViewModels @@ -17,19 +20,14 @@ namespace Tango.PPC.Technician.ViewModels public class LoggingViewVM : PPCViewModel { private const int MAX_LOGS = 1000; + private List paused_logs; + private List paused_embedded_logs; public SynchronizedObservableCollection ApplicationLogs { get; set; } public SynchronizedObservableCollection EmbeddedLogs { get; set; } - private LogItemBase _selectedLog; - public LogItemBase SelectedLog - { - get { return _selectedLog; } - set { _selectedLog = value; RaisePropertyChangedAuto(); OnSelectedLogChanged(); } - } - private ICollectionView _applicationLogsViewSource; public ICollectionView ApplicationLogsViewSource { @@ -37,6 +35,20 @@ namespace Tango.PPC.Technician.ViewModels set { _applicationLogsViewSource = value; RaisePropertyChangedAuto(); } } + private ICollectionView _embeddedLogsViewSource; + public ICollectionView EmbeddedLogsViewSource + { + get { return _embeddedLogsViewSource; } + set { _embeddedLogsViewSource = value; RaisePropertyChangedAuto(); } + } + + private LogItemBase _selectedLog; + public LogItemBase SelectedLog + { + get { return _selectedLog; } + set { _selectedLog = value; RaisePropertyChangedAuto(); OnSelectedLogChanged(); } + } + private String _filter; public String Filter { @@ -46,6 +58,7 @@ namespace Tango.PPC.Technician.ViewModels _filter = value; RaisePropertyChangedAuto(); ApplicationLogsViewSource.Refresh(); + EmbeddedLogsViewSource.Refresh(); } } @@ -56,6 +69,13 @@ namespace Tango.PPC.Technician.ViewModels set { _isPaused = value; RaisePropertyChangedAuto(); OnIsPausedChanged(); } } + private bool _processDebugLogs; + public bool ProcessDebugLogs + { + get { return _processDebugLogs; } + set { _processDebugLogs = value; RaisePropertyChangedAuto(); OnProcessDebugLogsChanged(); } + } + public RelayCommand ClearCommand { get; set; } public LoggingViewVM() @@ -63,8 +83,19 @@ namespace Tango.PPC.Technician.ViewModels ApplicationLogs = new SynchronizedObservableCollection(); EmbeddedLogs = new SynchronizedObservableCollection(); ApplicationLogsViewSource = CollectionViewSource.GetDefaultView(ApplicationLogs); + EmbeddedLogsViewSource = CollectionViewSource.GetDefaultView(EmbeddedLogs); paused_logs = new List(); + paused_embedded_logs = new List(); + + var appStartLogs = LogsHelper.GetLogSafe().EmptyAndDispose(); + + foreach (var log in appStartLogs) + { + ApplicationLogs.Insert(0, log); + } + LogManager.NewLog += LogManager_NewLog; + MachineOperator.EmbeddedLogManager.NewLog += EmbeddedLogManager_NewLog; ClearCommand = new RelayCommand(ClearLogs); Filter = "error"; @@ -81,6 +112,31 @@ namespace Tango.PPC.Technician.ViewModels return false; } }; + + EmbeddedLogsViewSource.Filter = (x) => + { + try + { + LogItemBase log = x as LogItemBase; + return String.IsNullOrWhiteSpace(Filter) || log.Category.ToString().ToLower().Contains(Filter.ToLower()) || log.Message.ToLower().Contains(Filter.ToLower()); + } + catch + { + return false; + } + }; + } + + private void OnProcessDebugLogsChanged() + { + if (ProcessDebugLogs) + { + LogManager.Categories.Add(LogCategory.Debug); + } + else + { + LogManager.Categories.RemoveAll(x => x == LogCategory.Debug); + } } private void OnIsPausedChanged() @@ -91,6 +147,14 @@ namespace Tango.PPC.Technician.ViewModels } paused_logs.Clear(); + + + foreach (var log in paused_embedded_logs) + { + EmbeddedLogManager_NewLog(this, log); + } + + paused_embedded_logs.Clear(); } private void LogManager_NewLog(object sender, LogItemBase log) @@ -120,22 +184,59 @@ namespace Tango.PPC.Technician.ViewModels } } + private void EmbeddedLogManager_NewLog(object sender, LogItemBase log) + { + if (!IsPaused) + { + InvokeUI(() => + { + EmbeddedLogs.Insert(0, log); + + try + { + if (EmbeddedLogs.Count > MAX_LOGS) + { + EmbeddedLogs.Remove(EmbeddedLogs.Last()); + } + } + catch + { + //I don't know if this will cause an exception but I'm tired. + } + }); + } + else + { + paused_embedded_logs.Add(log); + } + } + private void ClearLogs() { ApplicationLogs.Clear(); + EmbeddedLogs.Clear(); paused_logs.Clear(); + paused_embedded_logs.Clear(); } private async void OnSelectedLogChanged() { if (SelectedLog != null) { - await NotificationProvider.ShowDialog(new LogItemDetailsViewVM() + if (SelectedLog.GetType() == typeof(EmbeddedLogItem)) { - Log = SelectedLog, - }); - - SelectedLog = null; + await NotificationProvider.ShowDialog(new EmbeddedLogItemDetailsViewVM() + { + Log = SelectedLog as EmbeddedLogItem, + }); + } + else + { + await NotificationProvider.ShowDialog(new LogItemDetailsViewVM() + { + Log = SelectedLog, + }); + } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/MainViewVM.cs index d63a89f3b..4f8aba952 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/MainViewVM.cs @@ -12,13 +12,13 @@ namespace Tango.PPC.Technician.ViewModels { public override void OnApplicationStarted() { - + } public override void OnNavigatedTo() { base.OnNavigatedTo(); - NavigationManager.NavigateTo(nameof(CatalogView)); + NavigationManager.NavigateTo(nameof(CatalogView), false); } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/PackagesViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/PackagesViewVM.cs new file mode 100644 index 000000000..1d7e1780a --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/PackagesViewVM.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.PPC.Common; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Technician.ViewModels +{ + public class PackagesViewVM : PPCViewModel + { + [TangoInject(TangoInjectMode.WhenAvailable)] + public IPackageRunner PackageRunner { get; set; } + + private List _packages; + public List Packages + { + get { return _packages; } + set { _packages = value; RaisePropertyChangedAuto(); } + } + + public override void OnApplicationStarted() + { + + } + + public async override void OnApplicationReady() + { + base.OnApplicationReady(); + + try + { + Packages = (await PackageRunner.GetPackagesFile()).PackageInstallations; + } + catch (Exception ex) + { + LogManager.Log(ex, "An error occurred while trying to list the installed update packages."); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/RemoteConnectionsViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/RemoteConnectionsViewVM.cs new file mode 100644 index 000000000..2d8857329 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/RemoteConnectionsViewVM.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common; + +namespace Tango.PPC.Technician.ViewModels +{ + public class RemoteConnectionsViewVM : PPCViewModel + { + public RelayCommand DisconnectCommand { get; set; } + + private ExternalBridgeReceiver _selectedReceiver; + public ExternalBridgeReceiver SelectedReceiver + { + get { return _selectedReceiver; } + set + { + if (value != null) + { + _selectedReceiver = value; + InvalidateRelayCommands(); + } + } + } + + public RemoteConnectionsViewVM() + { + DisconnectCommand = new RelayCommand(DisconnectReceiver, () => SelectedReceiver != null); + } + + private async void DisconnectReceiver() + { + if (SelectedReceiver != null) + { + try + { + await Task.Factory.StartNew(() => + { + SelectedReceiver.Disconnect().Wait(); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disconnecting the specified receiver."); + } + finally + { + _selectedReceiver = null; + RaisePropertyChanged(nameof(SelectedReceiver)); + InvalidateRelayCommands(); + } + } + } + + public override void OnApplicationStarted() + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/SystemViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/SystemViewVM.cs index 444c1d09e..452907366 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/SystemViewVM.cs +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/SystemViewVM.cs @@ -8,16 +8,20 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Timers; +using Tango.BL; using Tango.Core.Commands; using Tango.PPC.Common; using Tango.PPC.Common.OS; using Tango.Settings; +using System.Data.Entity; +using Tango.PPC.Common.UWF; namespace Tango.PPC.Technician.ViewModels { public class SystemViewVM : PPCViewModel { private IOperationSystemManager _os; + private IUnifiedWriteFilterManager _uwf; private Timer _statsTimer; private bool _resettingDevice; @@ -56,6 +60,20 @@ namespace Tango.PPC.Technician.ViewModels set { _ipAddress = value; RaisePropertyChangedAuto(); } } + private String _totalDyeTime; + public String TotalDyeTime + { + get { return _totalDyeTime; } + set { _totalDyeTime = value; RaisePropertyChangedAuto(); } + } + + private String _totalDyeMeters; + public String TotalDyeMeters + { + get { return _totalDyeMeters; } + set { _totalDyeMeters = value; RaisePropertyChangedAuto(); } + } + public RelayCommand ResetDeviceCommand { get; set; } public RelayCommand RestartCommand { get; set; } @@ -66,9 +84,10 @@ namespace Tango.PPC.Technician.ViewModels public RelayCommand ExitToExplorerCommand { get; set; } - public SystemViewVM(IOperationSystemManager os) + public SystemViewVM(IOperationSystemManager os, IUnifiedWriteFilterManager uwf) { _os = os; + _uwf = uwf; CPU = 0; RAM = 0; @@ -86,7 +105,7 @@ namespace Tango.PPC.Technician.ViewModels { _resettingDevice = true; ResetDeviceCommand.RaiseCanExecuteChanged(); - await MachineProvider.MachineOperator.ResetDFU(); + await MachineProvider.MachineOperator.Reset(); await NotificationProvider.ShowInfo("Embedded device has been reset successfully."); } catch (Exception ex) @@ -102,11 +121,30 @@ namespace Tango.PPC.Technician.ViewModels private async void FactoryReset() { - if (await NotificationProvider.ShowQuestion("Are you sure you want to reset this device and back to factory settings?")) + if (await NotificationProvider.ShowQuestion("Are you sure you want to reset this device back to factory settings?")) { Settings.ApplicationState = ApplicationStates.FactoryRestore; Settings.Save(); - ApplicationManager.Restart(); + try + { + NotificationProvider.SetGlobalBusyMessage("Disabling write filter protection..."); + await _uwf.Disable(); + await Task.Delay(2000); + NotificationProvider.ReleaseGlobalBusyMessage(); + await NavigationManager.NavigateTo(Common.Navigation.NavigationView.RestartingSystemView); + await Task.Delay(4000); + _os.Restart(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error executing factory reset."); + NotificationProvider.ReleaseGlobalBusyMessage(); + await NotificationProvider.ShowError($"Error executing factory reset.\n{ex.FlattenMessage()}"); + } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + } } } @@ -122,6 +160,8 @@ namespace Tango.PPC.Technician.ViewModels { if (await NotificationProvider.ShowQuestion("Are you sure you want to restart the device?")) { + await NavigationManager.NavigateTo(Common.Navigation.NavigationView.RestartingSystemView); + await Task.Delay(4000); _os.Restart(); } } @@ -130,12 +170,7 @@ namespace Tango.PPC.Technician.ViewModels { if (await NotificationProvider.ShowQuestion("Close the application and start OS shell?")) { - Process.Start(new ProcessStartInfo() - { - UseShellExecute = true, - FileName = "explorer.exe", - }); - + _os.OpenShell(); ApplicationManager.ShutDown(); } } @@ -148,12 +183,6 @@ namespace Tango.PPC.Technician.ViewModels _statsTimer.Start(); } - public override void OnApplicationReady() - { - base.OnApplicationReady(); - IPAddress = GetIpv4Address(); - } - private void _statsTimer_Elapsed(object sender, ElapsedEventArgs e) { if (IsVisible) @@ -244,5 +273,31 @@ namespace Tango.PPC.Technician.ViewModels return "N/A"; } } + + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + IPAddress = GetIpv4Address(); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var jobRuns = await db.JobRuns.Select(x => new { x.StartDate, x.EndDate, x.EndPosition }).ToListAsync(); + + TotalDyeTime = TimeSpan.FromHours(jobRuns.Select(x => x.EndDate - x.StartDate).Sum(x => x.TotalHours)).ToStringUnlimitedHours(); + + int meters = (int)jobRuns.Select(x => x.EndPosition).Sum(); + TotalDyeMeters = $"{meters.ToString("N0")} meters"; + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading machine counters."); + TotalDyeTime = "error!"; + TotalDyeMeters = "error!"; + } + } } } diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/UpdatesViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/UpdatesViewVM.cs new file mode 100644 index 000000000..3f4232252 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/UpdatesViewVM.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.PPC.Common; +using System.Data.Entity; +using Tango.PPC.Technician.Dialogs; +using Tango.PPC.Common.Synchronization; + +namespace Tango.PPC.Technician.ViewModels +{ + public class UpdatesViewVM : PPCViewModel + { + public RelayCommand SynchronizeCommand { get; set; } + + private List _updates; + public List Updates + { + get { return _updates; } + set { _updates = value; RaisePropertyChangedAuto(); } + } + + private TangoUpdate _selectedUpdate; + public TangoUpdate SelectedUpdate + { + get { return _selectedUpdate; } + set { _selectedUpdate = value; OnSelectedUpdateChanged(); } + } + + private SynchronizationStatus _selectedSynchronization; + public SynchronizationStatus SelectedSynchronization + { + get { return _selectedSynchronization; } + set { _selectedSynchronization = value; OnSelectedSynchronizationChanged(); } + } + + public UpdatesViewVM() + { + Updates = new List(); + SynchronizeCommand = new RelayCommand(Synchronize, () => !MachineDataSynchronizer.IsSynchronizing); + } + + public override void OnApplicationStarted() + { + + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + MachineDataSynchronizer.SynchronizationStarted += (_, __) => InvalidateRelayCommands(); + MachineDataSynchronizer.SynchronizationEnded += (_, __) => InvalidateRelayCommands(); + } + + private async void Synchronize() + { + try + { + await MachineDataSynchronizer.Synchronize(); + } + catch { } + } + + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + Updates = await db.TangoUpdates.Where(x => + x.Status != (int)TangoUpdateStatuses.SynchronizationCompleted && + x.Status != (int)TangoUpdateStatuses.SynchronizationFailed && + x.Status != (int)TangoUpdateStatuses.SynchronizationStarted + ).OrderByDescending(x => x.StartDate).ToListAsync(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading update history."); + } + } + + private async void OnSelectedUpdateChanged() + { + if (SelectedUpdate != null) + { + await NotificationProvider.ShowDialog(new UpdateDetailsViewVM() { Update = SelectedUpdate }); + } + } + + private async void OnSelectedSynchronizationChanged() + { + if (SelectedSynchronization != null) + { + await NotificationProvider.ShowDialog(new SynchronizationDetailsViewVM() { Status = SelectedSynchronization }); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/CatalogView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/CatalogView.xaml index 58c88324f..78fa17979 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/CatalogView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/CatalogView.xaml @@ -20,32 +20,116 @@ - Technician Mode + Technician - - - - - Logging - - - - - - - System - - - - - - - Dispensers - - - - - + + + + + + + + + The technician module enables additional diagnostic tools. + + + + + + Logging + + Display and investigate issues using application and embedded device logs. + + + + + + + + + + System + + Display system properties, perform system actions, reset, shutdown etc... + + + + + + + + + + Dispensers + + Perform manual dispensers homing priming. + + + + + + + + + + Installed Packages + + View the history of update packages installation. + + + + + + + + + + Updates & Synchronization + + View the current status and history of update and synchronization operations. + + + + + + + + + + Remote Connections + + View the current status of remote connections to this machine. + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/LoggingView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/LoggingView.xaml index 39353c286..8393349ea 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/LoggingView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/LoggingView.xaml @@ -34,7 +34,7 @@ - + Application Embedded @@ -47,91 +47,109 @@ + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/MainView.xaml index 08f9a335a..d4235341c 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/MainView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/MainView.xaml @@ -17,6 +17,9 @@ + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml new file mode 100644 index 000000000..a7944497b --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml @@ -0,0 +1,103 @@ + + + + + + + + + + + + Installed Packages + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml.cs new file mode 100644 index 000000000..52384fe73 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Views +{ + /// + /// Interaction logic for DispensersView.xaml + /// + public partial class PackagesView : UserControl + { + public PackagesView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml new file mode 100644 index 000000000..af93a56e5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml @@ -0,0 +1,88 @@ + + + + + + + + + + + + Remote Connections + + + + + + DISCONNECT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml.cs new file mode 100644 index 000000000..5d8e32444 --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Views +{ + /// + /// Interaction logic for RemoteConnectionsView.xaml + /// + public partial class RemoteConnectionsView : UserControl + { + public RemoteConnectionsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/SystemView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/SystemView.xaml index f2bfcdf7d..52abfc239 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/SystemView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/SystemView.xaml @@ -8,9 +8,10 @@ xmlns:vm="clr-namespace:Tango.PPC.Technician.ViewModels" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:global="clr-namespace:Tango.PPC.Technician" mc:Ignorable="d" - d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:SystemViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.SystemViewVM}" x:Name="view"> + d:DesignHeight="1260" d:DesignWidth="600" d:DataContext="{d:DesignInstance Type=vm:SystemViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.SystemViewVM}" x:Name="view"> @@ -29,55 +30,283 @@ System - - - - - - CPU: - % - - - - RAM: - - - - - TEMP: - - - - - - - - - UP TIME: - - - - - IP ADDRESS: - - - + + + + + + + + + + + + + + + Reset Embedded Device + + Resets the embedded device using the DFU channel. + + + + - - - - - + + + + + Restart Panel PC + + Restarts the panel PC operation system. + + + + + + + + + Shutdown Panel PC + + Turns off the panel PC (requires turning on from reset button). + + + + + + + + + Factory Reset + + Removes all data associated with this machine and installs the latest version. + + + + + + + + + Exit To Shell + + Closes the PPC application and opens the windows shell. + + + - Restart Device - Shutdown Device - Factory Reset - Exit To Shell + + + + + + + + + + + + + + + + + + + + Application Version: + + + + + + + + + + + + + + Firmware Version: + + + + + + + + + + + + + + FPGA 1: + + + + + + + + + + + + + + FPGA 2: + + + + + + + + + + + + + + FPGA 3: + + + + + + + + + + + + + + CPU: + + + + + + + + % + + + + + + + + + RAM: + + + + + + + + + + + + + + Temperature: + + + + + + + + + + + + + + Up Time: + + + + + + + + + + + + + + IP Address: + + + + + + + + + + + + + + Total Dye Time: + + + + + + + + + + + + + + Total Dye Meters: + + + + + + + + + + +
+
+
-
+
diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml new file mode 100644 index 000000000..501632bfa --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + Updates & Synchronization + + + + + + + Updates + Synchronization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Synchronize Now + Synchronization occurres automatically in the background. You can choose to synchronize now. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml.cs new file mode 100644 index 000000000..cdac5cbbb --- /dev/null +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.Technician.Views +{ + /// + /// Interaction logic for UpdatesView.xaml + /// + public partial class UpdatesView : UserControl + { + public UpdatesView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Application/IPPCApplicationManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Application/IPPCApplicationManager.cs index 7c67ac1a3..a9d4e7c3a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Application/IPPCApplicationManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Application/IPPCApplicationManager.cs @@ -45,6 +45,11 @@ namespace Tango.PPC.Common.Application ///
event EventHandler SystemRestartRequired; + /// + /// Occurs when the updater utility has failed to perform the last update. + /// + event EventHandler UpdaterFailed; + /// /// Occurs when the application has encountered an error when initializing. /// @@ -60,6 +65,16 @@ namespace Tango.PPC.Common.Application ///
bool IsInTechnicianMode { get; } + /// + /// Gets a value indicating whether an update has occurred before the application started. + /// + bool IsAfterUpdate { get; } + + /// + /// Gets a value indicating whether the updater utility has failed to perform the last update. + /// + bool IsUpdateFailed { get; } + /// /// Shutdown the application. /// @@ -90,6 +105,11 @@ namespace Tango.PPC.Common.Application ///
Version Version { get; } + /// + /// Gets the firmware version. + /// + Version FirmwareVersion { get; } + /// /// Gets the application build date. /// @@ -100,6 +120,11 @@ namespace Tango.PPC.Common.Application /// DateTime StartUpDate { get; } + /// + /// Gets or sets the application folder. + /// + String StartPath { get; } + /// /// Gets or sets a value indicating whether the screen is currently locked. /// @@ -114,5 +139,11 @@ namespace Tango.PPC.Common.Application /// Invokes a dialog for entering a password and releasing the screen lock. /// void ReleaseScreenLock(); + + /// + /// Sets the state of the main window. + /// + /// The state. + void SetWindowState(WindowState state); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Authentication/IAuthenticationProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Authentication/IAuthenticationProvider.cs index 33761c8d6..ca927e6df 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Authentication/IAuthenticationProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Authentication/IAuthenticationProvider.cs @@ -22,6 +22,11 @@ namespace Tango.PPC.Common.Authentication /// User CurrentUser { get; } + /// + /// Gets a value indicating whether the authentication provider is using a null user. + /// + bool AuthenticationRequired { get; } + /// /// Performs a user login by the specified email and password. /// @@ -31,6 +36,12 @@ namespace Tango.PPC.Common.Authentication /// Task Login(String email, String password, bool encrypt = true); + /// + /// Performs a fake login when no authentication is used. + /// + /// + Task Login(); + /// /// Logs-out the current logged-in user. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupFile.cs new file mode 100644 index 000000000..c687377a6 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupFile.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Exports; +using Tango.Web; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup file record. + /// + public class BackupFile + { + /// + /// Gets or sets the backup file version. + /// + public int Version { get; set; } + + /// + /// Gets or sets the backup name. + /// + public String Name { get; set; } + + /// + /// Gets or sets the creation date. + /// + public DateTime Date { get; set; } + + /// + /// Gets or sets the machine serial number. + /// + public String MachineSerialNumber { get; set; } + + /// + /// Gets or sets the application version. + /// + public String ApplicationVersion { get; set; } + + /// + /// Gets or sets the firmware version. + /// + public String FirmwareVersion { get; set; } + + /// + /// Gets or sets the settings file. + /// + public String SettingsFile { get; set; } + + /// + /// Gets or sets the job files. + /// + public List JobFiles { get; set; } + + /// + /// Gets or sets the backup settings. + /// + public BackupSettings Settings { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public BackupFile() + { + Settings = new BackupSettings(); + JobFiles = new List(); + } + + public String ToJson() + { + return JsonConvert.SerializeObject(this); + } + + public static BackupFile FromJson(String json) + { + return JsonConvert.DeserializeObject(json); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupMode.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupMode.cs new file mode 100644 index 000000000..8533ce22a --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupMode.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup mode. + /// + public enum BackupMode + { + /// + /// Jobs only backup. + /// + Jobs, + /// + /// Complete backup of data, app binaries, firmware and settings file. + /// + Full, + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreProgressEventArgs.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreProgressEventArgs.cs new file mode 100644 index 000000000..d12db7b56 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreProgressEventArgs.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup restore procedure progress. + /// + /// + public class BackupRestoreProgressEventArgs : EventArgs + { + /// + /// Gets or sets a value indicating whether the progress is intermediate. + /// + public bool IsIntermediate { get; set; } + + /// + /// Gets or sets the progress value. + /// + public double Progress { get; set; } + + + /// + /// Gets or sets the maximum progress. + /// + public double MaxProgress { get; set; } + + /// + /// Gets or sets the progress stage. + /// + public BackupRestoreStage Stage { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreStage.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreStage.cs new file mode 100644 index 000000000..4e0398237 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreStage.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup restore procedure stage. + /// + public enum BackupRestoreStage + { + [Description("Initializing")] + Initializing, + + //Backup + [Description("Backing up jobs...")] + BackingupJobs, + [Description("Backing up data...")] + BackingupDatabase, + [Description("Backing up application...")] + BackingupApplication, + [Description("Backing up user settings...")] + BackingupSettings, + [Description("Writing configuration...")] + WritingConfiguration, + [Description("Compressing files...")] + CompressingFiles, + [Description("Encrypting...")] + Encrypting, + + //Restore + [Description("Decrypting...")] + Decrypting, + [Description("Extracting backup configuration...")] + ExtractingBackupConfiguration, + [Description("Validating machine state...")] + ValidatingMachineState, + [Description("Extracting content...")] + ExtractingContent, + [Description("Restoring user settings...")] + RestoringSettings, + [Description("Restoring jobs...")] + RestoringJobs, + [Description("Restoring data...")] + RestoringDatabase, + [Description("Removing temporary files...")] + RemovingTemporaryFiles, + [Description("Restoring firmware version...")] + RestoringFirmware, + [Description("Rolling back changes...")] + RollingBackChanges, + + + [Description("Done")] + Done, + + [Description("Error")] + Error, + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupSettings.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupSettings.cs new file mode 100644 index 000000000..b2021ba39 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupSettings.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup settings. + /// + public class BackupSettings + { + /// + /// Gets or sets the backup mode. + /// + public BackupMode Mode { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/DefaultBackupManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/DefaultBackupManager.cs new file mode 100644 index 000000000..d32df734d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/DefaultBackupManager.cs @@ -0,0 +1,604 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.BackupRestore; +using Tango.Core.ExtensionMethods; +using Tango.Core.DI; +using Tango.PPC.Common.Connection; +using System.IO; +using Tango.Core.Helpers; +using Tango.BL; +using Tango.Settings; +using Tango.Core.DB; +using System.Data.SqlClient; +using Ionic.Zip; +using Tango.BL.Entities; +using Tango.PPC.Common.Authentication; +using Tango.Integration.Upgrade; +using Tango.Core.IO; + +namespace Tango.PPC.Common.BackupRestore +{ + public class DefaultBackupManager : ExtendedObject, IBackupManager + { + private const string BACKUP_FILE_NAME = "Backup.json"; + private const string DATABASE_FILE_NAME = "Tango.bak"; + private const int VERSION = 1; + private const string PASSWORD = "1Creativity"; + + [TangoInject(TangoInjectMode.WhenAvailable)] + private IPPCApplicationManager _applicationManager; + + [TangoInject(TangoInjectMode.WhenAvailable)] + private IMachineProvider _machineProvider; + + [TangoInject(TangoInjectMode.WhenAvailable)] + private IAuthenticationProvider _authenticationProvider; + + public DefaultBackupManager() + { + TangoIOC.Default.Inject(this); + } + + public event EventHandler Progress; + + public Task CreateBackup(string filePath, String name, BackupSettings settings) + { + return Task.Factory.StartNew(() => + { + var tempFolder = TemporaryManager.CreateFolder(); + + try + { + //Basic + LogManager.Log($"Starting backup operation to file '{filePath}'..."); + LogManager.Log($"Backup settings:\n{settings.ToJsonString()}"); + OnProgress(BackupRestoreStage.Initializing); + + LogManager.Log($"Temporary folder created on {tempFolder.Path}."); + + BackupFile backupFile = new BackupFile(); + backupFile.Version = VERSION; + backupFile.Date = DateTime.Now; + backupFile.Settings = settings; + backupFile.Name = name; + backupFile.MachineSerialNumber = _machineProvider.Machine.SerialNumber; + backupFile.ApplicationVersion = _applicationManager.Version.ToString(); + + //Firmware + try + { + LogManager.Log("Extracting firmware version from local tfp package..."); + using (var st = File.OpenRead(Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "firmware_package.tfp"))) + { + backupFile.FirmwareVersion = _machineProvider.MachineOperator.GetFirmwarePackageInfo(st).Result.FileDescriptors.SingleOrDefault(x => x.Destination == PMR.FirmwareUpgrade.VersionFileDestination.Mcu).Version; + } + } + catch (Exception ex) + { + throw new FileLoadException("Could extract the firmware version from the TFP package.", ex); + } + + LogManager.Log($"Backup file generated:\n{backupFile.ToJsonString()}"); + + if (settings.Mode == BackupMode.Jobs) + { + //Jobs + LogManager.Log("Starting jobs backup..."); + OnProgress(BackupRestoreStage.BackingupJobs); + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var jobs = db.Jobs.ToList(); + + foreach (var job in jobs) + { + try + { + LogManager.Log($"Backing up job '{job.Name}'..."); + var jobFile = job.ToJobFile().Result; + backupFile.JobFiles.Add(jobFile); + + OnProgress(BackupRestoreStage.BackingupJobs, jobs.IndexOf(job) + 1, jobs.Count, false); + } + catch (Exception ex) + { + throw new InvalidOperationException($"Error extracting job {job.Name}.", ex); + } + } + } + LogManager.Log("Jobs backup completed."); + } + else + { + //User Settings + LogManager.Log("Backing up application settings..."); + OnProgress(BackupRestoreStage.BackingupSettings); + backupFile.SettingsFile = File.ReadAllText(SettingsManager.Default.FilePath); + + //Application Version + LogManager.Log("Backing up application files..."); + OnProgress(BackupRestoreStage.BackingupApplication); + + try + { + PathHelper.CopyDirectory(AssemblyHelper.GetCurrentAssemblyFolder(), tempFolder, true, (current, total) => + { + OnProgress(BackupRestoreStage.BackingupApplication, current, total, false); + }); + } + catch (Exception ex) + { + throw new IOException($"Error occurred while copying application files.", ex); + } + + //Database + LogManager.Log("Backing up database..."); + OnProgress(BackupRestoreStage.BackingupDatabase); + try + { + var dataSource = ObservablesContext.GetActualDataSource(); + using (var dbManager = DbManager.FromDataSource(dataSource)) + { + Directory.CreateDirectory("C:\\Backups"); + var dbBackupFile = $"C:\\Backups\\{DATABASE_FILE_NAME}"; + if (File.Exists(dbBackupFile)) + { + File.Delete(dbBackupFile); + } + dbManager.Backup(dataSource.Catalog, dbBackupFile); + File.Move(dbBackupFile, Path.Combine(tempFolder, DATABASE_FILE_NAME)); + } + } + catch (Exception ex) + { + throw new IOException("Error creating database backup", ex); + } + + LogManager.Log("Database backup completed."); + } + + //Backup.json + try + { + OnProgress(BackupRestoreStage.WritingConfiguration); + var backupFilePath = Path.Combine(tempFolder, BACKUP_FILE_NAME); + LogManager.Log($"Writing backup configuration file '{backupFilePath}'..."); + File.WriteAllText(backupFilePath, backupFile.ToJsonString()); + } + catch (Exception ex) + { + throw new IOException("Error writing backup configuration file.", ex); + } + + //Compression + LogManager.Log($"Generating {filePath}..."); + using (ZipFile zip = new ZipFile()) + { + zip.Password = PASSWORD; + zip.AddDirectory(tempFolder); + + zip.SaveProgress += (x, e) => + { + if (e.EventType == ZipProgressEventType.Saving_AfterWriteEntry) + { + LogManager.Log($"Compressing '{e.CurrentEntry.FileName}'..."); + OnProgress(BackupRestoreStage.CompressingFiles, e.EntriesSaved + 1, e.EntriesTotal, false); + } + }; + + zip.ParallelDeflateThreshold = -1; + zip.Save(filePath); + } + + //Done + LogManager.Log("Backup operation completed!!!"); + OnProgress(BackupRestoreStage.Done, 100, 100, false); + tempFolder.Delete(); + } + catch (Exception ex) + { + tempFolder.Delete(); + + OnProgress(BackupRestoreStage.Error, 100, 100, false); + LogManager.Log(ex, "Could not complete the backup operation."); + throw ex; + } + }); + } + + /// + /// Extracts the backup configuration from the specified backup file. + /// + /// The file path. + /// + public Task ExtractBackupConfiguration(string filePath) + { + return Task.Factory.StartNew(() => + { + using (ZipFile zip = ZipFile.Read(filePath)) + { + zip.Password = PASSWORD; + var reader = zip.Entries.SingleOrDefault(x => x.FileName == BACKUP_FILE_NAME).OpenReader(); + String json = String.Empty; + + using (StreamReader stReader = new StreamReader(reader)) + { + json = stReader.ReadToEnd(); + } + + var backupFile = BackupFile.FromJson(json); + reader.Close(); + reader.Dispose(); + return backupFile; + } + }); + } + + public Task Restore(string filePath, RestoreSettings settings) + { + TaskCompletionSource completionSource = new TaskCompletionSource(); + + String dbRollbackFile = null; + bool shouldRollback = false; + + Task.Factory.StartNew(() => + { + LogManager.Log($"Starting restore operation from file '{filePath}'..."); + OnProgress(BackupRestoreStage.Initializing); + + var tempFolder = TemporaryManager.CreateFolder(); + tempFolder.Persist = true; + + var restoreResult = new RestoreResult() { FolderPath = tempFolder }; + + try + { + LogManager.Log("Extracting backup file configuration..."); + + BackupFile backupFile = null; + + //Extract Configuration + try + { + OnProgress(BackupRestoreStage.ExtractingBackupConfiguration); + backupFile = ExtractBackupConfiguration(filePath).Result; + restoreResult.BackupFile = backupFile; + LogManager.Log($"Backup settings:\n{backupFile.Settings.ToJsonString()}"); + } + catch (Exception ex) + { + throw new IOException("Error extracting backup configuration.", ex); + } + + //Validate Version + if (backupFile.Version > VERSION) + { + throw new NotSupportedException($"Backup file version {backupFile} is not supported."); + } + + //Validate Machine Serial Number + if (backupFile.Settings.Mode == BackupMode.Full && backupFile.MachineSerialNumber != _machineProvider.Machine.SerialNumber) + { + throw new InvalidOperationException($"The specified backup file targets machine '{backupFile.MachineSerialNumber}'. Cannot perform the restore operation."); + } + + //Validate Machine State + LogManager.Log("Validating machine state..."); + OnProgress(BackupRestoreStage.ValidatingMachineState); + if (_machineProvider.MachineOperator.IsPrinting) + { + LogManager.Log("The machine is currently printing. Aborting!"); + throw new InvalidOperationException("Cannot perform restore operation while machine is dyeing."); + } + + if (backupFile.Settings.Mode == BackupMode.Full && _machineProvider.MachineOperator.State != Transport.TransportComponentState.Connected) + { + LogManager.Log("Backup is configured to restore the firmware but machine is not connected!"); + throw new InvalidOperationException("The restore operation is configured to restore the firmware version but the machine is currently disconnected."); + } + + //Create Restore Point + try + { + LogManager.Log("Creating database rollback file..."); + var dataSource = ObservablesContext.GetActualDataSource(); + using (var dbManager = DbManager.FromDataSource(dataSource)) + { + Directory.CreateDirectory("C:\\Backups"); + dbRollbackFile = $"C:\\Backups\\{Path.GetRandomFileName()}.bak"; + LogManager.Log($"Creating database rollback to '{dbRollbackFile}'..."); + dbManager.Backup(dataSource.Catalog, dbRollbackFile); + LogManager.Log("Database rollback created successfully."); + shouldRollback = true; + } + } + catch (Exception ex) + { + throw new InvalidDataException("Error creating database rollback file.", ex); + } + + if (backupFile.Settings.Mode == BackupMode.Jobs) + { + //Restore Jobs + OnProgress(BackupRestoreStage.RestoringJobs); + LogManager.Log("Starting jobs restore..."); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var jobs = db.Jobs.ToList(); + var jobFiles = backupFile.JobFiles; + + if (settings.AllowDeleteJobs) + { + try + { + LogManager.Log("Removing existing jobs..."); + foreach (var job in jobs.ToList()) + { + LogManager.Log($"Removing job '{job.Name}'..."); + job.Delete(db); + jobs.Remove(job); + } + + db.SaveChanges(); + } + catch (Exception ex) + { + throw new Exception("Error removing existing jobs from database.", ex); + } + } + + foreach (var jobFile in jobFiles) + { + LogManager.Log($"Importing job '{jobFile.Name}'..."); + + try + { + var existingJob = jobs.FirstOrDefault(x => x.Name == jobFile.Name); + + if (existingJob != null) + { + if (settings.OverwriteExistingJobs) + { + try + { + LogManager.Log("Job already exist, overwriting..."); + + var newJob = Job.FromJobFile(jobFile, _machineProvider.Machine.Guid, null).Result; + newJob.Guid = existingJob.Guid; + + existingJob.Delete(db); + jobs.Remove(existingJob); + + db.SaveChanges(); + db.Jobs.Add(newJob); + db.SaveChanges(); + } + catch (Exception ex) + { + throw new InvalidOperationException("Error overwriting job.", ex); + } + } + } + else + { + var newJob = Job.FromJobFile(jobFile, _machineProvider.Machine.Guid, null).Result; + db.Jobs.Add(newJob); + } + } + catch (Exception ex) + { + throw new InvalidOperationException("Error importing job.", ex); + } + + OnProgress(BackupRestoreStage.RestoringJobs, jobFiles.IndexOf(jobFile) + 1, jobFiles.Count, false); + } + + OnProgress(BackupRestoreStage.RestoringJobs); + db.SaveChanges(); + } + + LogManager.Log("Jobs restored successfully."); + OnProgress(BackupRestoreStage.Done, 100, 100, false); + completionSource.SetResult(restoreResult); + } + else + { + //Extract zip file + LogManager.Log("Starting backup file extraction..."); + OnProgress(BackupRestoreStage.ExtractingContent); + try + { + using (ZipFile zip = new ZipFile(filePath)) + { + zip.Password = PASSWORD; + + zip.ExtractProgress += (x, e) => + { + if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry) + { + LogManager.Log($"Extracting '{e.CurrentEntry.FileName}'..."); + OnProgress(BackupRestoreStage.ExtractingContent, e.EntriesExtracted + 1, e.EntriesTotal, false); + } + }; + + zip.ParallelDeflateThreshold = -1; + zip.ExtractAll(tempFolder); + } + } + catch (Exception ex) + { + throw new IOException("Error extracting backup content.", ex); + } + + //Overwrite settings + LogManager.Log("Validating user settings..."); + if (backupFile.SettingsFile != null) + { + try + { + LogManager.Log("Overwriting settings file..."); + OnProgress(BackupRestoreStage.RestoringSettings); + File.WriteAllText(SettingsManager.Default.FilePath, backupFile.SettingsFile); + } + catch (Exception ex) + { + throw new IOException("Error overwriting user settings.", ex); + } + } + else + { + LogManager.Log("No user settings, skipping..."); + } + + //Restore database + var backupFilePath = Path.Combine(tempFolder, DATABASE_FILE_NAME); + LogManager.Log($"Looking for file database backup on '{backupFilePath}'..."); + if (File.Exists(backupFilePath)) + { + LogManager.Log("Restoring database..."); + OnProgress(BackupRestoreStage.RestoringDatabase); + try + { + var dataSource = ObservablesContext.GetActualDataSource(); + using (var dbManager = DbManager.FromDataSource(dataSource)) + { + Directory.CreateDirectory("C:\\Backups"); + var dbBackupFile = $"C:\\Backups\\{DATABASE_FILE_NAME}"; + File.Copy(backupFilePath, dbBackupFile, true); + dbManager.Restore(dataSource.Catalog, dbBackupFile); + File.Delete(dbBackupFile); + } + } + catch (Exception ex) + { + throw new IOException("Error restoring database backup", ex); + } + + LogManager.Log("Database backup completed."); + } + else + { + LogManager.Log("Database backup file not found, skipping..."); + } + + //Remove extra files from application temp folder + OnProgress(BackupRestoreStage.RemovingTemporaryFiles); + LogManager.Log("Removing redundant files from temp folder..."); + try + { + File.Delete(backupFilePath); + } + catch { } + try + { + File.Delete(Path.Combine(tempFolder, BACKUP_FILE_NAME)); + } + catch { } + + //Update firmware + var tfpFile = Path.Combine(tempFolder, "firmware_package.tfp"); + LogManager.Log($"Looking for tfp file on '{tfpFile}'..."); + if (File.Exists(tfpFile)) + { + OnProgress(BackupRestoreStage.RestoringFirmware); + LogManager.Log("Restoring firmware version..."); + + var stream = new FileStream(tfpFile, FileMode.Open); + + _machineProvider.MachineOperator.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; + + + var handler = _machineProvider.MachineOperator.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo).Result; + handler.Failed += (_, ex) => + { + stream.Dispose(); + OnRestoreException(ex, completionSource, shouldRollback, dbRollbackFile, tempFolder); + }; + handler.Completed += (_, __) => + { + OnProgress(BackupRestoreStage.RestoringFirmware, 100, 100, false); + stream.Dispose(); + LogManager.Log("Full backup restored successfully."); + OnProgress(BackupRestoreStage.Done, 100, 100, false); + completionSource.SetResult(restoreResult); + }; + handler.Canceled += (_, __) => + { + stream.Dispose(); + OnRestoreException(new Exception("The operation has been canceled."), completionSource, shouldRollback, dbRollbackFile, tempFolder); + }; + handler.Progress += (_, e) => + { + OnProgress(BackupRestoreStage.RestoringFirmware, e.Current, e.Total, false); + }; + } + else + { + LogManager.Log("Firmware package file not found, skipping..."); + OnProgress(BackupRestoreStage.Done, 100, 100, false); + completionSource.SetResult(restoreResult); + } + } + } + catch (Exception ex) + { + OnRestoreException(ex, completionSource, shouldRollback, dbRollbackFile, tempFolder); + } + }); + + return completionSource.Task; + } + + private void OnRestoreException(Exception ex, TaskCompletionSource completionSource, bool shouldRollback, String dbRollbackFile, TemporaryFolder tempFolder) + { + if (shouldRollback) + { + LogManager.Log("Rolling back database changes..."); + + var dataSource = ObservablesContext.GetActualDataSource(); + using (var dbManager = DbManager.FromDataSource(dataSource)) + { + try + { + OnProgress(BackupRestoreStage.RollingBackChanges); + dbManager.Restore(dataSource.Catalog, dbRollbackFile); + LogManager.Log("Database restored successfully."); + } + catch (Exception e) + { + LogManager.Log(e, "Error rolling back database."); + } + finally + { + try + { + File.Delete(dbRollbackFile); + } + catch { } + } + } + } + + tempFolder.Delete(); + OnProgress(BackupRestoreStage.Error, 100, 100, false); + LogManager.Log(ex, "Could not complete the restore operation."); + completionSource.SetException(ex); + } + + protected virtual void OnProgress(BackupRestoreStage stage, double progress = 0, double maxProgress = 100, bool isIntermediate = true) + { + Progress?.Invoke(this, new BackupRestoreProgressEventArgs() + { + Stage = stage, + Progress = progress, + MaxProgress = maxProgress, + IsIntermediate = isIntermediate, + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/IBackupManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/IBackupManager.cs new file mode 100644 index 000000000..ae1884677 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/IBackupManager.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + /// + /// Represents a backup/restore manager. + /// + public interface IBackupManager + { + /// + /// Occurs when the backup/restore procedure makes progress. + /// + event EventHandler Progress; + + /// + /// Creates a backup file containing database, application and firmware versions. + /// + /// The file path. + /// The backup name. + /// Backup configuration. + /// + Task CreateBackup(String filePath, String name, BackupSettings settings); + + /// + /// Restores a backup located in the specified file path. + /// + /// The file path. + /// The restore settings + /// + Task Restore(String filePath, RestoreSettings settings); + + /// + /// Extracts the backup configuration from the specified backup file. + /// + /// The file path. + /// + Task ExtractBackupConfiguration(String filePath); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreResult.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreResult.cs new file mode 100644 index 000000000..5f10aebcf --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreResult.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.BackupRestore +{ + public class RestoreResult + { + public String FolderPath { get; set; } + public BackupFile BackupFile { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreSettings.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreSettings.cs new file mode 100644 index 000000000..a5b343302 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreSettings.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Common.BackupRestore +{ + public class RestoreSettings : ExtendedObject + { + private bool _allowDeleteJobs; + public bool AllowDeleteJobs + { + get { return _allowDeleteJobs; } + set { _allowDeleteJobs = value; RaisePropertyChangedAuto(); } + } + + private bool _overwriteExistingJobs; + public bool OverwriteExistingJobs + { + get { return _overwriteExistingJobs; } + set { _overwriteExistingJobs = value; RaisePropertyChangedAuto(); } + } + + public RestoreSettings() + { + OverwriteExistingJobs = true; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs index a16e2f649..b2c752ca8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs @@ -21,6 +21,7 @@ using Tango.Integration; using Tango.Transport; using System.Threading; using Tango.Core.ExtensionMethods; +using System.IO.Ports; namespace Tango.PPC.Common.Connection { @@ -35,6 +36,26 @@ namespace Tango.PPC.Common.Connection private Thread _connection_thread; private ObservablesContext _context; + /// + /// Occurs when the machine has connected. + /// + public event EventHandler MachineConnected; + + /// + /// Occurs when the machine has disconnected. + /// + public event EventHandler MachineDisconnected; + + private bool _isConnected; + /// + /// Gets a value indicating whether the machine is currently connected. + /// + public bool IsConnected + { + get { return _isConnected; } + private set { _isConnected = value; RaisePropertyChangedAuto(); } + } + private Machine _machine; /// /// Gets the database machine entity associated with the current machine. @@ -74,18 +95,24 @@ namespace Tango.PPC.Common.Connection /// public DefaultMachineProvider() { + var settings = SettingsManager.Default.GetOrCreate(); + MachineOperator = new MachineOperator(); + MachineOperator.StatusChanged += MachineOperator_StatusChanged; MachineOperator.EnableEventsNotification = true; MachineOperator.EnableJobResume = true; MachineOperator.UseKeepAlive = true; MachineOperator.EnableMachineStatusUpdates = true; - MachineOperator.EnableDiagnostics = false; - MachineOperator.EnableEmbeddedDebugging = false; - MachineOperator.FirmwareUpgradeMode = Integration.Upgrade.FirmwareUpgradeModes.DFU | Integration.Upgrade.FirmwareUpgradeModes.TFP_PACKAGE; + MachineOperator.EnableDiagnostics = true; + MachineOperator.EnablePowerUpSequence = true; + MachineOperator.EnableEmbeddedDebugging = settings.EnableEmbeddedDebugLogs; + MachineOperator.EnableAutomaticThreadLoading = settings.EnableAutomaticThreadLoading; + MachineOperator.JobRunsLogger.JobSource = BL.Enumerations.JobSource.Local; - var settings = SettingsManager.Default.GetOrCreate(); + MachineOperator.FirmwareUpgradeMode = Integration.Upgrade.FirmwareUpgradeModes.DFU | Integration.Upgrade.FirmwareUpgradeModes.TFP_PACKAGE; MachineOperator.JobUploadStrategy = settings.JobUploadStrategy; + MachineOperator.JobUnitsMethod = settings.JobUnitsMethod; MachineOperator.GradientGenerationConfiguration.IsEnabled = settings.EnableGradientGeneration; MachineOperator.GradientGenerationConfiguration.ResolutionCM = settings.GradientGenerationResolution; @@ -96,8 +123,28 @@ namespace Tango.PPC.Common.Connection MachineOperator.EnableJobLiquidQuantityValidation = settings.EnableJobLiquidQuantityValidation; } + private void MachineOperator_StatusChanged(object sender, MachineStatuses status) + { + if (status != MachineStatuses.Disconnected) + { + if (!IsConnected) + { + OnMachineConnected(); + } + } + else + { + if (IsConnected) + { + OnMachineDisconnected(); + } + } + } + private async void ConnectionThreadMethod() { + bool fileLoggingDisabled = false; + while (true) { if (MachineOperator.State != TransportComponentState.Connected) @@ -106,7 +153,10 @@ namespace Tango.PPC.Common.Connection { Thread.Sleep(2000); - LogManager.Log("Starting machine connection procedure...", LogCategory.Debug); + if (!fileLoggingDisabled) + { + LogManager.Log("Starting machine connection procedure...", LogCategory.Info); + } var settings = SettingsManager.Default.GetOrCreate(); @@ -116,22 +166,28 @@ namespace Tango.PPC.Common.Connection { TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate().MachineScanningTimeoutSeconds); - LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Debug); + LogManager.Log("Scanning for machine on available serial ports...", LogCategory.Info); Transport.Discovery.UsbCommunicationScanner scanner = new Transport.Discovery.UsbCommunicationScanner(UsbSerialBaudRates.BR_115200); var response = await scanner.Scan(new ConnectRequest() { Password = "1234" }, settings.EmbeddedDeviceHint, timeout); - LogManager.Log("Machine discovered on port: " + response.Adapter.Address, LogCategory.Debug); + LogManager.Log("Machine discovered on port: " + response.Adapter.Address, LogCategory.Info); LogManager.Log("Device Information:", LogCategory.Debug); - LogManager.Log(response.Response.DeviceInformation.ToJsonString(), LogCategory.Debug); + LogManager.Log(response.Response.DeviceInformation.ToJsonString(), LogCategory.Info); - LogManager.Log("Disconnecting machine operator...", LogCategory.Debug); + LogManager.Log("Disconnecting machine operator...", LogCategory.Info); await MachineOperator.Disconnect(); MachineOperator.Adapter = response.Adapter; MachineOperator.JobHandlingMode = JobHandlerModes.SettingUp; - LogManager.Log("Connecting machine operator...", LogCategory.Debug); + LogManager.Log("Connecting machine operator...", LogCategory.Info); try { await MachineOperator.Connect(); + + if (MachineOperator.DeviceInformation != null) + { + settings.FirmwareVersion = MachineOperator.DeviceInformation.Version; + settings.Save(); + } } catch (Exception) { @@ -146,7 +202,17 @@ namespace Tango.PPC.Common.Connection } else { - LogManager.Log($"Connecting to machine on {settings.EmbeddedComPort}...", LogCategory.Debug); + //Perform a pre-test to not overload the log file when machine is off for a long time. + using (SerialPort preCheckSerialPort = new SerialPort(settings.EmbeddedComPort)) + { + preCheckSerialPort.BaudRate = UsbSerialBaudRates.BR_115200.ToInt32(); + preCheckSerialPort.Open(); + preCheckSerialPort.Close(); + fileLoggingDisabled = false; + Thread.Sleep(500); //Wait a little while to not scare the other side?.. + } + + LogManager.Log($"Connecting to machine on {settings.EmbeddedComPort}...", LogCategory.Info); UsbTransportAdapter adapter = new UsbTransportAdapter(settings.EmbeddedComPort, UsbSerialBaudRates.BR_115200); MachineOperator.Adapter = adapter; @@ -154,6 +220,12 @@ namespace Tango.PPC.Common.Connection try { await MachineOperator.Connect(); + + if (MachineOperator.DeviceInformation != null) + { + settings.FirmwareVersion = MachineOperator.DeviceInformation.Version; + settings.Save(); + } } catch (Exception) { @@ -184,13 +256,24 @@ namespace Tango.PPC.Common.Connection LogManager.Log("Connecting machine operator..."); await MachineOperator.Connect(); + if (MachineOperator.DeviceInformation != null) + { + settings.FirmwareVersion = MachineOperator.DeviceInformation.Version; + settings.Save(); + } + await Task.Delay(1000); await MachineOperator.UploadHardwareConfiguration(Machine.Configuration.HardwareVersion, Machine.Configuration); } } catch (Exception ex) { - LogManager.Log(ex, LogCategory.Debug, "Error while trying to scan and connect to the machine."); + if (!fileLoggingDisabled || LogManager.Categories.Contains(LogCategory.Debug)) + { + LogManager.Log(ex, "Error while trying to scan and connect to the machine."); + LogManager.Log("Application logging of further connection attempts is now disabled and will resume when connection is successful."); + fileLoggingDisabled = true; + } } } @@ -217,6 +300,15 @@ namespace Tango.PPC.Common.Connection if (Machine != null) { LogManager.Log("First machine entry found. Machine serial number is: " + Machine.SerialNumber + "."); + + if (Machine.IsDemo) + { + LogManager.Log("Machine is in demo mode. Changing firmware upgrade mode to TFP package only."); + MachineOperator.FirmwareUpgradeMode = Integration.Upgrade.FirmwareUpgradeModes.TFP_PACKAGE; + } + + MachineOperator.JobRunsLogger.SetDefaultMachine(Machine); + ConnectToMachine(); } else @@ -247,7 +339,7 @@ namespace Tango.PPC.Common.Connection public async Task SaveMachine() { await _context.SaveChangesAsync(); - Machine = await new MachineBuilder(_context).SetFirst().WithSettings().BuildAsync(); + Machine = await new MachineBuilder(_context).SetFirst().BuildAsync(); TangoMessenger.Default.Send(new MachineSettingsSavedMessage() { Machine = Machine }); } @@ -304,5 +396,23 @@ namespace Tango.PPC.Common.Connection return machineOperator; } + + /// + /// Called when the machine has connected. + /// + protected virtual void OnMachineConnected() + { + IsConnected = true; + MachineConnected?.Invoke(this, new EventArgs()); + } + + /// + /// Called when the machine has disconnected. + /// + protected virtual void OnMachineDisconnected() + { + IsConnected = false; + MachineDisconnected?.Invoke(this, new EventArgs()); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/IMachineProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/IMachineProvider.cs index 10180b9cc..774fa7c9e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/IMachineProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/IMachineProvider.cs @@ -15,6 +15,21 @@ namespace Tango.PPC.Common.Connection /// public interface IMachineProvider { + /// + /// Occurs when the machine has connected. + /// + event EventHandler MachineConnected; + + /// + /// Occurs when the machine has disconnected. + /// + event EventHandler MachineDisconnected; + + /// + /// Gets a value indicating whether the machine is currently connected. + /// + bool IsConnected { get; } + /// /// Gets the database machine entity associated with the current machine. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connectivity/IConnectivityProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connectivity/IConnectivityProvider.cs index 67b73d4f6..39404934d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Connectivity/IConnectivityProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Connectivity/IConnectivityProvider.cs @@ -20,10 +20,15 @@ namespace Tango.PPC.Common.Connectivity event EventHandler ConnectionStateChanged; /// - /// Gets a value indicating whether there is any Internet connection available. + /// Gets a value indicating whether there is a WiFi connection. /// bool IsConnected { get; } + /// + /// Gets a value indicating whether there is LAN connection. + /// + bool IsLanConnected { get; } + /// /// Gets the available WiFi networks. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs new file mode 100644 index 000000000..94b677b18 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Console; +using Tango.Console.Network; +using Tango.Core; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.Transport; + +namespace Tango.PPC.Common.Console +{ + /// + /// Represents the default implementation + /// which listens to incoming console request by registering as a external bridge request handler. + /// + /// + /// + [TangoCreateWhenRegistered] + public class DefaultConsoleEngineService : ExtendedObject, IConsoleEngineService, IExternalBridgeRequestHandler + { + /// + /// Gets or sets a value indicating whether this is enabled. + /// + public bool Enabled { get; set; } = true; + + /// + /// Initializes a new instance of the class. + /// + /// The external bridge service instance. + public DefaultConsoleEngineService(IPPCExternalBridgeService externalBridge) + { + externalBridge.RegisterRequestHandler(this); + } + + /// + /// Handles requests. + /// + /// The request. + /// The token. + /// The transporter. + [ExternalBridgeRequestHandlerMethod(typeof(GetCurrentDirectoryRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetCurrentDirectoryRequest(GetCurrentDirectoryRequest request, String token, ITransporter transporter) + { + this.ThrowIfDisabled(); + + await transporter.SendGenericResponse(new GetCurrentDirectoryResponse() + { + CurrentDirectory = Environment.CurrentDirectory, + Suggestions = ConsoleExecutionEngine.GetSuggestions(Environment.CurrentDirectory) + }, token); + } + + /// + /// Handles requests. + /// + /// The request. + /// The token. + /// The transporter. + [ExternalBridgeRequestHandlerMethod(typeof(ConsoleCommandRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnConsoleCommandRequest(ConsoleCommandRequest request, String token, ITransporter transporter) + { + this.ThrowIfDisabled(); + + LogManager.Log($"{nameof(ConsoleCommandRequest)} received with command '{request.Command}'. Executing..."); + + ConsoleExecutionEngine engine = new ConsoleExecutionEngine(); + var result = await engine.Execute(request); + + LogManager.Log("Console command executed successfully."); + + await transporter.SendGenericResponse(new ConsoleCommandResponse() + { + Output = result.Output, + Suggestions = result.Suggestions, + WorkingFolder = result.WorkingFolder + }, token); + } + + /// + /// Called when any of the external bridge clients (receivers) has disconnected. + /// + /// The receiver. + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do nothing. + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs new file mode 100644 index 000000000..18edb3629 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Console +{ + /// + /// Represents a command prompt console service which listens for incoming console requests. + /// + public interface IConsoleEngineService : IPPCService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.cs new file mode 100644 index 000000000..ba2550e25 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using Tango.SharedUI.Controls; + +namespace Tango.PPC.Common.Controls +{ + [ContentProperty(nameof(Elements))] + public class ImageGalleryControl : Control + { + private NavigationControl _navigationControl; + private DispatcherTimer _timer; + + public int SelectedIndex + { + get { return (int)GetValue(SelectedIndexProperty); } + set { SetValue(SelectedIndexProperty, value); } + } + public static readonly DependencyProperty SelectedIndexProperty = + DependencyProperty.Register("SelectedIndex", typeof(int), typeof(ImageGalleryControl), new PropertyMetadata(0)); + + public ObservableCollection Elements + { + get { return (ObservableCollection)GetValue(ElementsProperty); } + set { SetValue(ElementsProperty, value); } + } + public static readonly DependencyProperty ElementsProperty = + DependencyProperty.Register("Elements", typeof(ObservableCollection), typeof(ImageGalleryControl), new PropertyMetadata(null)); + + public Duration Duration + { + get { return (Duration)GetValue(DurationProperty); } + set { SetValue(DurationProperty, value); } + } + public static readonly DependencyProperty DurationProperty = + DependencyProperty.Register("Duration", typeof(Duration), typeof(ImageGalleryControl), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(2)))); + + + static ImageGalleryControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageGalleryControl), new FrameworkPropertyMetadata(typeof(ImageGalleryControl))); + } + + public ImageGalleryControl() + { + Elements = new ObservableCollection(); + Loaded += ImageGalleryControl_Loaded; + + _timer = new DispatcherTimer(); + _timer.Tick += _timer_Tick; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _navigationControl = GetTemplateChild("navigationControl") as NavigationControl; + } + + private void ImageGalleryControl_Loaded(object sender, RoutedEventArgs e) + { + if (_navigationControl != null) + { + _navigationControl.Elements = Elements; + + _timer.Interval = Duration.TimeSpan; + + if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) + { + _timer.Start(); + } + } + } + + private void _timer_Tick(object sender, EventArgs e) + { + if (SelectedIndex < Elements.Count - 1) + { + SelectedIndex++; + } + else + { + SelectedIndex = 0; + } + } + + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); + _timer.Stop(); + } + + protected override void OnPreviewMouseUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseUp(e); + _timer.Start(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.xaml new file mode 100644 index 000000000..495335ff1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.xaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs new file mode 100644 index 000000000..02539aed9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs @@ -0,0 +1,492 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.DataStore; +using Tango.DataStore.EF; +using Tango.DataStore.Lite; +using Tango.DataStore.Remote; +using Tango.Integration.ExternalBridge; +using Tango.PMR.DataStore; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.ExternalBridge; +using Tango.Transport; +using Tango.Core.ExtensionMethods; +using Newtonsoft.Json.Linq; +using Tango.BL; +using Tango.DataStore.Editing; +using Newtonsoft.Json; +using Tango.Core; + +namespace Tango.PPC.Common.DataStore +{ + [TangoCreateWhenRegistered] + public class DefaultDataStoreService : ExtendedObject, IDataStoreService, IExternalBridgeRequestHandler + { + private IDataStoreManager _manager; + private IMachineProvider _machineProvider; + private List _listenerReceivers; + + private class ListerReceiver + { + public String Token { get; set; } + public ExternalBridgeReceiver Receiver { get; set; } + } + + public DefaultDataStoreService(IPPCExternalBridgeService externalBridge, IMachineProvider machineProvider) + { + externalBridge.RegisterRequestHandler(this); + + + _listenerReceivers = new List(); + _machineProvider = machineProvider; + machineProvider.MachineOperator.RegisterRequestHandler(OnPutDataStoreItemRequest); + machineProvider.MachineOperator.RegisterRequestHandler(OnGetDataStoreItemRequest); + } + + public IDataStoreManager GetManager() + { + if (_manager == null) + { + _manager = new EFDataStoreManager(); + } + + return _manager; + } + + public void Dispose() + { + _manager?.Dispose(); + } + + #region Generic Handlers + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStorePutRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStorePutRequest(RemoteDataStorePutRequest request, String token, ExternalBridgeReceiver receiver) + { + ValidateCollectionAndKey(request.Collection, request.Key); + GetManager().GetCollection(request.Collection).Put(request.Key, request.Value); + await receiver.SendGenericResponse(new RemoteDataStorePutResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreGetRequest(RemoteDataStoreGetRequest request, String token, ExternalBridgeReceiver receiver) + { + ValidateCollectionAndKey(request.Collection, request.Key); + + if (request.DefaultValue is JObject obj) + { + request.DefaultValue = DataStoreProtoObject.FromJObject(obj); + } + + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key, request.DefaultValue); + await receiver.SendGenericResponse(new RemoteDataStoreGetResponse() + { + DataType = item.Type, + Value = item.Value, + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetItemRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreGetItemRequest(RemoteDataStoreGetItemRequest request, String token, ExternalBridgeReceiver receiver) + { + ValidateCollectionAndKey(request.Collection, request.Key); + + if (request.DefaultValue is JObject obj) + { + request.DefaultValue = DataStoreProtoObject.FromJObject(obj); + } + + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key, request.DefaultValue); + await receiver.SendGenericResponse(new RemoteDataStoreGetItemResponse() + { + Item = CreateRemoteItem(item) + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreCountRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreCountRequest(RemoteDataStoreCountRequest request, String token, ExternalBridgeReceiver receiver) + { + var count = GetManager().GetCollection(request.Collection).Count(); + await receiver.SendGenericResponse(new RemoteDataStoreCountResponse() + { + Count = count + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreDeleteRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreDeleteRequest(RemoteDataStoreDeleteRequest request, String token, ExternalBridgeReceiver receiver) + { + throw new InvalidOperationException("Deleting from the data store is not allowed."); + GetManager().GetCollection(request.Collection).Delete(request.Key); + await receiver.SendGenericResponse(new RemoteDataStoreDeleteResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreDeleteAllRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreDeleteAllRequest(RemoteDataStoreDeleteAllRequest request, String token, ExternalBridgeReceiver receiver) + { + throw new InvalidOperationException("Deleting from the data store is not allowed."); + GetManager().GetCollection(request.Collection).DeleteAll(); + await receiver.SendGenericResponse(new RemoteDataStoreDeleteAllResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetAllRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreGetAllRequest(RemoteDataStoreGetAllRequest request, String token, ExternalBridgeReceiver receiver) + { + var all = GetManager().GetCollection(request.Collection).GetAll(); + await receiver.SendGenericResponse(new RemoteDataStoreGetAllResponse() + { + Items = all.Select(x => CreateRemoteItem(x)).ToList() + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetCollectionNamesRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreGetCollectionNamesRequest(RemoteDataStoreGetCollectionNamesRequest request, String token, ExternalBridgeReceiver receiver) + { + var names = GetManager().GetCollectionNames(); + await receiver.SendGenericResponse(new RemoteDataStoreGetCollectionNamesResponse() + { + Names = names + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreGetAllItemsRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreGetAllItemsRequest(RemoteDataStoreGetAllItemsRequest request, String token, ExternalBridgeReceiver receiver) + { + List collections = new List(); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var items = db.DataStoreItems.Where(x => !x.IsDeleted).ToList(); + + foreach (var itemsGroup in items.GroupBy(x => x.CollectionName)) + { + RemoteDataStoreCollection collection = new RemoteDataStoreCollection(); + collection.Name = itemsGroup.First().CollectionName; + collections.Add(collection); + + foreach (var item in itemsGroup) + { + collection.Items.Add(CreateRemoteItem(item.ToDataStoreItem())); + } + } + } + + await receiver.SendGenericResponse(new RemoteDataStoreGetAllItemsResponse() + { + Collections = collections + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(UpdateDataStoreRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnUpdateDataStoreRequest(UpdateDataStoreRequest request, String token, ExternalBridgeReceiver receiver) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var allItems = db.DataStoreItems.ToList(); + + List deleted = new List(); + + foreach (var guid in request.ToDelete) + { + var item = allItems.FirstOrDefault(x => x.Guid == guid); + if (item != null) + { + item.IsDeleted = true; + item.IsSynchronized = true; + item.LastUpdated = DateTime.UtcNow; + deleted.Add(item); + } + } + + foreach (var item in request.ToUpsert) + { + ValidateCollectionAndKey(item.CollectionName, item.Key); + } + + foreach (var item in request.ToUpsert) + { + var itemDb = allItems.FirstOrDefault(x => x.CollectionName == item.CollectionName && x.Key == item.Key); + + if (itemDb == null) + { + itemDb = new BL.Entities.DataStoreItem(); + itemDb.Guid = item.Guid; + db.DataStoreItems.Add(itemDb); + } + + itemDb.CollectionName = item.CollectionName; + itemDb.DataType = item.DataType; + itemDb.IsDeleted = item.IsDeleted; + itemDb.IsSynchronized = true; + itemDb.Key = item.Key; + itemDb.LastUpdated = item.LastUpdated; + itemDb.Value = item.Value; + } + + db.SaveChanges(); + + if (_machineProvider.IsConnected) + { + Core.Threading.ThreadFactory.StartNew(() => + { + foreach (var item in request.ToUpsert) + { + try + { + var response = _machineProvider.MachineOperator.SendRequest(new DataStoreItemModifiedRequest() + { + Collection = item.CollectionName, + Key = item.Key + }).Result; + } + catch (Exception ex) + { + Logging.LogManager.Default.Log(ex, $"Error notifying firmware about data store item change '{item.CollectionName}.{item.Key}'."); + } + } + + foreach (var item in deleted) + { + try + { + var response = _machineProvider.MachineOperator.SendRequest(new DataStoreItemModifiedRequest() + { + Collection = item.CollectionName, + Key = item.Key + }).Result; + } + catch (Exception ex) + { + Logging.LogManager.Default.Log(ex, $"Error notifying firmware about data store item change '{item.CollectionName}.{item.Key}'."); + } + } + }); + } + } + + await receiver.SendGenericResponse(new UpdateDataStoreResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDataStoreStartListenRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDataStoreStartListenRequest(RemoteDataStoreStartListenRequest request, String token, ExternalBridgeReceiver receiver) + { + _listenerReceivers.Add(new ListerReceiver() { Receiver = receiver, Token = token }); + + await receiver.SendGenericResponse(new RemoteDataStoreStartListenResponse() + { + ChangeType = RemoteDataStoreChangeType.None, + Item = null + }, token); + } + + private RemoteDataStoreItem CreateRemoteItem(IDataStoreItem item) + { + RemoteDataStoreItem remote = new RemoteDataStoreItem(); + + item.MapPropertiesTo(remote, MappingFlags.All); + + return remote; + } + + #endregion + + #region Proto Handlers + + private async void OnPutDataStoreItemRequest(ITransporter transporter, PutDataStoreItemRequest request, string token) + { + try + { + ValidateCollectionAndKey(request.Collection, request.Key); + + GetManager().GetCollection(request.Collection).Put(request.Key, GetPMRValue(request.Item)); + await transporter.SendResponse(new PutDataStoreItemResponse(), token); + + try + { + if (_listenerReceivers.Count > 0) + { + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key); + var remoteItem = CreateRemoteItem(item); + + foreach (var listener in _listenerReceivers.ToList()) + { + try + { + await listener.Receiver.SendGenericResponse(new RemoteDataStoreStartListenResponse() + { + ChangeType = RemoteDataStoreChangeType.Modified, + CollectionName = request.Collection, + Item = remoteItem + }, listener.Token); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error sending data store item notification to receiver '{listener.Receiver.Adapter.ToString()}'"); + } + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating data store item notifications."); + } + } + catch (Exception ex) + { + try + { + await transporter.SendResponse(new PutDataStoreItemResponse(), token, new TransportResponseConfig() + { + ErrorCode = PMR.Common.ErrorCode.GeneralDatastoreError, + ErrorMessage = ex.Message + }); + } + catch (Exception exx) + { + Debug.WriteLine(exx); + } + } + } + + private async void OnGetDataStoreItemRequest(ITransporter transporter, GetDataStoreItemRequest request, string token) + { + try + { + ValidateCollectionAndKey(request.Collection, request.Key); + + var item = GetManager().GetCollection(request.Collection).GetItem(request.Key, GetPMRValue(request.DefaultItem)); + await transporter.SendResponse(new GetDataStoreItemResponse() + { + Key = item.Key, + Item = CreatePMRDataStoreItem(item), + }, token); + } + catch (KeyNotFoundException ex) + { + try + { + await transporter.SendResponse(new GetDataStoreItemResponse(), token, new TransportResponseConfig() + { + ErrorCode = PMR.Common.ErrorCode.KeyNotFound, + ErrorMessage = ex.Message + }); + } + catch (Exception exx) + { + Debug.WriteLine(exx); + } + } + catch (Exception ex) + { + try + { + await transporter.SendResponse(new GetDataStoreItemResponse(), token, new TransportResponseConfig() + { + ErrorCode = PMR.Common.ErrorCode.GeneralDatastoreError, + ErrorMessage = ex.Message + }); + } + catch (Exception exx) + { + Debug.WriteLine(exx); + } + } + } + + #region Helpers + + private DataStoreItem CreatePMRDataStoreItem(IDataStoreItem item) + { + DataStoreItem pmr = new DataStoreItem(); + pmr.DataType = (PMR.DataStore.DataType)item.Type; + + switch (item.Type) + { + case Tango.DataStore.DataType.Int32: + pmr.Int32Value = (int)Convert.ChangeType(item.Value, typeof(int)); + break; + case Tango.DataStore.DataType.Float: + pmr.FloatValue = (float)Convert.ChangeType(item.Value, typeof(float)); + break; + case Tango.DataStore.DataType.Double: + pmr.DoubleValue = (double)Convert.ChangeType(item.Value, typeof(double)); + break; + case Tango.DataStore.DataType.Boolean: + pmr.BooleanValue = (bool)Convert.ChangeType(item.Value, typeof(bool)); + break; + case Tango.DataStore.DataType.String: + pmr.StringValue = (String)Convert.ChangeType(item.Value, typeof(String)); + break; + case Tango.DataStore.DataType.Bytes: + pmr.BytesValue = Google.Protobuf.ByteString.CopyFrom((byte[])Convert.ChangeType(item.Value, typeof(byte[]))); + break; + case Tango.DataStore.DataType.Proto: + DataStoreProtoObject proto = item.Value as DataStoreProtoObject; + pmr.BytesValue = Google.Protobuf.ByteString.CopyFrom(proto.Data); + pmr.ProtoType = proto.MessageType; + break; + } + + return pmr; + } + + private Object GetPMRValue(DataStoreItem item) + { + if (item == null) return null; + + switch (item.DataType) + { + case PMR.DataStore.DataType.Int32: + return item.Int32Value; + case PMR.DataStore.DataType.Float: + return item.FloatValue; + case PMR.DataStore.DataType.Double: + return item.DoubleValue; + case PMR.DataStore.DataType.Boolean: + return item.BooleanValue; + case PMR.DataStore.DataType.String: + return item.StringValue; + case PMR.DataStore.DataType.Bytes: + return item.BytesValue.ToByteArray(); + case PMR.DataStore.DataType.Proto: + return DataStoreProtoObject.FromPMRDataStoreItem(item); + } + + throw new NotSupportedException("The specified data type if not supported."); + } + + #endregion + + #endregion + + private void ValidateCollectionAndKey(String collection = null, String key = null) + { + if (collection != null) + { + if (!DataStoreHelper.ValidateCollectionOrKeyName(collection)) + { + throw new ArgumentException("Collection name contains invalid characters."); + } + } + + if (key != null) + { + if (!DataStoreHelper.ValidateCollectionOrKeyName(key)) + { + throw new ArgumentException("Item key contains invalid characters."); + } + } + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do nothing. + _listenerReceivers.RemoveAll(x => x.Receiver == receiver); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/IDataStoreService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/IDataStoreService.cs new file mode 100644 index 000000000..94ae3fa30 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/IDataStoreService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.DataStore; + +namespace Tango.PPC.Common.DataStore +{ + public interface IDataStoreService : IDisposable + { + IDataStoreManager GetManager(); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/DefaultEventLogger.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/DefaultEventLogger.cs index f9674e409..ee96a77a5 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/DefaultEventLogger.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/DefaultEventLogger.cs @@ -16,6 +16,10 @@ using Tango.Integration.Operation; using Tango.PPC.Common.Application; using Tango.PPC.Common.Authentication; using Tango.PPC.Common.Connection; +using Tango.Transport; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Events; +using Tango.Core.DI; namespace Tango.PPC.Common.EventLogging { @@ -35,6 +39,7 @@ namespace Tango.PPC.Common.EventLogging private bool _isInitialized; private List _pendingEvents; private List _currentEvents; + private Machine _machine; #region Events @@ -50,6 +55,21 @@ namespace Tango.PPC.Common.EventLogging #endregion + private IPPCExternalBridgeService _externalBridge; + [TangoInject(Mode = TangoInjectMode.WhenAvailable)] + public IPPCExternalBridgeService ExternalBridgeService + { + get { return _externalBridge; } + set + { + if (_externalBridge != value) + { + _externalBridge = value; + _externalBridge.RegisterRequestHandler(this); + } + } + } + #region Constructors /// @@ -84,7 +104,6 @@ namespace Tango.PPC.Common.EventLogging _machineProvider.MachineOperator.PrintingAborted += MachineOperator_PrintingAborted; _machineProvider.MachineOperator.PrintingCompleted += MachineOperator_PrintingCompleted; _machineProvider.MachineOperator.PrintingFailed += MachineOperator_PrintingFailed; - } #endregion @@ -99,18 +118,28 @@ namespace Tango.PPC.Common.EventLogging { _db = ObservablesContext.CreateDefault(); + _machine = _db.Machines.FirstOrDefault(); + _db.EventTypes.ToList(); foreach (var type in _db.EventTypes) { - _eventTypesGuids.Add((EventTypes)type.Code, type); + try + { + _eventTypesGuids.Add((EventTypes)type.Code, type); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error initializing event type '{type.Name}'."); + } } _isInitialized = true; } - catch + catch (Exception ex) { _isInitialized = false; + LogManager.Log(ex, "Error initializing event types."); } } } @@ -250,7 +279,7 @@ namespace Tango.PPC.Common.EventLogging machineEvent.HostName = _hostName; machineEvent.EventType = _eventTypesGuids[machineEvent.Type]; - if (_machineProvider.MachineOperator == null || _authentication.CurrentUser == null) + if (_machine == null) { _pendingEvents.Add(machineEvent); } @@ -268,14 +297,14 @@ namespace Tango.PPC.Common.EventLogging } LogManager.Log("Logging event " + machineEvent.EventType.Name); - machineEvent.MachineGuid = _machineProvider.Machine.Guid; - machineEvent.UserGuid = _authentication.CurrentUser.Guid; - machineEvent.User = _authentication.CurrentUser; + machineEvent.MachineGuid = _machine.Guid; + machineEvent.UserGuid = null; + machineEvent.User = null; _events.Enqueue(machineEvent); if (!_currentEvents.Exists(x => x.Type == machineEvent.Type)) { - if (machineEvent.Group != EventTypeGroups.Application && machineEvent.Group != EventTypeGroups.Transport) + if (machineEvent.Group != EventTypeGroups.Application && machineEvent.Group != EventTypeGroups.Transport && machineEvent.Group != EventTypeGroups.Jobs) { _currentEvents.Add(machineEvent); } @@ -385,5 +414,21 @@ namespace Tango.PPC.Common.EventLogging } #endregion + + #region External Bridge Handler + + [ExternalBridgeRequestHandlerMethod(typeof(PushEmulatedEventRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnStartPerformanceUpdatesRequest(PushEmulatedEventRequest request, String token, ExternalBridgeReceiver receiver) + { + _machineProvider.MachineOperator.PushEmulatedEvent(request.Event, request.Timeout); + await receiver.SendGenericResponse(new PushEmulatedEventResponse(), token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + + } + + #endregion } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/IEventLogger.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/IEventLogger.cs index 10560e034..81cce927d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/IEventLogger.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/IEventLogger.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.BL.Enumerations; +using Tango.Integration.ExternalBridge; using Tango.PMR.Diagnostics; namespace Tango.PPC.Common.EventLogging @@ -12,7 +13,7 @@ namespace Tango.PPC.Common.EventLogging /// /// Represents a database events logger. /// - public interface IEventLogger + public interface IEventLogger : IExternalBridgeRequestHandler { /// /// Occurs when a new machine event has been received. diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs index c50202e86..99951d812 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.Core.DI; +using Tango.Core.Helpers; +using Tango.CSV; using Tango.Integration.ExternalBridge; using Tango.Integration.Operation; +using Tango.PMR.Common; using Tango.PPC.Common.Application; using Tango.PPC.Common.Connection; using Tango.PPC.Common.Messages; @@ -14,6 +18,11 @@ using Tango.Settings; namespace Tango.PPC.Common.ExternalBridge { + public class CsvEntry + { + public String MessageType { get; set; } + } + /// /// Represents the PPC external bridge service capable of exposing a remote API for communicating and controlling the machine through the PPC. /// @@ -28,11 +37,36 @@ namespace Tango.PPC.Common.ExternalBridge /// The machine provider. public PPCExternalBridgeService(IPPCApplicationManager applicationManager, IMachineProvider machineProvider) { - applicationManager.ApplicationReady += (_, __) => + var csvStream = EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.PPC.Common.SafetyLevelOperations.csv"); + + List entries = CsvFile.Read(new CsvSource(csvStream)).ToList(); + + foreach (var entry in entries) + { + MessageType type; + if (Enum.TryParse(entry.MessageType, out type)) + { + ExternalBridgeService.SafetyLevelOperations.Add(type); + } + } + + applicationManager.ApplicationReady += (_, __) => { var settings = SettingsManager.Default.GetOrCreate(); + //TODO: Configure external bridge for configure protocol enforce... MachineOperator = machineProvider.MachineOperator; Machine = machineProvider.Machine; + SignalRConfiguration.Enabled = settings.EnableExternalBridgeSignalR; + TcpTransportAdapterWriteMode = settings.TcpTransportAdapterWriteMode; + if (Environment.CommandLine.Contains("-webDebug")) + { + SignalRConfiguration.Address = "http://localhost:1111/"; //settings.DeploymentSlot.ToAddress(); + } + else + { + SignalRConfiguration.Address = settings.DeploymentSlot.ToAddress(); + } + SignalRConfiguration.Hub = settings.ExternalBridgeSignalRHub; Enabled = settings.EnableExternalBridge; }; } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs new file mode 100644 index 000000000..8272ea34d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs @@ -0,0 +1,433 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.DI; +using Tango.Core.IO; +using Tango.FileSystem; +using Tango.FileSystem.Network; +using Tango.Integration.ExternalBridge; +using Tango.Integration.Operation; +using Tango.Logging; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Logs; +using Tango.Settings; +using Tango.Transport; +using Tango.Transport.Transporters; +using Tango.WebRTC; + +namespace Tango.PPC.Common.FileSystem +{ + /// + /// Represents the default implementation. + /// + /// + /// + /// + [TangoCreateWhenRegistered] + public class DefaultFileSystemService : ExtendedObject, IFileSystemService, IExternalBridgeRequestHandler + { + private FileSystemManager _manager; + private Dictionary _operations; + private Dictionary _webRtcClients; + private PPCSettings _settings; + + public bool Enabled { get; set; } = true; + public bool EnableWebRTC { get; set; } = true; + + public DefaultFileSystemService(IPPCExternalBridgeService externalBridge) + { + _webRtcClients = new Dictionary(); + _manager = new FileSystemManager(); + _operations = new Dictionary(); + externalBridge.RegisterRequestHandler(this); + _settings = SettingsManager.Default.GetOrCreate(); + } + + [ExternalBridgeRequestHandlerMethod(typeof(InitWebRtcRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnInitWebRtcRequest(InitWebRtcRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + try + { + if (!EnableWebRTC) + { + await receiver.SendErrorResponse(new InvalidOperationException("The file system service WebRTC channel is disabled on this machine."), token); + return; + } + + LogManager.Log("Initializing WebRTC channel for file system service."); + + if (_webRtcClients.ContainsKey(receiver)) + { + _webRtcClients[receiver].Dispose(); + } + + LogManager.Log("Initializing WebRTC transport adapter on 'Passive' mode."); + var webRtcAdapter = new WebRtcTransportAdapter(receiver, WebRtcTransportAdapterMode.Passive, request.DataChannelName) + { + EnableCompression = receiver.Adapter.EnableCompression + }; + webRtcAdapter.Ready += (x, e) => + { + LogManager.Log("The file system service WebRTC channel is ready."); + }; + + BasicTransporter webRtcTransporter = new BasicTransporter(webRtcAdapter); + webRtcTransporter.GenericProtocol = receiver.GenericProtocol; + webRtcTransporter.ComponentName = "File System Passive WebRTC Transporter"; + webRtcTransporter.UseKeepAlive = false; + webRtcTransporter.RegisterRequestHandler(WebRtcChunkDownloadRequestReceived); + webRtcTransporter.RegisterRequestHandler(WebRtcChunkUploadRequestReceived); + await webRtcTransporter.Connect(); + + LogManager.Log("Sending WebRTC initialization response..."); + + await receiver.SendGenericResponse(new InitWebRtcResponse(), token); + _webRtcClients[receiver] = webRtcTransporter; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error initializing WebRTC channel for file system service."); + await receiver.SendErrorResponse(ex, token); + } + } + + private async void WebRtcChunkDownloadRequestReceived(ITransporter transporter, ChunkDownloadRequest request, string token) + { + await OnChunkDownloadRequest(request, token, transporter); + } + + private async void WebRtcChunkUploadRequestReceived(ITransporter transporter, ChunkUploadRequest request, string token) + { + await OnChunkUploadRequest(request, token, transporter); + } + + [ExternalBridgeRequestHandlerMethod(typeof(GetFileSystemItemRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnGetFileSystemItemRequest(GetFileSystemItemRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + FileSystemItemDTO dto = _manager.GetFolder(request); + await receiver.SendGenericResponse(new GetFileSystemItemResponse() { FileSystemItem = dto }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(FileUploadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFileUploadRequest(FileUploadRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + var tempFile = TemporaryManager.CreateFile(); + using (var stream = new FileStream(tempFile, FileMode.Create)) { } + + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path }; + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FileUploadResponse() { OperationId = operation.Id }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(FolderUploadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFolderUploadRequest(FolderUploadRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + var tempFile = TemporaryManager.CreateFile(); + using (var stream = new FileStream(tempFile, FileMode.Create)) { } + + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Upload, tempFile) { UploadPostPath = request.Path, IsPathTempZip = true }; + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FolderUploadResponse() { OperationId = operation.Id }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(FileDownloadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFileDownloadRequest(FileDownloadRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + if (!File.Exists(request.Path)) + { + throw new FileNotFoundException("Could not find the specified file."); + } + + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, request.Path); + + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FileDownloadResponse() + { + OperationId = operation.Id, + Length = new FileInfo(request.Path).Length + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(FolderDownloadRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnFolderDownloadRequest(FolderDownloadRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + if (!Directory.Exists(request.Path)) + { + throw new FileNotFoundException("Could not find the specified directory."); + } + + var tempFile = TemporaryManager.CreateImaginaryFile(); + + ZipFile.CreateFromDirectory(request.Path, tempFile); + + FileSystemOperation operation = new FileSystemOperation(FileSystemOperationMode.Download, tempFile); + operation.IsPathTempZip = true; + + _operations.Add(operation.Id, operation); + + await receiver.SendGenericResponse(new FolderDownloadResponse() + { + OperationId = operation.Id, + Length = new FileInfo(tempFile).Length + }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(ChunkUploadRequest))] + public async Task OnChunkUploadRequest(ChunkUploadRequest request, String token, ITransporter receiver) + { + this.ThrowIfDisabled(); + + FileSystemOperation operation; + _operations.TryGetValue(request.OperationId, out operation); + + if (operation == null) + { + throw new ArgumentException("Invalid operation id."); + } + + using (var stream = new FileStream(operation.Path, FileMode.Append)) + { + stream.Write(request.Data, 0, request.Data.Length); + } + + if (request.IsCompleted) + { + if (!operation.IsPathTempZip) + { + File.Copy(operation.Path, operation.UploadPostPath, true); + try + { + File.Delete(operation.Path); + } + catch { } + } + else + { + using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(operation.Path)) + { + zip.ExtractAll(operation.UploadPostPath, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently); + } + + try + { + File.Delete(operation.Path); + } + catch { } + } + } + + await receiver.SendGenericResponse(new ChunkUploadResponse(), token, new TransportResponseConfig() { Priority = QueuePriority.Low }); + } + + [ExternalBridgeRequestHandlerMethod(typeof(ChunkDownloadRequest))] + public async Task OnChunkDownloadRequest(ChunkDownloadRequest request, String token, ITransporter receiver) + { + this.ThrowIfDisabled(); + + FileSystemOperation operation; + _operations.TryGetValue(request.OperationId, out operation); + + if (operation == null) + { + throw new ArgumentException("Invalid operation id."); + } + + FileStream stream = null; + bool removeTempZipFile = false; + + try + { + stream = new FileStream(operation.Path, FileMode.Open); + stream.Position = request.Position; + byte[] data = new byte[Math.Min(request.MaxChunkSize, stream.Length - stream.Position)]; + + if (stream.Position + data.Length == stream.Length) + { + removeTempZipFile = true; + } + + await stream.ReadAsync(data, 0, data.Length); + stream.Dispose(); + stream = null; + await receiver.SendGenericResponse(new ChunkDownloadResponse() + { + Data = data + }, token, new TransportResponseConfig() { Priority = QueuePriority.Low }); + } + catch (Exception ex) + { + stream?.Dispose(); + throw ex; + } + finally + { + if (operation.IsPathTempZip && removeTempZipFile) + { + try + { + if (File.Exists(operation.Path)) + { + File.Delete(operation.Path); + } + } + catch { } + } + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(AbortOperationRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnAbortOperationRequest(AbortOperationRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + FileSystemOperation operation; + _operations.TryGetValue(request.OperationId, out operation); + + if (operation == null) + { + throw new ArgumentException("Invalid operation id."); + } + + if (operation.Mode == FileSystemOperationMode.Upload) + { + if (File.Exists(operation.Path)) + { + File.Delete(operation.Path); + } + } + else if (operation.IsPathTempZip) + { + if (File.Exists(operation.Path)) + { + File.Delete(operation.Path); + } + } + + await receiver.SendGenericResponse(new AbortOperationResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(MoveRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnMoveRequest(MoveRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + _manager.Move(request); + await receiver.SendGenericResponse(new MoveResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(CopyRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnCopyRequest(CopyRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + _manager.Copy(request); + await receiver.SendGenericResponse(new CopyResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(DeleteRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnDeleteRequest(DeleteRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + _manager.Delete(request.Path); + await receiver.SendGenericResponse(new DeleteResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(CreateFolderRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnCreateFolderRequest(CreateFolderRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + var dto = _manager.CreateFolder(request.Path, request.FolderName); + await receiver.SendGenericResponse(new CreateFolderResponse() { FolderItem = dto }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(PerformDiskSpaceOptimizationRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnPerformDiskSpaceOptimizationRequest(PerformDiskSpaceOptimizationRequest request, String token, ExternalBridgeReceiver receiver) + { + var deletedBytes = _manager.PerformDiskSpaceOptimization(); + await receiver.SendGenericResponse(new PerformDiskSpaceOptimizationResponse() { DeletedBytes = deletedBytes }, token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(GetLogFilesRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnGetLogFilesRequest(GetLogFilesRequest request, String token, ExternalBridgeReceiver receiver) + { + FolderItem folder = null; + + if (request.LogFileType == RemoteLogFileType.Application) + { + var fileLogger = LogManager.RegisteredLoggers.SingleOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; + + if (fileLogger == null) + { + throw new InvalidOperationException("Could not locate the application file logger."); + } + + folder = await _manager.GetFolder(fileLogger.Folder, false, "*.log") as FolderItem; + } + else + { + if (MachineOperator.EmbeddedLogsFolder == null) + { + throw new InvalidOperationException("The firmware file logger folder could not be read."); + } + + folder = await _manager.GetFolder(MachineOperator.EmbeddedLogsFolder, false, "*.log") as FolderItem; + } + + GetLogFilesResponse response = new GetLogFilesResponse(); + + foreach (var file in folder.Items.OfType().OrderByDescending(x => x.DateCreated).DistinctBy(x => x.Name)) + { + response.LogFiles.Add(new RemoteLogFile() + { + DateModified = file.DateModified, + DateCreated = file.DateCreated, + Name = file.Name, + Path = file.Path, + Length = new FileInfo(file.Path).Length + }); + } + + await receiver.SendGenericResponse(response, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + if (_webRtcClients.ContainsKey(receiver)) + { + try + { + LogManager.Log("External bridge receiver disconnected. Disposing file system service WebRTC channel..."); + var webRtcTransporter = _webRtcClients[receiver]; + _webRtcClients.Remove(receiver); + webRtcTransporter.Dispose(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disposing the WebRTC channel."); + } + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs new file mode 100644 index 000000000..9fba7a874 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.FileSystem +{ + /// + /// Represents an active file system file/folder download/upload operation + /// + public class FileSystemOperation + { + /// + /// Gets or sets the operation mode. + /// + public FileSystemOperationMode Mode { get; set; } + + /// + /// Gets or sets the operation identifier. + /// + public String Id { get; set; } + + /// + /// Gets or sets the path for the operation. + /// + public String Path { get; set; } + + /// + /// Should be set to true when the is a temporary zip file when performing download of a folder. + /// + public bool IsPathTempZip { get; set; } + + /// + /// Gets or sets the actual path to extract the zip file when uploading folder. + /// + public String UploadPostPath { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The mode. + /// The path. + public FileSystemOperation(FileSystemOperationMode mode, String path) + { + Mode = mode; + Id = Guid.NewGuid().ToString(); + Path = path; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs new file mode 100644 index 000000000..e28843bce --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.FileSystem +{ + public enum FileSystemOperationMode + { + Upload, + Download + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs new file mode 100644 index 000000000..7a80db9c7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.FileSystem +{ + /// + /// Represents a PPC file system remote service. + /// + /// + public interface IFileSystemService : IPPCService + { + /// + /// Gets or sets a value indicating whether to enable the WebRTC transport channel. + /// + bool EnableWebRTC { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs new file mode 100644 index 000000000..202f0378e --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Touch.Keyboard; + +namespace Tango.PPC.Common.Helpers +{ + public static class KeyboardHelper + { + public static void OpenKeyboard(KeyboardActionKeyMode action, TouchKeyboardMode mode = TouchKeyboardMode.AlphaNumeric) + { + KeyboardView.Keyboard.ActionKeyMode = action; + KeyboardView.Keyboard.Mode = mode; + KeyboardView.Default.IsOpened = true; + } + + public static void CloseKeyboard() + { + KeyboardView.Default.IsOpened = false; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/LogsHelper.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/LogsHelper.cs new file mode 100644 index 000000000..b7ab2d5b8 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/LogsHelper.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Logging; + +namespace Tango.PPC.Common.Helpers +{ + public static class LogsHelper + { + private static LogSafe _logSafe; + + public static void SetLogSafe(LogSafe logSafe) + { + _logSafe = logSafe; + } + + public static LogSafe GetLogSafe() + { + return _logSafe; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs new file mode 100644 index 000000000..5dfe5335c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; + +namespace Tango.PPC.Common +{ + /// + /// Represents a PPC remoting service. + /// + public interface IPPCService + { + /// + /// Gets or sets a value indicating whether this is enabled. + /// + bool Enabled { get; set; } + } +} + +public static class ExtensionMethods +{ + /// + /// Throws an exception is the service is disabled. + /// + /// The service. + /// + public static void ThrowIfDisabled(this IPPCService service) + { + if (!service.Enabled) + { + throw new NotSupportedException($"The {service.GetType().Name} is currently disabled. Could not perform the requested action."); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.png b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.png new file mode 100644 index 000000000..5aaea8e6c Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.png b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.png new file mode 100644 index 000000000..554c16305 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs new file mode 100644 index 000000000..75c5ae9cd --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; +using Tango.Core.DI; +using Tango.Insights; +using Tango.Integration.ExternalBridge; +using Tango.Logging; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Insights; +using Tango.Settings; + +namespace Tango.PPC.Common.Insights +{ + [TangoCreateWhenRegistered] + public class DefaultInsightsService : ExtendedObject, IInsightsService, IExternalBridgeRequestHandler + { + private InsightsListener _listener; + + private IMachineProvider MachineProvider { get; set; } + + public DefaultInsightsService(IPPCExternalBridgeService externalBridge, IMachineProvider machineProvider, IPPCApplicationManager applicationManager) + { + externalBridge.RegisterRequestHandler(this); + MachineProvider = machineProvider; + applicationManager.ApplicationStarted += ApplicationManager_ApplicationStarted; + } + + private void ApplicationManager_ApplicationStarted(object sender, EventArgs e) + { + Task.Factory.StartNew(() => + { + try + { + var settings = SettingsManager.Default.GetOrCreate(); + settings.Save(); + + if (settings.InsightsEnabled) + { + LogManager.Log("Starting insights service..."); + + _listener = new InsightsListener(MachineProvider.MachineOperator); + _listener.SamplingInterval = settings.InsightsSamplingInterval; + _listener.StorageCleanupInterval = settings.InsightsStorageCleanupInterval; + _listener.MaxStorageDuration = settings.InsightsMaxStorageDuration; + + LogManager.Log($"Insights configuration:\nSampling Interval: {_listener.SamplingInterval}\nStorage Cleanup Interval: {_listener.StorageCleanupInterval}\nMax Storage Duration: {_listener.MaxStorageDuration}"); + + _listener.Start(); + } + else + { + LogManager.Log("Insights service is disabled.", LogCategory.Warning); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error initializing insights listener."); + } + }); + } + + [ExternalBridgeRequestHandlerMethod(typeof(InsightsRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnInsightsRequest(InsightsRequest request, String token, ExternalBridgeReceiver receiver) + { + try + { + InsightsFile insightsFile = new InsightsFile(); + var filePath = TemporaryManager.CreateImaginaryFile(); + + await Task.Factory.StartNew(() => + { + var frames = InsightsManager.Default.GetFrames(request.StartDateUTC, request.EndDateUTC); + insightsFile.Frames = frames; + + if (request.IncludeEvents) + { + insightsFile.Events = InsightsManager.Default.GetEvents(request.StartDateUTC, request.EndDateUTC); + } + + if (request.IncludeStatuses) + { + insightsFile.Statuses = InsightsManager.Default.GetStatuses(request.StartDateUTC, request.EndDateUTC); + } + + if (request.IncludeApplicationExceptions) + { + insightsFile.ApplicationExceptions = InsightsManager.Default.GetApplicationExceptions(request.StartDateUTC, request.EndDateUTC); + } + + insightsFile.ToFile(filePath); + }); + + await receiver.SendGenericResponse(new InsightsResponse() + { + InisightsFilePath = filePath, + InsightsFileLength = new FileInfo(filePath).Length + }, token); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error processing insights request."); + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(InsightsDownloadCompletedRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnInsightsDownloadCompletedRequest(InsightsDownloadCompletedRequest request, String token, ExternalBridgeReceiver receiver) + { + await Task.Factory.StartNew(() => + { + try + { + File.Delete(request.InisightsFilePath); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error deleting insights request temp file after download completion."); + } + }); + await receiver.SendGenericResponse(new InsightsResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(InsightsMinDateRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnInsightsMinDateRequest(InsightsMinDateRequest request, String token, ExternalBridgeReceiver receiver) + { + DateTime? minDate = null; + + try + { + await Task.Factory.StartNew(() => + { + minDate = InsightsManager.Default.GetFramesMinDate(); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error retrieving insights frames minimum date."); + } + + await receiver.SendGenericResponse(new InsightsMinDateResponse() { MinDate = minDate }, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do Nothing... + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/IInsightsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/IInsightsService.cs new file mode 100644 index 000000000..268bb269b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/IInsightsService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Insights +{ + public interface IInsightsService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs index 004c37096..15902f629 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs @@ -11,12 +11,15 @@ using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; using Tango.Core; using Tango.Core.DB; using Tango.Core.ExtensionMethods; using Tango.Core.Helpers; using Tango.Core.IO; using Tango.Integration.Operation; +using Tango.Logging; using Tango.PMR.Synchronization; using Tango.PPC.Common.Application; using Tango.PPC.Common.Connection; @@ -28,6 +31,7 @@ using Tango.Settings; using Tango.SharedUI.Helpers; using Tango.SQLExaminer; using Tango.Transport.Web; +using System.Data.Entity; namespace Tango.PPC.Common.MachineSetup { @@ -42,6 +46,9 @@ namespace Tango.PPC.Common.MachineSetup private IUnifiedWriteFilterManager _uwf; private IOperationSystemManager _windows_manager; private PPCWebClient _client; + private List _logs; + private bool _isUpdating; + private DateTime _setupStartDate; #region Events @@ -80,6 +87,21 @@ namespace Tango.PPC.Common.MachineSetup _remoteAssistance = remoteAssistance; _uwf = unifiedWriterFilterManager; _windows_manager = operationSystemManager; + + _logs = new List(); + LogManager.NewLog += LogManager_NewLog; + } + + #endregion + + #region Event Handlers + + private void LogManager_NewLog(object sender, LogItemBase e) + { + if (_isUpdating) + { + _logs.Add(e); + } } #endregion @@ -99,6 +121,82 @@ namespace Tango.PPC.Common.MachineSetup }); } + private async void OnFailed(Exception ex, TaskCompletionSource completionSource, MachineSetupResponse response) + { + LogManager.Log(ex, "An error occurred in machine setup."); + + completionSource.SetException(ex); + + if (response != null) + { + try + { + var result = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.SetupFailed, + FailedReason = ex.FlattenMessage(), + FailedLog = GetLogsStringAndClear(), + }); + } + catch (Exception xx) + { + LogManager.Log(xx, "Error notifying setup completed."); + } + } + + _isUpdating = false; + } + + private async void OnCompleted(MachineSetupResult result, TaskCompletionSource completionSource, MachineSetupResponse response) + { + completionSource.SetResult(result); + + if (response != null) + { + try + { + var r = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.SetupCompleted, + }); + } + catch (Exception xx) + { + LogManager.Log(xx, "Error notifying setup completed."); + } + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = response.Version; + update.FirmwareVersion = response.FirmwareVersion; + update.MachineGuid = (await db.Machines.FirstAsync()).Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.SetupCompleted; + update.StartDate = _setupStartDate; + update.EndDate = DateTime.UtcNow; + await db.SaveChangesAsync(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving tango setup information to database."); + } + } + + _isUpdating = false; + } + + private String GetLogsStringAndClear() + { + String logsString = String.Join(Environment.NewLine, _logs.ToList().Select(x => x.ToString())); + _logs.Clear(); + return logsString; + } + #endregion #region Public Methods @@ -111,10 +209,17 @@ namespace Tango.PPC.Common.MachineSetup /// public async Task Setup(string serialNumber) { + _logs.Clear(); + TaskCompletionSource result = new TaskCompletionSource(); + MachineSetupResponse setup_response = null; + _setupStartDate = DateTime.UtcNow; + try { + _isUpdating = true; + LogManager.Log($"Starting machine setup for serial number {serialNumber}..."); var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); @@ -130,16 +235,24 @@ namespace Tango.PPC.Common.MachineSetup Login(serialNumber).Wait(); + String deviceName = $"Tango-{serialNumber}-{settings.DeploymentSlot.ToString()}"; + LogManager.Log($"Settings device name: '{deviceName}'..."); + try + { + await _windows_manager.SetDeviceName(deviceName); + } + catch + { + throw new IOException("Error setting device name."); + } + MachineSetupRequest request = new MachineSetupRequest(); - request.SerialNumber = serialNumber; request.DeviceID = await _windows_manager.GetDeviceId(); - request.DeviceName = await _windows_manager.GetDeviceName(); - - - MachineSetupResponse setup_response = null; + request.DeviceName = deviceName; try { + LogManager.Log($"Sending setup request...\n{request.ToJsonString()}"); setup_response = await _client.MachineSetup(request); } catch (Exception ex) @@ -175,20 +288,20 @@ namespace Tango.PPC.Common.MachineSetup UpdateProgress("Activating operation system license", "Activating..."); await _windows_manager.Activate(setup_response.OSKey); } + } - if (setup_response.SetupRemoteAssistance) - { - LogManager.Log("Installing remote assistance..."); - UpdateProgress("Installing remote assistance", "Installing..."); - await _remoteAssistance.InstallRemoteAssistance(serialNumber); - } + if (setup_response.SetupRemoteAssistance) + { + LogManager.Log("Installing remote assistance..."); + UpdateProgress("Installing remote assistance", "Installing..."); + await _remoteAssistance.InstallRemoteAssistance(serialNumber, setup_response.Organization, settings.DeploymentSlot.ToString()); + } - if (setup_response.SetupUWF) - { - LogManager.Log("Activating unified write filter..."); - UpdateProgress("Activating disk protection", "Activating..."); - await _uwf.Setup(); - } + if (setup_response.SetupUWF) + { + LogManager.Log("Activating unified write filter..."); + UpdateProgress("Activating disk protection", "Activating..."); + await _uwf.Setup(); } //Create temporary folders for packages. @@ -204,27 +317,29 @@ namespace Tango.PPC.Common.MachineSetup LogManager.Log("Downloading software package..."); - long fileSize = 0; - UpdateProgress("Downloading software package", "Downloading...", false); - - await Task.Factory.StartNew(() => + using (AutoFileDownloader downloader = new AutoFileDownloader(setup_response.BlobAddress, setup_response.CdnAddress, tempFile)) { - using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => + await downloader.ResolveMode(); + + if (downloader.Mode == AutoFileDownloader.DownloadMode.Standard) { - UpdateProgress("Downloading software package", "Downloading...", false, current, fileSize); - })) + LogManager.Log($"Connecting to storage CDN with address {downloader.Address}"); + } + else { - - LogManager.Log($"Connecting to storage blob with address {setup_response.BlobAddress}"); - CloudBlockBlob blob = new CloudBlockBlob(new Uri(setup_response.BlobAddress)); - LogManager.Log("Fetching blob attributes..."); - blob.FetchAttributes(); - fileSize = blob.Properties.Length; - LogManager.Log("Download size: " + fileSize + " bytes."); - LogManager.Log("Starting blob download..."); - blob.DownloadToStream(fs); + LogManager.Log($"Connecting to storage blob with address {downloader.Address}"); } - }); + + downloader.Progress += (x, e) => + { + UpdateProgress("Downloading software package", "Downloading...", false, e.Current, e.Total); + }; + + var size = await downloader.GetFileSize(); + LogManager.Log("Download size: " + size + " bytes."); + LogManager.Log("Starting file download..."); + await downloader.Download(); + } UpdateProgress("Downloading software package", "Extracting package..."); @@ -320,25 +435,25 @@ namespace Tango.PPC.Common.MachineSetup UpdateProgress("Updating Firmware", "Loading firmware package..."); var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); var stream = new FileStream(tfpPath, FileMode.Open); - var handler = await op.UpgradeFirmware(stream); + var handler = await op.UpgradeFirmware(stream, setup_response.IsDemo); handler.Failed += (_, ex) => { stream.Dispose(); - result.SetException(ex); + OnFailed(ex, result, setup_response); }; handler.Completed += (_, __) => { UpdateProgress("Updating Firmware", "Firmware update completed successfully."); stream.Dispose(); - result.SetResult(new MachineSetupResult() + OnCompleted(new MachineSetupResult() { UpdatePackagePath = _newPackageTempFolder, - }); + }, result, setup_response); }; handler.Canceled += (_, __) => { stream.Dispose(); - result.SetException(new Exception("The operation has been canceled.")); + OnFailed(new Exception("The operation has been canceled."), result, setup_response); }; handler.Progress += (_, e) => { @@ -347,16 +462,15 @@ namespace Tango.PPC.Common.MachineSetup } else { - result.SetResult(new MachineSetupResult() + OnCompleted(new MachineSetupResult() { UpdatePackagePath = _newPackageTempFolder, - }); + }, result, setup_response); } } catch (Exception ex) { - LogManager.Log(ex, "An error occurred in machine setup."); - result.SetException(ex); + OnFailed(ex, result, setup_response); } return await result.Task; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs index 85d61d4cc..7c835165f 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs @@ -4,12 +4,27 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.PMR.Synchronization; +using Tango.PPC.Common.Publish; +using Tango.PPC.Common.UpdatePackages; using Tango.PPC.Common.Web; namespace Tango.PPC.Common.MachineUpdate { public interface IMachineUpdateManager { + /// + /// Occurs when an application update is available. + /// + event EventHandler UpdateAvailable; + + /// + /// Gets or sets a value indicating whether to automatically check for new application updates. + /// + bool EnableAutoCheckForUpdates { get; set; } + + /// + /// Gets the current machine update progress status. + /// MachineUpdateProgress Status { get; } /// @@ -23,46 +38,68 @@ namespace Tango.PPC.Common.MachineUpdate event EventHandler Progress; /// - /// Performs a machine update using the specified serial number and machine service address. + /// Performs a machine update. /// - /// The serial number. /// if set to true updates the embedded device firmware. /// if set to true updates the embedded device FPGA version and other parameters. /// - Task Update(String serialNumber, bool setupFirmware, bool setupFPGA); + Task Update(bool setupFirmware, bool setupFPGA); /// /// Performs a machine update using the specified software update package path. /// /// Name of the file. /// - Task UpdateFromTUP(String fileName); + Task UpdateFromTUP(String fileName, bool setupFirmware, bool setupFPGA); + + /// + /// Performs a firmware upgrade from the specified TFP file. + /// + /// Name of the file. + /// + Task UpdateFromTFP(String fileName); /// - /// Checks if any update are available for the specified machine serial number. + /// Checks if any update are available. /// - /// The serial number. /// - Task CheckForUpdate(String serialNumber); + Task CheckForUpdate(); /// /// Checks whether it is necessary to updates all the "overwrite-able" database tables. /// - /// The serial number. /// - Task UpdateDBCheck(String serialNumber); + Task UpdateDBCheck(); /// /// Updates all the "overwrite-able" database tables. /// /// - Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber); + Task UpdateDB(DbCompareResult dbCompareResult); /// /// Gets the update package file information. /// /// The file path. /// - Task GetUpdatePackageFileInfo(String filePath); + Task GetUpdatePackageFileInfo(String filePath); + + /// + /// Checks whether any post update packages needs to be installed. + /// + /// + Task PostUpdatePackagesRequired(); + + /// + /// Runs all post update packages. + /// + /// + Task RunPostUpdatePackages(); + + /// + /// Restores the last database backup. + /// + /// + Task RestoreLastDatabaseBackup(); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs index b7573ec60..c115f4f5b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; using Tango.Core; using Tango.Core.DB; using Tango.Core.ExtensionMethods; @@ -16,25 +18,47 @@ using Tango.Core.Helpers; using Tango.Core.IO; using Tango.Integration.Operation; using Tango.Integration.Upgrade; +using Tango.Logging; using Tango.PMR.Synchronization; using Tango.PPC.Common.Application; using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Navigation; +using Tango.PPC.Common.Publish; +using Tango.PPC.Common.UpdatePackages; using Tango.PPC.Common.Web; using Tango.Settings; using Tango.SharedUI.Helpers; using Tango.SQLExaminer; using Tango.Transport.Web; +using System.Data.Entity; +using Tango.PPC.Common.ExternalBridge; +using Tango.Integration.ExternalBridge; +using Tango.BL.DTO; +using Tango.PPC.Shared.Updates; +using Tango.PPC.Shared.RemoteUpgrade; +using Tango.Core.Threading; namespace Tango.PPC.Common.MachineUpdate { - public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager + public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager, IExternalBridgeRequestHandler { private IPPCApplicationManager _app_manager; private IMachineProvider _machineProvider; + private IPackageRunner _packageRunner; private PPCWebClient _client; + private List _logs; + private System.Timers.Timer _checkForUpdateTimer; + private bool _isUpdating; + private PPCSettings _settings; + private DateTime _updateStartDate; #region Events + /// + /// Occurs when an application update is available. + /// + public event EventHandler UpdateAvailable; + /// /// Occurs when there is a text log message available. /// @@ -50,12 +74,25 @@ namespace Tango.PPC.Common.MachineUpdate #region Properties private MachineUpdateProgress _status; + /// + /// Gets the current machine update progress status. + /// public MachineUpdateProgress Status { get { return _status; } private set { _status = value; RaisePropertyChangedAuto(); } } + private bool _autoCheckForUpdates; + /// + /// Gets or sets a value indicating whether to automatically check for new application updates. + /// + public bool EnableAutoCheckForUpdates + { + get { return _autoCheckForUpdates; } + set { _autoCheckForUpdates = value; RaisePropertyChangedAuto(); } + } + #endregion #region Constructors @@ -64,592 +101,1583 @@ namespace Tango.PPC.Common.MachineUpdate /// Initializes a new instance of the class. /// /// The application manager. - public MachineUpdateManager(PPCWebClient ppcWebClient, IPPCApplicationManager applicationManager, IMachineProvider machineProvider) + public MachineUpdateManager(PPCWebClient ppcWebClient, IPPCApplicationManager applicationManager, IMachineProvider machineProvider, IPackageRunner packageRunner, IPPCExternalBridgeService externalBridge) { _client = ppcWebClient; _machineProvider = machineProvider; _app_manager = applicationManager; - } + _app_manager.ApplicationReady += _app_manager_ApplicationReady; + _packageRunner = packageRunner; + _packageRunner.PackageProgress += _packageRunner_PackageProgress; - #endregion + _logs = new List(); + LogManager.NewLog += LogManager_NewLog; - #region Private Methods + _settings = SettingsManager.Default.GetOrCreate(); - private Task Login(String serialNumber) - { - return _client.Login(new LoginRequest() - { - Mode = LoginMode.Machine, - SerialNumber = serialNumber, - }); + _checkForUpdateTimer = new System.Timers.Timer(_settings.AutoUpdateCheckInterval.TotalMilliseconds); + _checkForUpdateTimer.Elapsed += _checkForUpdateTimer_Elapsed; + _checkForUpdateTimer.Stop(); + + externalBridge.RegisterRequestHandler(this); } #endregion - #region Public Methods + #region Event Handlers - /// - /// Performs a machine update using the specified serial number and machine service address. - /// - /// The serial number. - /// if set to true updates the embedded device firmware. - /// if set to true updates the embedded device FPGA version and other parameters. - /// - /// - /// Could not perform an update while the machine is not connected. - /// or - /// or - /// - /// Database tango does not exists. - public async Task Update(String serialNumber, bool setupFirmware, bool setupFPGA) + private void _app_manager_ApplicationReady(object sender, EventArgs e) { - TaskCompletionSource result = new TaskCompletionSource(); + _checkForUpdateTimer.Start(); - var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; - bool performDatabaseRollback = false; - String dbBackupFile = null; + if (!_app_manager.IsUpdateFailed) + { + ClearLastDatabaseBackup(); + } + } - try + private void _packageRunner_PackageProgress(object sender, PackageProgressEventArgs e) + { + UpdateProgress(e.PackageName, e.Message, e.IsIntermediate, e.Progress, e.Total); + } + + private void LogManager_NewLog(object sender, LogItemBase e) + { + if (_isUpdating) { - var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); + _logs.Add(e); + } + } - LogManager.Log($"Starting machine update for serial number {serialNumber}..."); + #endregion - //Connecting to machine... - LogManager.Log("Verifying machine connection and state..."); + #region Private Methods - UpdateProgress("Verifying machine state", "Initializing..."); + private Task Login(String machineGuid) + { + return _client.Login(new LoginRequest() + { + Mode = LoginMode.Machine, + MachineGuid = machineGuid, + }); + } - await Task.Delay(1000); + private async void OnFailed(Exception ex, TaskCompletionSource completionSource, DownloadUpdateResponse response, bool performDatabaseRollback, String dbBackupFile, String backupsFolder, String tempDbName, Tango.Core.DataSource localDataSource, String tempUpdatePackageFolder = null, PublishInfo tupPublishInfo = null) + { + LogManager.Log(ex, "An error occurred in machine update."); - IMachineOperator op = _machineProvider.MachineOperator; + await Task.Factory.StartNew(() => + { - if (setupFirmware) + if (performDatabaseRollback) { - LogManager.Log("Machine is configured to update firmware..."); + LogManager.Log("Rolling back database changes..."); - if (op.State != Transport.TransportComponentState.Connected) + using (DbManager db = DbManager.FromDataSource(localDataSource)) { - throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); + try + { + UpdateProgress("Rollback", "Rolling back database changes..."); + db.Restore(localDataSource.Catalog, dbBackupFile); + LogManager.Log("Database restored successfully."); + } + catch (Exception e) + { + LogManager.Log(e, "Could not rollback the database."); + } + finally + { + try + { + File.Delete(dbBackupFile); + } + catch { } + } + } + } + + if (tempDbName != null) + { + try + { + LogManager.Log($"Removing temporary database '{tempDbName}'..."); + using (DbManager dbManager = DbManager.FromDataSource(localDataSource)) + { + dbManager.SetOffline(tempDbName); + dbManager.SetOnline(tempDbName); + dbManager.Delete(tempDbName); + } } - if (op.IsPrinting) + catch (Exception exx) { - throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); + LogManager.Log(exx, "Error removing temporary database."); } } - //Connect to machine service and get matching packages for this machine. - UpdateProgress("Downloading software package", "Connecting to machine service..."); - - LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - - await Login(serialNumber); - - DownloadUpdateRequest request = new DownloadUpdateRequest(); - request.SerialNumber = serialNumber; - - DownloadUpdateResponse update_response = null; - - update_response = await _client.MachineUpdate(request); - - LogManager.Log($"Machine update response received: {Environment.NewLine}{update_response.ToJsonString()}"); - - //Create temporary folders for packages. - var _newPackageTempFolder = TemporaryManager.CreateFolder(); - _newPackageTempFolder.Persist = true; - - LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}."); - - //Download software package. - var tempFile = TemporaryManager.CreateFile(".zip"); - - LogManager.Log($"Temporary package zip file created: {tempFile}."); - - LogManager.Log("Downloading software package..."); - - long fileSize = 0; - UpdateProgress("Downloading software package", "Downloading...", false); - - using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => + try { - UpdateProgress("Downloading software package", "Downloading...", false, current, fileSize); - })) + Directory.Delete(backupsFolder, true); + } + catch (Exception ee) { - LogManager.Log($"Connecting to storage blob with address {update_response.BlobAddress}"); - CloudBlockBlob blob = new CloudBlockBlob(new Uri(update_response.BlobAddress)); - LogManager.Log("Fetching blob attributes..."); - blob.FetchAttributes(); - fileSize = blob.Properties.Length; - LogManager.Log("Download size: " + fileSize + " bytes."); - LogManager.Log("Starting blob download..."); - blob.DownloadToStream(fs); + LogManager.Log(ee, $"Error deleting backups folder '{backupsFolder}'."); } - UpdateProgress("Downloading software package", "Extracting package..."); - - LogManager.Log("Extracting downloaded zip file..."); - //Extract software package. - ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder); + if (tempUpdatePackageFolder != null) + { + try + { + Directory.Delete(tempUpdatePackageFolder, true); + } + catch (Exception eee) + { + LogManager.Log(eee, "Error removing temporary package folder."); + } + } + }); - LogManager.Log("Copying latest updater utility to application path..."); - //Copy new updater utility to app path. - File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true); + completionSource.SetException(ex); + String logs = GetLogsStringAndClear(); - //Synchronize database - UpdateProgress("Updating Database", "Initializing..."); + if (response != null) + { + try + { + var result = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.UpdateFailed, + FailedReason = ex.FlattenMessage(), + FailedLog = logs, + }); + } + catch (Exception xx) + { + LogManager.Log(xx, "Error notifying update failed."); + } - LogManager.Log($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = response.Version; + update.FirmwareVersion = response.FirmwareVersion; + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.UpdateFailed; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + update.FailedReason = ex.FlattenMessage(); + update.FailedLog = logs; + db.TangoUpdates.Add(update); + await db.SaveChangesAsync(); + } + } + catch (Exception xxx) + { + LogManager.Log(xxx, "Error saving tango update information to database."); + } + } - UpdateProgress("Updating Database", "Connecting to local database..."); - LogManager.Log("Initializing database manager..."); - DbManager db = DbManager.FromDataSource(localDataSource); - LogManager.Log("Checking Tango database exists on the local machine..."); - if (!db.Exists(localDataSource.Catalog)) + if (tupPublishInfo != null) + { + try { - throw new InvalidProgramException("Database tango does not exists."); + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = tupPublishInfo.ApplicationVersion; + update.FirmwareVersion = tupPublishInfo.GetFirmwareVersion(); + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineUpdateFailed; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + update.FailedReason = ex.FlattenMessage(); + update.FailedLog = logs; + db.TangoUpdates.Add(update); + await db.SaveChangesAsync(); + } } - - if (setupFirmware) + catch (Exception xxx) { - LogManager.Log("Setup firmware is active so a database rollback procedure should be configured."); - UpdateProgress("Updating Database", "Creating database backup..."); + LogManager.Log(xxx, "Error saving tango offline update information to database."); + } + } + + _isUpdating = false; + } + private async void OnCompleted(MachineUpdateResult result, TaskCompletionSource completionSource, DownloadUpdateResponse response, String tempDbName, String backupsFolder, Core.DataSource localDataSource, PublishInfo tupPublishInfo = null) + { + await Task.Factory.StartNew(() => + { + if (tempDbName != null) + { try { - Directory.CreateDirectory("C:\\Backups"); - dbBackupFile = $"C:\\Backups\\{Path.GetRandomFileName()}.bak"; - LogManager.Log($"Creating database backup to '{dbBackupFile}'..."); - await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile)); - LogManager.Log("Database backup created successfully."); + LogManager.Log($"Removing temporary database '{tempDbName}'..."); + using (DbManager dbManager = DbManager.FromDataSource(localDataSource)) + { + dbManager.SetOffline(tempDbName); + dbManager.SetOnline(tempDbName); + dbManager.Delete(tempDbName); + } } catch (Exception ex) { - throw LogManager.Log(ex, "Setup manager error while trying to create a database backup."); + LogManager.Log(ex, "Error removing temporary database."); } } - LogManager.Log("Disposing database manager."); - db.Dispose(); + //try + //{ + // Directory.Delete(backupsFolder, true); + //} + //catch (Exception ex) + //{ + // LogManager.Log(ex, $"Error deleting backups folder '{backupsFolder}'."); + //} - LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); + if (!result.RequiresBinariesUpdate) + { + try + { + Directory.Delete(result.UpdatePackagePath, true); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error removing temporary package folder."); + } + } - UpdateProgress("Updating Database", "Initializing update sequence..."); + }); - ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( - Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"), - Path.Combine(_newPackageTempFolder, "Update Scripts"), - update_response.DataSource, - localDataSource, - serialNumber); + completionSource.SetResult(result); - runner.Log += (x, msg) => + if (response != null) + { + try { - LogManager.Log(msg); - ProgressLog?.Invoke(this, msg); - }; - - runner.ScriptExecuting += (x, item) => + var r = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.UpdateCompleted, + }); + } + catch (Exception ex) { - LogManager.Log($"Executing script {item.ToString()}..."); - UpdateProgress("Updating Database", item.Name + "..."); - }; - - LogManager.Log("Starting synchronization process..."); + LogManager.Log(ex, "Error notifying update completed."); + } try { - await runner.Run(); - LogManager.Log("Synchronization completed successfully!"); - UpdateProgress("Updating Database", "Database synchronization completed successfully."); + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = response.Version; + update.FirmwareVersion = response.FirmwareVersion; + update.MachineGuid = (await db.Machines.FirstAsync()).Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.UpdateCompleted; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + db.TangoUpdates.Add(update); + await db.SaveChangesAsync(); + } } catch (Exception ex) { - throw LogManager.Log(ex, "Setup manager error while trying to synchronize database."); + LogManager.Log(ex, "Error saving tango update information to database."); } + } - //Updating firmware - if (setupFirmware) + + if (tupPublishInfo != null) + { + try { - performDatabaseRollback = true; + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = tupPublishInfo.ApplicationVersion; + update.FirmwareVersion = tupPublishInfo.GetFirmwareVersion(); + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineUpdateCompleted; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + db.TangoUpdates.Add(update); + await db.SaveChangesAsync(); + } + } + catch (Exception xxx) + { + LogManager.Log(xxx, "Error saving tango offline update information to database."); + } + } - UpdateProgress("Updating Firmware", "Connecting to firmware device..."); - LogManager.Log(""); - LogManager.Log("-------------------------------------------------------------------------"); - LogManager.Log("Updating Firmware..."); + _isUpdating = false; + } - UpdateProgress("Updating Firmware", "Loading firmware package..."); - var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); - var stream = new FileStream(tfpPath, FileMode.Open); + private void OnFailed(Exception ex, UpdateDBResponse response, bool performDatabaseRollback, String dbBackupFile, Tango.Core.DataSource localDataSource) + { + LogManager.Log(ex, "An error occurred in database update."); - if (setupFPGA) + if (performDatabaseRollback) + { + LogManager.Log("Rolling back database changes..."); + + using (DbManager db = DbManager.FromDataSource(localDataSource)) + { + try { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; + UpdateProgress("Rollback", "Rolling back database changes..."); + db.Restore(localDataSource.Catalog, dbBackupFile); + LogManager.Log("Database restored successfully."); } - else + catch (Exception e) { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; + LogManager.Log(e, "Could not rollback the database."); + throw ex; } - - var handler = await op.UpgradeFirmware(stream); - handler.Failed += (_, ex) => + finally { - stream.Dispose(); - throw ex; - }; - handler.Completed += (_, __) => - { - UpdateProgress("Updating Firmware", "Firmware update completed successfully."); - stream.Dispose(); - result.SetResult(new MachineUpdateResult() + try { - UpdatePackagePath = _newPackageTempFolder, - }); - }; - handler.Canceled += (_, __) => - { - stream.Dispose(); - throw new Exception("The operation has been canceled."); - }; - handler.Progress += (_, e) => + File.Delete(dbBackupFile); + } + catch { } + } + } + } + + String logs = GetLogsStringAndClear(); + + if (response != null) + { + try + { + var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() { - UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total); - }; + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.DatabaseFailed, + FailedReason = ex.FlattenMessage(), + FailedLog = logs, + }).Result; } - else + catch (Exception xx) + { + LogManager.Log(xx, "Error notifying database failed."); + } + + try { - result.SetResult(new MachineUpdateResult() + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - UpdatePackagePath = _newPackageTempFolder, - }); + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = _app_manager.Version.ToString(); + update.FirmwareVersion = _app_manager.FirmwareVersion.ToString(); + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.DatabaseFailed; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + update.FailedReason = ex.FlattenMessage(); + update.FailedLog = logs; + db.TangoUpdates.Add(update); + db.SaveChanges(); + } + } + catch (Exception exx) + { + LogManager.Log(exx, "Error saving database update information to database."); } } - catch (Exception ex) - { - LogManager.Log(ex, "An error occurred in machine update."); - if (performDatabaseRollback) + _isUpdating = false; + } + + private void OnCompleted(UpdateDBResponse response, bool completedWithNoDifferences = false) + { + if (response != null) + { + try { - LogManager.Log("Rolling back database changes..."); + var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = response.NotifyCompletedToken, + Status = BL.Enumerations.TangoUpdateStatuses.DatabaseCompleted, + ReportsAboutDbCheckNoDifferences = completedWithNoDifferences, + }).Result; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error notifying database completed."); + } - using (DbManager db = DbManager.FromDataSource(localDataSource)) + if (!completedWithNoDifferences) + { + try { - try - { - UpdateProgress("Rollback", "Rolling back database changes..."); - await Task.Factory.StartNew(() => db.Restore(localDataSource.Catalog, dbBackupFile)); - LogManager.Log("Database restored successfully."); - } - catch (Exception e) - { - LogManager.Log(e, "Could not rollback the database."); - throw ex; - } - finally + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - try - { - File.Delete(dbBackupFile); - } - catch { } + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = _app_manager.Version.ToString(); + update.FirmwareVersion = _app_manager.FirmwareVersion.ToString(); + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.DatabaseCompleted; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + db.TangoUpdates.Add(update); + db.SaveChanges(); } } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving database update information to database."); + } } + } + + _isUpdating = false; + } + + private void OnFailed(Exception ex, TaskCompletionSource completionSource, String firmwareVersion) + { + LogManager.Log(ex, "An error occurred in firmware upgrade."); + + completionSource.SetException(ex); + String logs = GetLogsStringAndClear(); - result.SetException(ex); + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = _app_manager.Version.ToString(); + update.FirmwareVersion = firmwareVersion; + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineFirmwareUpgradeFailed; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + update.FailedReason = ex.FlattenMessage(); + update.FailedLog = logs; + db.TangoUpdates.Add(update); + db.SaveChanges(); + } } - finally + catch (Exception exx) { - try + LogManager.Log(exx, "Error saving firmware upgrade information to database."); + } + + _isUpdating = false; + } + + private void OnCompleted(TaskCompletionSource completionSource, String firmwareVersion) + { + LogManager.Log("Firmware upgrade completed successfully."); + completionSource.SetResult(true); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - File.Delete(dbBackupFile); + TangoUpdate update = new TangoUpdate(); + update.ApplicationVersion = _app_manager.Version.ToString(); + update.FirmwareVersion = firmwareVersion; + update.MachineGuid = _machineProvider.Machine.Guid; + update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineFirmwareUpgradeCompleted; + update.StartDate = _updateStartDate; + update.EndDate = DateTime.UtcNow; + db.TangoUpdates.Add(update); + db.SaveChanges(); } - catch { } + } + catch (Exception exx) + { + LogManager.Log(exx, "Error saving firmware upgrade information to database."); } - return await result.Task; + _isUpdating = false; + } + + private String GetLogsStringAndClear() + { + String logsString = String.Join(Environment.NewLine, _logs.ToList().Select(x => x.ToString())); + _logs.Clear(); + return logsString; + } + + private void ClearLastDatabaseBackup() + { + Task.Factory.StartNew(() => + { + try + { + var lastBackupFile = SettingsManager.Default.GetOrCreate().LastDatabaseBackupFile; + + if (File.Exists(lastBackupFile)) + { + File.Delete(lastBackupFile); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error removing last database backup file."); + } + }); } + #endregion + + #region Public Methods + /// - /// Checks if any update are available for the specified machine serial number. + /// Performs a machine update. /// - /// The serial number. - /// The machine service address. + /// if set to true updates the embedded device firmware. + /// if set to true updates the embedded device FPGA version and other parameters. /// - public Task CheckForUpdate(string serialNumber) + /// + /// Could not perform an update while the machine is not connected. + /// or + /// or + /// + /// Database tango does not exists. + public async Task Update(bool setupFirmware, bool setupFPGA) { - return Task.Factory.StartNew(() => + _updateStartDate = DateTime.UtcNow; + _logs.Clear(); + + TaskCompletionSource result = new TaskCompletionSource(); + + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + bool performDatabaseRollback = false; + String dbBackupFile = null; + DownloadUpdateResponse update_response = null; + String backupsFolder = "C:\\Backups"; + + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; + + String machineGuid = _machineProvider.Machine.Guid; + + try { - var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); + _isUpdating = true; + + var machineServiceAddress = _settings.GetMachineServiceAddress(); + + LogManager.Log($"Starting machine update..."); + + //Connecting to machine... + LogManager.Log("Verifying machine connection and state..."); + + UpdateProgress("Verifying machine state", "Initializing..."); + + await Task.Delay(1000); + + IMachineOperator op = _machineProvider.MachineOperator; + + if (setupFirmware) + { + LogManager.Log("Machine is configured to update firmware..."); + + if (op.State != Transport.TransportComponentState.Connected) + { + throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); + } + } + + if (!op.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); + } + + //Connect to machine service and get matching packages for this machine. + UpdateProgress("Downloading software package", "Connecting to machine service..."); LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - Login(serialNumber).GetAwaiter().GetResult(); + await Login(machineGuid); - LogManager.Log($"Checking if updates available..."); + DownloadUpdateRequest request = new DownloadUpdateRequest(); - CheckForUpdateRequest request = new CheckForUpdateRequest(); - request.SerialNumber = serialNumber; - request.Version = _app_manager.Version.ToString(); + update_response = await _client.MachineUpdate(request); - CheckForUpdateResponse update_response = null; + LogManager.Log($"Machine update response received: {Environment.NewLine}{update_response.ToJsonString()}"); - update_response = _client.CheckForUpdates(request).Result; + LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}."); - LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}"); + //Download software package. + var tempFile = TemporaryManager.CreateFile(".zip"); - return update_response; - }); - } + LogManager.Log($"Temporary package zip file created: {tempFile}."); - /// - /// Updates all the "overwrite-able" database tables. - /// - /// The serial number. - /// The machine service address. - /// - public Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber) - { - return Task.Factory.StartNew(() => - { - LogManager.Log("Starting database update..."); + LogManager.Log("Downloading software package..."); + + UpdateProgress("Downloading software package", "Downloading...", false); + + using (AutoFileDownloader downloader = new AutoFileDownloader(update_response.BlobAddress, update_response.CdnAddress, tempFile)) + { + await downloader.ResolveMode(); + + if (downloader.Mode == AutoFileDownloader.DownloadMode.Standard) + { + LogManager.Log($"Connecting to storage CDN with address {downloader.Address}"); + } + else + { + LogManager.Log($"Connecting to storage blob with address {downloader.Address}"); + } + downloader.Progress += (x, e) => + { + UpdateProgress("Downloading software package", "Downloading...", false, e.Current, e.Total); + }; + + var size = await downloader.GetFileSize(); + LogManager.Log("Download size: " + size + " bytes."); + LogManager.Log("Starting file download..."); + await downloader.Download(); + } + + UpdateProgress("Downloading software package", "Extracting package..."); + + LogManager.Log("Extracting downloaded zip file..."); + + await Task.Factory.StartNew(() => + { + //Extract software package. + ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder); + }); + + LogManager.Log("Copying latest updater utility to application path..."); + //Copy new updater utility to app path. + File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true); + + LogManager.Log("Initializing database manager..."); + DbManager db = DbManager.FromDataSource(localDataSource); + + //Create Database Backup + UpdateProgress("Updating Database", "Creating database backup..."); + try + { + Directory.CreateDirectory(backupsFolder); + dbBackupFile = $"{backupsFolder}\\{Path.GetRandomFileName()}.bak"; + _settings.LastDatabaseBackupFile = dbBackupFile; + _settings.Save(); + LogManager.Log($"Creating database backup to '{dbBackupFile}'..."); + await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile)); + performDatabaseRollback = true; + LogManager.Log("Database backup created successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Update manager error while trying to create a database backup."); + } + + //Run pre-update packages. + try + { + UpdateProgress("Preparing", "Running update packages..."); + LogManager.Log("Running pre-update packages..."); + var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages"); + + Version updateVersion = new Version(1, 0, 0, 0); + try + { + updateVersion = Version.Parse(update_response.Version); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error parsing new version string for package runner."); + } + + await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error running pre-update packages..."); + } + + //Synchronize database UpdateProgress("Updating Database", "Initializing..."); - LogManager.Log("Looking for update scripts configuration on application path..."); + LogManager.Log($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); - String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); + UpdateProgress("Updating Database", "Connecting to local database..."); - if (!File.Exists(config_file)) + LogManager.Log("Checking Tango database exists on the local machine..."); + if (!db.Exists(localDataSource.Catalog)) { - throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); + throw new InvalidProgramException("Database tango does not exists."); } - UpdateDBResponse update_response = dbCompareResult.UpdateDBResponse; + LogManager.Log("Disposing database manager."); + db.Dispose(); + + LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); - var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + UpdateProgress("Updating Database", "Initializing update sequence..."); + + ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( + Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"), + Path.Combine(_newPackageTempFolder, "Update Scripts"), + update_response.DataSource, + localDataSource, + machineGuid); + + runner.Log += (x, msg) => + { + LogManager.Log(msg); + ProgressLog?.Invoke(this, msg); + }; + + runner.ScriptExecuting += (x, item) => + { + LogManager.Log($"Executing script {item.ToString()}..."); + UpdateProgress("Updating Database", item.Name + "..."); + }; + + LogManager.Log("Starting synchronization process..."); + + try + { + await runner.Run(); + LogManager.Log("Synchronization completed successfully!"); + UpdateProgress("Updating Database", "Database synchronization completed successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Update manager error while trying to synchronize database."); + } + + //Updating firmware + if (setupFirmware) + { + UpdateProgress("Updating Firmware", "Connecting to firmware device..."); + LogManager.Log(""); + LogManager.Log("-------------------------------------------------------------------------"); + LogManager.Log("Updating Firmware..."); + + UpdateProgress("Updating Firmware", "Loading firmware package..."); + var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); + var stream = new FileStream(tfpPath, FileMode.Open); + + if (setupFPGA) + { + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; + } + else + { + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; + } + + var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); + handler.Failed += (_, ex) => + { + stream.Dispose(); + OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder); + }; + handler.Completed += (_, __) => + { + UpdateProgress("Updating Firmware", "Firmware update completed successfully."); + stream.Dispose(); + OnCompleted(new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }, result, update_response, null, backupsFolder, localDataSource); + }; + handler.Canceled += (_, __) => + { + stream.Dispose(); + OnFailed(new Exception("The operation has been canceled."), result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder); + }; + handler.Progress += (_, e) => + { + UpdateProgress("Updating Firmware", e.Message, e.IsIndeterminate, e.Current, e.Total); + }; + } + else + { + OnCompleted(new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }, result, update_response, null, backupsFolder, localDataSource); + } + } + catch (Exception ex) + { + OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder); + } + + return await result.Task; + } + + /// + /// Checks if any update are available for the specified machine. + /// + /// The machine service address. + /// + public Task CheckForUpdate() + { + return Task.Factory.StartNew(() => + { + _isUpdating = true; + + var machineServiceAddress = _settings.GetMachineServiceAddress(); + + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); + + String machineGuid = _machineProvider.Machine.Guid; + + Login(machineGuid).GetAwaiter().GetResult(); + + LogManager.Log($"Checking if updates available..."); + + CheckForUpdateRequest request = new CheckForUpdateRequest(); + request.Version = _app_manager.Version.ToString(); + request.FirmwareVersion = _app_manager.FirmwareVersion?.ToString(); + + try + { + request.MachineLastUpdated = _machineProvider.Machine.LastUpdated; + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + request.Rmls = db.Rmls.ToList().Select(x => new UpdatedEntity(x)).ToList(); + request.HardwareVersions = db.HardwareVersions.ToList().Select(x => new UpdatedEntity(x)).ToList(); + request.Catalogs = db.ColorCatalogs.ToList().Select(x => new UpdatedEntity(x)).ToList(); + request.UsedRmlsGuids = db.Jobs.Select(x => x.RmlGuid).Distinct().ToList(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "An error occurred while trying to fill the existing database entities before checking for updates."); + } + + CheckForUpdateResponse update_response = null; + + update_response = _client.CheckForUpdates(request).Result; + + LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}"); + + _isUpdating = false; + + return update_response; + }); + } + + /// + /// Updates all the "overwrite-able" database tables. + /// + /// The machine service address. + /// + public Task UpdateDB(DbCompareResult dbCompareResult) + { + _updateStartDate = DateTime.UtcNow; + _logs.Clear(); + + return Task.Factory.StartNew(() => + { + _isUpdating = true; + UpdateDBResponse update_response = null; + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + bool performDatabaseRollback = false; + String dbBackupFile = null; + + try + { + LogManager.Log("Starting database update..."); + + if (_machineProvider.MachineOperator.IsPrinting) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform a database update while the machine is dyeing.")); + } + + UpdateProgress("Updating Database", "Initializing..."); + + LogManager.Log("Looking for update scripts configuration on application path..."); + + String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); + + if (!File.Exists(config_file)) + { + throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); + } + + update_response = dbCompareResult.UpdateDBResponse; + + LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + + UpdateProgress("Updating Database", "Initializing update sequence..."); + + ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); + + UpdateProgress("Updating Database", "Connecting to local database..."); + LogManager.Log("Initializing database manager..."); + DbManager db = DbManager.FromDataSource(localDataSource); + + LogManager.Log("Checking Tango database exists on the local machine..."); + if (!db.Exists(localDataSource.Catalog)) + { + throw new InvalidProgramException("Database tango does not exists."); + } + + UpdateProgress("Updating Database", "Creating database backup..."); + + //Create Database Backup + try + { + Directory.CreateDirectory("C:\\Backups"); + dbBackupFile = $"C:\\Backups\\{Path.GetRandomFileName()}.bak"; + LogManager.Log($"Creating database backup to '{dbBackupFile}'..."); + db.Backup(localDataSource.Catalog, dbBackupFile); + performDatabaseRollback = true; + LogManager.Log("Database backup created successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Update manager error while trying to create a database backup."); + } + + LogManager.Log("Disposing database manager."); + db.Dispose(); + + foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data || update_response.PerformSchemaUpdate).OrderBy(x => x.Index)) + { + LogManager.Log($"Executing update script '{item.FileName}...'"); + + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); + builder.SetSource(update_response.DataSource); + builder.SetTarget(localDataSource); + + if (item.RequiresSerialNumber) + { + builder.SetMachineSerialNumber(_machineProvider.Machine.Guid); + } + + builder.Synchronize(); + + var config = builder.Build(); + + ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema); + process.Progress += (x, msg) => + { + LogManager.Log(msg); + }; + + try + { + UpdateProgress("Updating Database", item.Name + "..."); + + var result = process.Execute().Result; + + if (result.ExitCode != ExaminerProcessExitCode.Success) + { + throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'.")); + } + + LogManager.Log("Script executed successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Upudate manager error while trying to update the database."); + } + } + + UpdateProgress("Updating Database", "Database synchronization completed successfully."); + LogManager.Log("Update completed successfully."); + OnCompleted(update_response); + } + catch (Exception ex) + { + OnFailed(ex, update_response, performDatabaseRollback, dbBackupFile, localDataSource); + throw ex; + } + }); + } + + /// + /// Checks whether it is necessary to updates all the "overwrite-able" database tables. + /// + /// The machine service address. + /// + public Task UpdateDBCheck() + { + return Task.Factory.StartNew(() => + { + var machineServiceAddress = _settings.GetMachineServiceAddress(); + + LogManager.Log($"Checking if database update is required..."); + + LogManager.Log("Looking for update scripts configuration on application path..."); + + String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); + + if (!File.Exists(config_file)) + { + throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); + } + + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); + + Login(_machineProvider.Machine.Guid).Wait(); + + UpdateDBRequest request = new UpdateDBRequest(); + request.ApplicationVersion = _app_manager.Version.ToString(); + request.FirmwareVersion = _app_manager.FirmwareVersion.ToString(); + + UpdateDBResponse update_response = null; + + update_response = _client.UpdateDB(request).Result; + + LogManager.Log($"Update DB response received: {Environment.NewLine}{update_response.ToJsonString()}"); + + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + + LogManager.Log($"Comparing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + + var report_file = TemporaryManager.CreateFile(".xml"); + + ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); + + bool has_differences = false; + + foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data).OrderBy(x => x.Index)) + { + LogManager.Log($"Executing update script '{item.FileName}...'"); + + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); + builder.SetSource(update_response.DataSource); + builder.SetTarget(localDataSource); + builder.SetReportFile(report_file); + + if (item.RequiresSerialNumber) + { + builder.SetMachineSerialNumber(_machineProvider.Machine.Guid); + } + + var config = builder.Build(); + + ExaminerProcess process = new ExaminerProcess(config, ExaminerProcessType.Data); + process.Progress += (x, msg) => + { + LogManager.Log(msg); + }; + + LogManager.Log("Starting comparison process..."); + LogManager.Log("Generating report on " + report_file); + + try + { + var result = process.Execute().Result; + + if (result.ExitCode != ExaminerProcessExitCode.Success) + { + throw LogManager.Log(new InvalidDataException(String.Format("Update script has terminated with exit code '{0}'.", result.ExitCode))); + } + + LogManager.Log("Comparison completed successfully!"); + LogManager.Log("Loading report file..."); + + ExaminerDataReport report = ExaminerDataReport.FromFile(report_file); + report_file.Delete(); + + LogManager.Log("Comparison summary: \n" + report.Totals.ToJsonString()); + + if (report.HasDifferences) + { + has_differences = true; + break; + } + } + catch (Exception ex) + { + OnFailed(ex, update_response, false, null, null); + throw LogManager.Log(ex, "Update manager error while trying to compare the database."); + } + } + + LogManager.Log("Comparison completed successfully."); + + if (!has_differences) + { + OnCompleted(update_response, true); + } + + return new DbCompareResult() + { + RequiresUpdate = has_differences, + UpdateDBResponse = update_response, + }; + }); + } + + /// + /// Performs a machine update using the specified software update package path. + /// + /// Name of the file. + /// + public async Task UpdateFromTUP(string fileName, bool setupFirmware, bool setupFPGA) + { + _updateStartDate = DateTime.UtcNow; + _logs.Clear(); + + TaskCompletionSource result = new TaskCompletionSource(); + + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + bool performDatabaseRollback = false; + String dbBackupFile = null; + String tempDbName = "Tango_TUP"; + String tempDbFileName = tempDbName + ".bak"; + String backupsFolder = "C:\\Backups"; + bool replaceBinaries = false; + PublishInfo publishInfo = null; + + String serialNumber = _machineProvider.Machine.SerialNumber; + + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; + + try + { + _isUpdating = true; + + LogManager.Log($"Starting machine update (TUP) for serial number {serialNumber}..."); + + //Connecting to machine... + LogManager.Log("Verifying machine connection and state..."); + + UpdateProgress("Verifying machine state", "Initializing..."); + + await Task.Delay(1000); + + IMachineOperator op = _machineProvider.MachineOperator; + + if (setupFirmware) + { + LogManager.Log("Machine is configured to update firmware..."); + + if (op.State != Transport.TransportComponentState.Connected) + { + throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); + } + } + + if (!op.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status.")); + } + + UpdateProgress("Exploring package", "Extracting..."); + LogManager.Log("Extracting package..."); + + LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}."); + + await Task.Factory.StartNew(() => + { + //Extract software package. + ZipFile.ExtractToDirectory(fileName, _newPackageTempFolder); + }); + + //Extracting publish info + UpdateProgress("Exploring package", "Verifying..."); + publishInfo = PublishInfo.FromJson(File.ReadAllText(Path.Combine(_newPackageTempFolder, "version.json"))); + + if (!publishInfo.IsMachineTupPackage) + { + throw new InvalidOperationException("The specified tup file is invalid. Updating a machine from a tup file requires a custom generated package."); + } + + if (publishInfo.MachineSerialNumber != serialNumber) + { + throw new InvalidOperationException("The specified tup file is invalid. The package was generated for a different machine."); + } + + if (publishInfo.MachineDeploymentSlot != _settings.DeploymentSlot) + { + throw new InvalidOperationException("The specified tup file is invalid. The package was generated on a different environment."); + } + + replaceBinaries = _app_manager.Version.ToString() != publishInfo.ApplicationVersion; + + LogManager.Log("Copying latest updater utility to application path..."); + + //Copy new updater utility to app path. + File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true); + + //Run pre-update packages. + try + { + UpdateProgress("Preparing", "Running update packages..."); + LogManager.Log("Running pre-update packages..."); + var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages"); + + Version updateVersion = new Version(1, 0, 0, 0); + try + { + updateVersion = Version.Parse(publishInfo.ApplicationVersion); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error parsing new version string for package runner."); + } + + await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error running pre-update packages..."); + } + + //Synchronize database + UpdateProgress("Updating Database", "Initializing..."); + + UpdateProgress("Updating Database", "Connecting to local database..."); + LogManager.Log("Initializing database manager..."); + DbManager db = DbManager.FromDataSource(localDataSource); + + LogManager.Log("Checking Tango database exists on the local machine..."); + if (!db.Exists(localDataSource.Catalog)) + { + throw new InvalidProgramException("Database tango does not exists."); + } + + UpdateProgress("Updating Database", "Creating database backup..."); + + //Create Database Backup + try + { + Directory.CreateDirectory(backupsFolder); + dbBackupFile = $"{backupsFolder}\\{Path.GetRandomFileName()}.bak"; + LogManager.Log($"Creating database backup to '{dbBackupFile}'..."); + await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile)); + performDatabaseRollback = true; + LogManager.Log("Database backup created successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Update manager error while trying to create a database backup."); + } + + LogManager.Log("Extracting database file from package..."); + File.Copy(Path.Combine(_newPackageTempFolder, tempDbFileName), Path.Combine(backupsFolder, tempDbFileName)); + + LogManager.Log("Restoring package database as a new database..."); + db.RestoreAsNew(tempDbName, Path.Combine(backupsFolder, tempDbFileName), backupsFolder); + + Core.DataSource tempDbDataSource = new Core.DataSource(); + tempDbDataSource.Address = localDataSource.Address; + tempDbDataSource.IntegratedSecurity = localDataSource.IntegratedSecurity; + tempDbDataSource.Type = localDataSource.Type; + tempDbDataSource.Catalog = tempDbName; + + LogManager.Log("Disposing database manager."); + db.Dispose(); + + LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); + + UpdateProgress("Updating Database", "Initializing update sequence..."); + + ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( + Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"), + Path.Combine(_newPackageTempFolder, "Update Scripts"), + tempDbDataSource, + localDataSource, + _machineProvider.Machine.Guid); + + runner.Log += (x, msg) => + { + LogManager.Log(msg); + ProgressLog?.Invoke(this, msg); + }; + + runner.ScriptExecuting += (x, item) => + { + LogManager.Log($"Executing script {item.ToString()}..."); + UpdateProgress("Updating Database", item.Name + "..."); + }; + + LogManager.Log("Starting synchronization process..."); + + try + { + await runner.Run(); + LogManager.Log("Synchronization completed successfully!"); + UpdateProgress("Updating Database", "Database synchronization completed successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Update manager error while trying to synchronize database."); + } - LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + LogManager.Log("Getting setup firmware/fpga directly from db.."); - UpdateProgress("Updating Database", "Initializing update sequence..."); + using (var dbManager = DbManager.FromDataSource(localDataSource)) + { + try + { + String firmware = dbManager.GetValue($"SELECT TOP 1 * FROM MACHINES WHERE SERIAL_NUMBER = '{serialNumber}'", "SETUP_FIRMWARE"); + String fpga = dbManager.GetValue($"SELECT TOP 1 * FROM MACHINES WHERE SERIAL_NUMBER = '{serialNumber}'", "SETUP_FPGA"); - ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); + setupFirmware = bool.Parse(firmware); + setupFPGA = bool.Parse(fpga); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error getting new values of SETUP_FIRMWARE and SETUP_FPGA."); + } + } - foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data || update_response.PerformSchemaUpdate).OrderBy(x => x.Index)) + //Updating firmware + if (setupFirmware) { - LogManager.Log($"Executing update script '{item.FileName}...'"); + UpdateProgress("Updating Firmware", "Connecting to firmware device..."); + LogManager.Log(""); + LogManager.Log("-------------------------------------------------------------------------"); + LogManager.Log("Updating Firmware..."); - ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); - builder.SetSource(update_response.DataSource); - builder.SetTarget(localDataSource); + UpdateProgress("Updating Firmware", "Loading firmware package..."); + var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); + var stream = new FileStream(tfpPath, FileMode.Open); - if (item.RequiresSerialNumber) + if (setupFPGA) { - builder.SetMachineSerialNumber(serialNumber); + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; + } + else + { + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; } - builder.Synchronize(); - - var config = builder.Build(); - - ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema); - process.Progress += (x, msg) => + var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); + handler.Failed += (_, ex) => { - LogManager.Log(msg); + stream.Dispose(); + OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo); }; - - try + handler.Completed += (_, __) => { - UpdateProgress("Updating Database", item.Name + "..."); - - var result = process.Execute().Result; - - if (result.ExitCode != ExaminerProcessExitCode.Success) + UpdateProgress("Updating Firmware", "Firmware update completed successfully."); + stream.Dispose(); + OnCompleted(new MachineUpdateResult() { - throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'.")); - } - - LogManager.Log("Script executed successfully."); - } - catch (Exception ex) + UpdatePackagePath = _newPackageTempFolder, + RequiresBinariesUpdate = replaceBinaries, + }, result, null, tempDbName, backupsFolder, localDataSource, publishInfo); + }; + handler.Canceled += (_, __) => { - throw LogManager.Log(ex, "Setup manager error while trying to update the database."); - } + stream.Dispose(); + OnFailed(new Exception("The operation has been canceled."), result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo); + }; + handler.Progress += (_, e) => + { + UpdateProgress("Updating Firmware", e.Message, e.IsIndeterminate, e.Current, e.Total); + }; + } + else + { + OnCompleted(new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + RequiresBinariesUpdate = replaceBinaries, + }, result, null, tempDbName, backupsFolder, localDataSource, publishInfo); } + } + catch (Exception ex) + { + OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo); + } - UpdateProgress("Updating Database", "Database synchronization completed successfully."); - LogManager.Log("Update completed successfully."); - }); + return await result.Task; } /// - /// Checks whether it is necessary to updates all the "overwrite-able" database tables. + /// Performs a firmware upgrade from the specified TFP file. /// - /// The serial number. - /// The machine service address. + /// Name of the file. /// - public Task UpdateDBCheck(string serialNumber) + /// + /// Could not perform a firmware upgrade while the machine is not connected. + /// or + /// + public async Task UpdateFromTFP(String fileName) { - return Task.Factory.StartNew(() => - { - var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); - - LogManager.Log($"Checking if database update is required for serial number {serialNumber}..."); - - LogManager.Log("Looking for update scripts configuration on application path..."); - - String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); + _updateStartDate = DateTime.UtcNow; + _logs.Clear(); - if (!File.Exists(config_file)) - { - throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); - } + TaskCompletionSource result = new TaskCompletionSource(); - LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); + String version = String.Empty; + Stream stream = null; - Login(serialNumber).Wait(); + try + { + _isUpdating = true; - UpdateDBRequest request = new UpdateDBRequest(); - request.SerialNumber = serialNumber; + IMachineOperator op = _machineProvider.MachineOperator; - UpdateDBResponse update_response = null; + UpdateProgress("Updating Firmware", "Loading firmware package..."); + stream = new FileStream(fileName, FileMode.Open); - update_response = _client.UpdateDB(request).Result; + var packageInfo = await op.GetFirmwarePackageInfo(stream); + stream.Position = 0; + version = packageInfo.FileDescriptors.FirstOrDefault(x => x.Destination == PMR.FirmwareUpgrade.VersionFileDestination.Mcu)?.Version; - LogManager.Log($"Update DB response received: {Environment.NewLine}{update_response.ToJsonString()}"); + LogManager.Log("Verifying machine connection and state..."); - var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + UpdateProgress("Verifying machine state", "Initializing..."); - LogManager.Log($"Comparing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + await Task.Delay(1000); - var report_file = TemporaryManager.CreateFile(".xml"); + if (op.State != Transport.TransportComponentState.Connected) + { + throw LogManager.Log(new InvalidOperationException("Could not perform a firmware upgrade while the machine is not connected.")); + } + if (!op.CanPrint) + { + throw LogManager.Log(new InvalidOperationException($"Could not perform a firmware upgrade while the machine is in {op.Status} status.")); + } - ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); + UpdateProgress("Updating Firmware", "Connecting to firmware device..."); + LogManager.Log(""); + LogManager.Log("-------------------------------------------------------------------------"); + LogManager.Log("Updating Firmware..."); - bool has_differences = false; + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; - foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data).OrderBy(x => x.Index)) + var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); + handler.Failed += (_, ex) => { - LogManager.Log($"Executing update script '{item.FileName}...'"); - - ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); - builder.SetSource(update_response.DataSource); - builder.SetTarget(localDataSource); - builder.SetReportFile(report_file); - - if (item.RequiresSerialNumber) + stream.Dispose(); + OnFailed(ex, result, version); + }; + handler.Completed += (_, __) => + { + UpdateProgress("Updating Firmware", "Firmware update completed successfully."); + stream.Dispose(); + OnCompleted(result, version); + }; + handler.Canceled += (_, __) => + { + stream.Dispose(); + OnFailed(new Exception("The operation has been canceled."), result, version); + }; + handler.Progress += (_, e) => + { + UpdateProgress("Updating Firmware", e.Message, e.IsIndeterminate, e.Current, e.Total); + }; + } + catch (Exception ex) + { + try + { + if (stream != null) { - builder.SetMachineSerialNumber(serialNumber); + stream.Dispose(); } + } + catch { } - var config = builder.Build(); + OnFailed(ex, result, version); + } - ExaminerProcess process = new ExaminerProcess(config, ExaminerProcessType.Data); - process.Progress += (x, msg) => - { - LogManager.Log(msg); - }; + await result.Task; + } - LogManager.Log("Starting comparison process..."); - LogManager.Log("Generating report on " + report_file); + /// + /// Gets the update package file information. + /// + /// The file path. + /// + public Task GetUpdatePackageFileInfo(string filePath) + { + return Task.Factory.StartNew(() => + { + using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(filePath)) + { + var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "version.json"); + var reader = appEntry.OpenReader(); - try + using (StreamReader stReader = new StreamReader(reader)) { - var result = process.Execute().Result; - - if (result.ExitCode != ExaminerProcessExitCode.Success) - { - throw LogManager.Log(new InvalidDataException(String.Format("Update script has terminated with exit code '{0}'.", result.ExitCode))); - } - - LogManager.Log("Comparison completed successfully!"); - LogManager.Log("Loading report file..."); + String json = stReader.ReadToEnd(); + reader.Dispose(); - ExaminerDataReport report = ExaminerDataReport.FromFile(report_file); - report_file.Delete(); - - LogManager.Log("Comparison summary: \n" + report.Totals.ToJsonString()); - - if (report.HasDifferences) - { - has_differences = true; - break; - } - } - catch (Exception ex) - { - throw LogManager.Log(ex, "Update manager error while trying to compare the database."); + return PublishInfo.FromJson(json); } } - - LogManager.Log("Comparison completed successfully."); - - return new DbCompareResult() - { - RequiresUpdate = has_differences, - UpdateDBResponse = update_response, - }; }); } /// - /// Performs a machine update using the specified software update package path. + /// Checks whether any post update packages needs to be installed. /// - /// Name of the file. /// - public Task UpdateFromTUP(string fileName) + public Task PostUpdatePackagesRequired() { - return Task.Factory.StartNew(() => - { - LogManager.Log($"Starting machine update from update package '{fileName}'..."); - - //Create temporary folders for packages. - var _newPackageTempFolder = TemporaryManager.CreateFolder(); - _newPackageTempFolder.Persist = true; - - LogManager.Log("Extracting downloaded zip file..."); - //Extract software package. - ZipFile.ExtractToDirectory(fileName, _newPackageTempFolder); - - LogManager.Log("Copying latest updater utility to application path..."); - //Copy new updater utility to app path. - File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true); - - LogManager.Log("Update operation completed!"); - - return new MachineUpdateResult() - { - UpdatePackagePath = _newPackageTempFolder, - }; - }); + String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages"); + return _packageRunner.IsPackageInstallationRequired(PackageType.Post, packagesFolder); } /// - /// Gets the update package file information. + /// Runs all post update packages. /// - /// The file path. /// - public Task GetUpdatePackageFileInfo(string filePath) + public Task RunPostUpdatePackages() { - return Task.Factory.StartNew(() => - { - UpdatePackageFile file = new UpdatePackageFile(); - var tempFolder = TemporaryManager.CreateFolder(); + String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages"); - using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(filePath)) - { - var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "Tango.PPC.UI.exe"); - appEntry.Extract(tempFolder); - } + Version previousVersion = null; + String str = _settings.PreviousApplicationVersion; + + if (Version.TryParse(str, out previousVersion)) + { + return _packageRunner.Run(PackageType.Post, previousVersion, packagesFolder); + } + else + { + throw new InvalidCastException($"Error parsing the previous version string '{str}'."); + } + } - FileVersionInfo info = FileVersionInfo.GetVersionInfo(Path.Combine(tempFolder, "Tango.PPC.UI.exe")); - file.Version = Version.Parse(info.ProductVersion); + public Task RestoreLastDatabaseBackup() + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Rolling back database changes..."); + UpdateProgress("Rollback", "Rolling back database changes..."); - tempFolder.Delete(); + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + var lastBackupFile = SettingsManager.Default.GetOrCreate().LastDatabaseBackupFile; - return file; + using (DbManager db = DbManager.FromDataSource(localDataSource)) + { + try + { + db.Restore(localDataSource.Catalog, lastBackupFile); + LogManager.Log("Database restored successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Could not rollback the database after a failed updater."); + throw ex; + } + finally + { + try + { + File.Delete(lastBackupFile); + } + catch { } + } + } }); } @@ -677,5 +1705,56 @@ namespace Tango.PPC.Common.MachineUpdate } #endregion + + #region Auto Check For Update + + private async void _checkForUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (EnableAutoCheckForUpdates && _settings.AutoCheckForUpdates && !_isUpdating) + { + _checkForUpdateTimer.Stop(); + + try + { + var response = await CheckForUpdate(); + if (response.IsUpdateAvailable || response.IsDatabaseUpdateAvailable) + { + LogManager.Log($"New {(response.IsDatabaseUpdateAvailable ? "database updates" : "application version")} detected ({response.Version}). Raising event..."); + UpdateAvailable?.Invoke(this, response); + } + } + catch { } + + _checkForUpdateTimer.Start(); + } + } + + #endregion + + #region External Bridge + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do nothing. + } + + [ExternalBridgeRequestHandlerMethod(typeof(GetUpdatesAndPackagesRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetUpdatesAndPackagesRequest(GetUpdatesAndPackagesRequest request, String token, ExternalBridgeReceiver receiver) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var updates = await db.TangoUpdates.OrderByDescending(x => x.StartDate).ToListAsync(); + var updatesDTO = updates.Select(x => TangoUpdateDTO.FromObservable(x)).ToList(); + var packages = (await _packageRunner.GetPackagesFile()).PackageInstallations; + + var response = new GetUpdatesAndPackagesResponse(); + response.Updates.AddRange(updatesDTO); + response.Packages.AddRange(packages); + + await receiver.SendGenericResponse(response, token); + } + } + + #endregion } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs index 17ae394ee..85dd5b7d2 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs @@ -12,5 +12,18 @@ namespace Tango.PPC.Common.MachineUpdate /// Gets or sets the temporary update package path from which to get the last downloaded software version. /// public String UpdatePackagePath { get; set; } + + /// + /// Gets or sets a value indicating whether the application should replace it's binaries. + /// + public bool RequiresBinariesUpdate { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MachineUpdateResult() + { + RequiresBinariesUpdate = true; + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs deleted file mode 100644 index df496c3be..000000000 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.PPC.Common.MachineUpdate -{ - public class UpdatePackageFile - { - public Version Version { get; set; } - } -} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Models/FineTuneItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Models/FineTuneItem.cs index 2eea5c3ce..c03be1ae9 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Models/FineTuneItem.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Models/FineTuneItem.cs @@ -18,6 +18,8 @@ namespace Tango.PPC.Common.Models { public event Action SelectedChanged; + public BrushStop BrushStop { get; set; } + /// /// Gets or sets the brush stops. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/INavigationManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/INavigationManager.cs index 8df0a7fb8..1fcdb4410 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/INavigationManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/INavigationManager.cs @@ -12,6 +12,11 @@ namespace Tango.PPC.Common.Navigation /// public interface INavigationManager { + /// + /// Occurs when the current view model has changed. + /// + event EventHandler CurrentVMChanged; + /// /// Gets the current module. /// @@ -27,6 +32,16 @@ namespace Tango.PPC.Common.Navigation /// bool CanNavigateBack { get; } + /// + /// Gets a value indicating whether the back should be enabled. + /// + bool IsBackEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether the navigation system is currently navigating. + /// + bool IsNavigating { get; set; } + /// /// Navigates to the previous view if is true. /// @@ -79,7 +94,7 @@ namespace Tango.PPC.Common.Navigation /// Navigates to the specified module and view by full path (e.g Jobs.JobsView). /// /// The full path. - Task NavigateTo(String fullPath, bool pushToHistory = true); + Task NavigateTo(String fullPath, bool pushToHistory = true, Action onNavigating = null, Action onNavigated = null); /// /// Navigates to the specified module and view with the specified object and expecting a return parameter. diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/NavigationView.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/NavigationView.cs index b4562054c..643908e87 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/NavigationView.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/NavigationView.cs @@ -22,6 +22,7 @@ namespace Tango.PPC.Common.Navigation HomeModule, ShutdownView, RestartingSystemView, - EmergencyView + EmergencyView, + RestartingView, } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarItem.cs index 1c47d2a97..fdd66a56b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarItem.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarItem.cs @@ -13,6 +13,16 @@ namespace Tango.PPC.Common.Notifications /// public abstract class AppBarItem : ItemBase { + private AppBarPriority _priority; + public AppBarPriority Priority + { + get { return _priority; } + set { _priority = value; RaisePropertyChangedAuto(); } + } + public AppBarItem() + { + Priority = AppBarPriority.Normal; + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarPriority.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarPriority.cs new file mode 100644 index 000000000..bd8547f5d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarPriority.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Notifications +{ + public enum AppBarPriority + { + Low, + Normal, + High + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/INotificationProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/INotificationProvider.cs index c4e82b7d2..950b8d23f 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/INotificationProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/INotificationProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -22,20 +23,25 @@ namespace Tango.PPC.Common.Notifications /// ObservableCollection NotificationItems { get; } + /// + /// Gets the notification items view. + /// + ICollectionView NotificationItemsView { get; } + /// /// Gets the collection of taskbar items. /// ObservableCollection TaskBarItems { get; } /// - /// Gets the current application bar item. + /// Gets the application bar items. /// - AppBarItem CurrentAppBarItem { get; } + ObservableCollection AppBarItems { get; } /// - /// Gets a value indicating whether this instance has application bar item. + /// Gets a value indicating whether this instance has any application bar items. /// - bool HasAppBarItem { get; } + bool HasAppBarItems { get; } /// /// Gets a value indicating whether this instance has notification items. @@ -176,7 +182,7 @@ namespace Tango.PPC.Common.Notifications /// /// /// - AppBarItem PushAppBarItem() where T : AppBarItem; + T PushAppBarItem() where T : AppBarItem; /// /// Pops the application bar item. diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItem.cs index c96fe9dee..6a29511a9 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItem.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItem.cs @@ -14,22 +14,22 @@ namespace Tango.PPC.Common.Notifications /// public abstract class NotificationItem : ItemBase { - /// - /// Initializes a new instance of the class. - /// - public NotificationItem() : base() + public enum NotificationPriority { - CanClose = true; + Low, + Normal, + High, + VeryHigh, + Critical, } - private bool _isExpanded; /// - /// Gets or sets a value indicating whether the notification panel is expanded. + /// Initializes a new instance of the class. /// - public bool IsExpanded + public NotificationItem() : base() { - get { return _isExpanded; } - set { _isExpanded = value; RaisePropertyChangedAuto(); } + CanClose = true; + Priority = NotificationPriority.Normal; } private bool _canClose; @@ -42,6 +42,11 @@ namespace Tango.PPC.Common.Notifications set { _canClose = value; RaisePropertyChangedAuto(); } } + /// + /// Gets or sets the notification priority. + /// + public NotificationPriority Priority { get; set; } + /// /// Called when the item has been pressed. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItem.cs index a9de336a1..7d85ef6a7 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItem.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItem.cs @@ -77,11 +77,12 @@ namespace Tango.PPC.Common.Notifications.NotificationItems /// The expanded message. /// The type. /// The pressed action. - public MessageNotificationItem(String message, String expandedMessage, MessageNotificationItemTypes type, Action pressedAction) : this() + public MessageNotificationItem(String message, String expandedMessage, MessageNotificationItemTypes type, Action pressedAction, NotificationPriority priority = NotificationPriority.Normal) : this() { Message = message; ExpandedMessage = expandedMessage; MessageType = type; + Priority = priority; Pressed += (_, __) => pressedAction?.Invoke(); } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItemView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItemView.xaml index 33c58f51e..cab40e50e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItemView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItemView.xaml @@ -111,20 +111,20 @@ - - + + - - - + + + - + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/DefaultOperationSystemManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/DefaultOperationSystemManager.cs index 2164a71c3..32fd74646 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/DefaultOperationSystemManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/DefaultOperationSystemManager.cs @@ -232,5 +232,27 @@ namespace Tango.PPC.Common.OS return Environment.MachineName; }); } + + /// + /// Sets the device host name. + /// + /// + public async Task SetDeviceName(String name) + { + var command = new CmdCommand("wmic", $"computersystem where caption='{Environment.MachineName}' rename '{name}'"); + await command.Run(); + } + + /// + /// Opens the operating system shell (explorer). + /// + public void OpenShell() + { + Process.Start(new ProcessStartInfo() + { + FileName = @"C:\Windows\Sysnative\cmd.exe", + Arguments = @"/c start /B explorer.exe" + }); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/IOperationSystemManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/IOperationSystemManager.cs index 3e24ffe72..4faef33f9 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/IOperationSystemManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/OS/IOperationSystemManager.cs @@ -56,6 +56,12 @@ namespace Tango.PPC.Common.OS /// Task GetDeviceName(); + /// + /// Sets the device host name. + /// + /// + Task SetDeviceName(String name); + /// /// Restarts the system. /// @@ -67,5 +73,10 @@ namespace Tango.PPC.Common.OS /// /// void Shutdown(); + + /// + /// Opens the operating system shell (explorer). + /// + void OpenShell(); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs index b1bc3faad..aacbe8901 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs @@ -4,9 +4,13 @@ using System.Linq; using System.ServiceModel; using System.Text; using System.Threading.Tasks; +using Tango.BL.Enumerations; +using Tango.Integration.Operation; using Tango.Logging; +using Tango.PMR.Integration; using Tango.PMR.Printing; using Tango.Settings; +using Tango.Transport.Adapters; using Tango.Web; namespace Tango.PPC.Common @@ -17,11 +21,6 @@ namespace Tango.PPC.Common /// public class PPCSettings : SettingsBase { - /// - /// Gets or sets the logging categories. - /// - public List LoggingCategories { get; set; } - /// /// Gets or sets the state of the application. /// @@ -137,6 +136,157 @@ namespace Tango.PPC.Common /// public bool EnableJobLiquidQuantityValidation { get; set; } + /// + /// Gets or sets the job number of units method. + /// + public JobUnitsMethods JobUnitsMethod { get; set; } + + /// + /// Gets or sets the loaded RML unique identifier. + /// + public String LoadedRmlGuid { get; set; } + + /// + /// Gets or sets the default RML unique identifier. + /// + public String DefaultRmlGuid { get; set; } + + /// + /// Gets or sets the default color space unique identifier. + /// + public List SupportedColorSpaces { get; set; } + + /// + /// Gets or sets the target job types. + /// + public List SupportedJobTypes { get; set; } + + /// + /// Gets or sets the default spool type unique identifier. + /// + public String DefaultSpoolTypeGuid { get; set; } + + /// + /// Gets or sets the default length of the segment. + /// + public int DefaultSegmentLength { get; set; } + + /// + /// Gets or sets the previous application version. + /// + public String PreviousApplicationVersion { get; set; } + + /// + /// Gets or sets a value indicating whether synchronize jobs with twine server. + /// + public bool SynchronizeJobs { get; set; } + + /// + /// Gets or sets a value indicating whether synchronize diagnostics data. + /// + public bool SynchronizeDiagnostics { get; set; } + + /// + /// Gets or sets the synchronization interval. + /// + public TimeSpan SynchronizationInterval { get; set; } + + /// + /// Gets or sets the known firmware version. + /// + public String FirmwareVersion { get; set; } + + /// + /// Gets or sets a value indicating whether to display the power up screen. + /// + public bool DisplayPowerUpScreen { get; set; } + + /// + /// Gets or sets the power up screen timeout. + /// + public TimeSpan PowerUpScreenTimeout { get; set; } + + /// + /// Gets or sets a value indicating whether to automatically check for software and database (quick) updates. + /// + public bool AutoCheckForUpdates { get; set; } + + /// + /// Gets or sets the automatic update check interval. + /// + public TimeSpan AutoUpdateCheckInterval { get; set; } + + /// + /// Gets or sets a value indicating whether to enable the automatic thread loading support. + /// + public bool EnableAutomaticThreadLoading { get; set; } + + /// + /// Gets or sets a value indicating whether to display the thread loading screen. + /// + public bool DisplayAutomaticThreadLoadingScreen { get; set; } + + /// + /// Gets or sets a value indicating whether to enable embedded debug logs. + /// + public bool EnableEmbeddedDebugLogs { get; set; } + + /// + /// Gets or sets the TCP transport adapter write mode. + /// + public TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; } + + /// + /// Gets or sets a value indicating whether to expose the external bridge service via SignalR. + /// + public bool EnableExternalBridgeSignalR { get; set; } + + /// + /// Gets or sets the name of the exteral bridge SignalR hub. + /// + public String ExternalBridgeSignalRHub { get; set; } + + /// + /// Gets or sets a value indicating whether to enable the internal remote desktop service. + /// + public bool EnableRemoteDesktop { get; set; } + + /// + /// Gets or sets the internal remote desktop service frame rate (1-20). + /// + public int RemoteDesktopFrameRate { get; set; } + + /// + /// Gets or sets a value indicating whether to enable insights. + /// + public bool InsightsEnabled { get; set; } + + /// + /// Gets or sets the insights sampling interval. + /// + public TimeSpan InsightsSamplingInterval { get; set; } + + /// + /// Gets or sets the insights storage cleanup interval. + /// + public TimeSpan InsightsStorageCleanupInterval { get; set; } + + /// + /// Gets or sets the duration of the insights maximum storage duration. + /// + public TimeSpan InsightsMaxStorageDuration { get; set; } + + /// + /// Gets or sets a value indicating whether to bypass Internet connectivity checks before attempting to perform an update for example. + /// + public bool BypassInternetConnectivityCheck { get; set; } + + /// + /// Gets or sets the last database backup file that was generated before application update. + /// If updater utility was successful, this file should be deleted. Otherwise should be restored. + /// + public String LastDatabaseBackupFile { get; set; } + /// /// Gets the machine service address. /// @@ -155,18 +305,44 @@ namespace Tango.PPC.Common EnableGradientGeneration = true; GradientGenerationResolution = 20; MachineScanningTimeoutSeconds = 20; - LoggingCategories = new List(); EmbeddedComPort = "COM10"; EmbeddedDeviceHint = "Tango USB Serial Port"; ExternalBridgePassword = "Aa123456"; HotSpotPassword = "Aa123456"; LockScreenTimeout = TimeSpan.FromMinutes(10); LockScreenPassword = "1111"; - DeploymentSlot = DeploymentSlot.TEST; + DeploymentSlot = DeploymentSlot.DEV; EnableWatchDog = true; EnableEmergencyNotifications = true; EmergencyComPort = "COM2"; EnableJobLiquidQuantityValidation = true; + JobUnitsMethod = JobUnitsMethods.Device; + DefaultSegmentLength = 100; + SupportedColorSpaces = new List(); + SupportedJobTypes = new List(); + PreviousApplicationVersion = "1.0.0.0"; + SynchronizeJobs = false; + SynchronizeDiagnostics = true; + SynchronizationInterval = TimeSpan.FromMinutes(60); + FirmwareVersion = "1.0.0.0"; + DisplayPowerUpScreen = true; + PowerUpScreenTimeout = TimeSpan.FromSeconds(60); + AutoCheckForUpdates = true; + AutoUpdateCheckInterval = TimeSpan.FromMinutes(30); + EnableAutomaticThreadLoading = true; + DisplayAutomaticThreadLoadingScreen = true; + EnableEmbeddedDebugLogs = true; + TcpTransportAdapterWriteMode = TcpTransportAdapterWriteMode.Interval; + EnableExternalBridgeSignalR = true; + ExternalBridgeSignalRHub = "ExternalBridgeHub"; + EnableRemoteDesktop = true; + RemoteDesktopFrameRate = 5; + BypassInternetConnectivityCheck = false; + + InsightsEnabled = true; + InsightsSamplingInterval = TimeSpan.FromMinutes(1); + InsightsMaxStorageDuration = TimeSpan.FromDays(30); + InsightsStorageCleanupInterval = TimeSpan.FromMinutes(60); } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCViewModel.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCViewModel.cs index 5e584f891..98eef6883 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCViewModel.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCViewModel.cs @@ -16,7 +16,10 @@ using Tango.PPC.Common.Navigation; using Tango.PPC.Common.Notifications; using Tango.PPC.Common.Printing; using Tango.PPC.Common.RemoteAssistance; +using Tango.PPC.Common.RemoteDesktop; using Tango.PPC.Common.Storage; +using Tango.PPC.Common.Synchronization; +using Tango.PPC.Common.ThreadLoading; using Tango.Settings; using Tango.SharedUI; using static Tango.SharedUI.Controls.NavigationControl; @@ -27,7 +30,7 @@ namespace Tango.PPC.Common /// Represents a PPC view model base class. /// /// - public abstract class PPCViewModel : ViewModel, INavigationViewModel, INavigationBlocker + public abstract class PPCViewModel : ViewModel, INavigationBlocker { /// /// Gets the static observable entities adapter. @@ -109,6 +112,24 @@ namespace Tango.PPC.Common [TangoInject] public IEventLogger EventLogger { get; set; } + /// + /// Gets or sets the machine data synchronizer. + /// + [TangoInject] + public IMachineDataSynchronizer MachineDataSynchronizer { get; set; } + + /// + /// Gets or sets the remote desktop service. + /// + [TangoInject] + public IRemoteDesktopService RemoteDesktopService { get; set; } + + /// + /// Gets or sets the thread loading service. + /// + [TangoInject] + public IThreadLoadingService ThreadLoadingService { get; set; } + private PPCSettings _settings; /// /// Gets the main PPC settings. @@ -158,6 +179,15 @@ namespace Tango.PPC.Common IsVisible = true; } + /// + /// Called when the navigation system has navigated to this VM view. + /// + /// The view model instance of the previous view model + public virtual void OnNavigatedTo(PPCViewModel fromVM) + { + + } + /// /// Called when the navigation system has navigated from this VM view. /// @@ -166,6 +196,22 @@ namespace Tango.PPC.Common IsVisible = false; } + /// + /// Called before the navigation system has navigated to this VM view. + /// + public virtual void OnBeforeNavigatedTo() + { + + } + + /// + /// Called before the navigation system has navigated from this VM view. + /// + public virtual void OnBeforeNavigatedFrom() + { + IsVisible = false; + } + /// /// Raises the specified message using the default . /// @@ -220,7 +266,7 @@ namespace Tango.PPC.Common /// public virtual void OnApplicationReady() { - + } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs new file mode 100644 index 000000000..59236f667 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Performance; + +namespace Tango.PPC.Common.Performance +{ + [TangoCreateWhenRegistered] + public class DefaultPerformanceService : ExtendedObject, IPerformanceService + { + #region Nested Classes + + public static class PerformanceInfo + { + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetPerformanceInfo([Out] out PerformanceInformation PerformanceInformation, [In] int Size); + + [StructLayout(LayoutKind.Sequential)] + public struct PerformanceInformation + { + public int Size; + public IntPtr CommitTotal; + public IntPtr CommitLimit; + public IntPtr CommitPeak; + public IntPtr PhysicalTotal; + public IntPtr PhysicalAvailable; + public IntPtr SystemCache; + public IntPtr KernelTotal; + public IntPtr KernelPaged; + public IntPtr KernelNonPaged; + public IntPtr PageSize; + public int HandlesCount; + public int ProcessCount; + public int ThreadCount; + } + + public static Int64 GetPhysicalAvailableMemoryInMiB() + { + PerformanceInformation pi = new PerformanceInformation(); + if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi))) + { + return Convert.ToInt64((pi.PhysicalAvailable.ToInt64() * pi.PageSize.ToInt64() / 1048576)); + } + else + { + return -1; + } + + } + + public static Int64 GetTotalMemoryInMiB() + { + PerformanceInformation pi = new PerformanceInformation(); + if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi))) + { + return Convert.ToInt64((pi.PhysicalTotal.ToInt64() * pi.PageSize.ToInt64() / 1048576)); + } + else + { + return -1; + } + + } + } + + #endregion + + private class PerformanceClient + { + public ExternalBridgeReceiver Receiver { get; set; } + public String Token { get; set; } + } + + private List _clients; + private PerformancePackage _package; + private bool _isStarted; + private Thread _performanceThread; + + public bool Enabled { get; set; } = true; + + public DefaultPerformanceService(IPPCExternalBridgeService externalBridge) + { + _package = new PerformancePackage(); + _clients = new List(); + externalBridge.RegisterRequestHandler(this); + } + + [ExternalBridgeRequestHandlerMethod(typeof(StartPerformanceUpdatesRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnStartPerformanceUpdatesRequest(StartPerformanceUpdatesRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + if (!_clients.Exists(x => x.Receiver == receiver)) + { + _clients.Add(new PerformanceClient() { Receiver = receiver, Token = token }); + OnReceiversChanged(); + } + + await receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + _clients.RemoveAll(x => x.Receiver == receiver); + OnReceiversChanged(); + } + + private void OnReceiversChanged() + { + if (_clients.Count > 0 && !_isStarted) + { + _isStarted = true; + _performanceThread = new Thread(PerformanceThreadMethod); + _performanceThread.IsBackground = true; + _performanceThread.Start(); + } + else if (_clients.Count == 0 && _isStarted) + { + _isStarted = false; + } + } + + private async void PerformanceThreadMethod() + { + while (_isStarted) + { + try + { + _package.ApplicationCPU = (int)GetAppCPU(); + _package.CPU = (int)GetTotalCPU(); + _package.ApplicationRAM = (int)BytesToMegaBytes(GetAppRam()); + _package.MaxRAM = (int)BytesToMegaBytes((long)new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory); + _package.RAM = _package.MaxRAM - (int)PerformanceInfo.GetPhysicalAvailableMemoryInMiB(); + + DriveInfo info = new DriveInfo("C"); + _package.DiskCapacity = (int)BytesToMegaBytes(info.TotalSize); + _package.AvailableDiskSpace = (int)BytesToMegaBytes(info.AvailableFreeSpace); + _package.DateTime = DateTime.Now; + + foreach (var client in _clients.ToList()) + { + try + { + await client.Receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, client.Token); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending performance package."); + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error creating performance package."); + } + + Thread.Sleep(200); + } + } + + #region Helpers + + private float BytesToMegaBytes(long bytes) + { + return bytes / 1024f / 1024f; + } + + public float GetAppCPU() + { + PerformanceCounter cpuCounter = new PerformanceCounter(); + cpuCounter.CategoryName = "Process"; + cpuCounter.CounterName = "% Processor Time"; + cpuCounter.InstanceName = Process.GetCurrentProcess().ProcessName; + + // will always start at 0 + float firstValue = cpuCounter.NextValue(); + System.Threading.Thread.Sleep(1000); + // now matches task manager reading + float secondValue = cpuCounter.NextValue(); + + return secondValue / Environment.ProcessorCount; + } + + public float GetTotalCPU() + { + PerformanceCounter cpuCounter = new PerformanceCounter(); + cpuCounter.CategoryName = "Processor"; + cpuCounter.CounterName = "% Processor Time"; + cpuCounter.InstanceName = "_Total"; + + // will always start at 0 + float firstValue = cpuCounter.NextValue(); + System.Threading.Thread.Sleep(1000); + // now matches task manager reading + float secondValue = cpuCounter.NextValue(); + + return secondValue; + } + + public long GetAppRam() + { + Process proc = Process.GetCurrentProcess(); + return proc.PrivateMemorySize64; + } + + #endregion + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs new file mode 100644 index 000000000..29e69aee2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.ExternalBridge; + +namespace Tango.PPC.Common.Performance +{ + public interface IPerformanceService : IPPCService, IExternalBridgeRequestHandler + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.Designer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.Designer.cs index 60e2bdb01..30828af87 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.Designer.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Tango.PPC.Common.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -59,5 +59,25 @@ namespace Tango.PPC.Common.Properties { resourceCulture = value; } } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap finger3 { + get { + object obj = ResourceManager.GetObject("finger3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tap { + get { + object obj = ResourceManager.GetObject("tap", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.resx b/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.resx index af7dbebba..ca6197f54 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.resx +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\finger3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\tap.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs index 526d4465a..1a289ff50 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Tango.AdvancedInstaller; using Tango.Core; using Tango.Core.Helpers; +using Tango.Git; using Tango.PMR.FirmwareUpgrade; using Tango.PPC.Common.Web; using Tango.SQLExaminer; @@ -59,14 +60,11 @@ namespace Tango.PPC.Common.Publish /// Gets the latest version. /// /// - public async Task GetRemoteVersion(String machineVersionGuid) + public async Task GetRemoteVersion(String machineVersionGuid) { _client.Environment = Options.Environment; - var response = await _client.GetLatestVersion(new LatestVersionRequest() - { - MachineVersionGuid = machineVersionGuid, - }); - return response.Version; + var response = await _client.GetLatestVersion(new LatestVersionRequest() { MachineVersionGuid = machineVersionGuid }); + return response; } /// @@ -163,8 +161,12 @@ namespace Tango.PPC.Common.Publish OnPublishProgress(0, 100, $"Fetching remote version from {Options.Environment.ToAddress()}..."); - String remote_version = GetRemoteVersion(Options.MachineVersionGuid).Result; + var r = GetRemoteVersion(Options.MachineVersionGuid).Result; + String remote_version = r.Version; + String remote_firmware_version = r.FirmwareVersion; + String local_version = GetLocalVersion(); + String local_firmware_version = GetLocalFirmwareVersion(Options.TfpPath); OnPublishProgress(0, 100, $"Remote version: {remote_version}"); OnPublishProgress(0, 100, $"Local version: {local_version}"); @@ -174,6 +176,11 @@ namespace Tango.PPC.Common.Publish throw new InvalidOperationException($"The local version '{local_version}' is not greater than the remote version '{remote_version}'."); } + if (Version.Parse(local_firmware_version) < Version.Parse(remote_firmware_version)) + { + throw new InvalidOperationException($"The local firmware version '{local_firmware_version}' is not greater than the remote version '{remote_firmware_version}'."); + } + OnPublishProgress(0, 100, $"Requesting version upload..."); var response = _client.UploadVersion(new UploadVersionRequest() @@ -185,6 +192,7 @@ namespace Tango.PPC.Common.Publish FirmwareVersion = GetVersionInfoFromTFP(Options.TfpPath).FileDescriptors.SingleOrDefault(x => x.Destination == VersionFileDestination.Mcu).Version, }).Result; + CreateTupPackage(tempFile).Wait(); if (!String.IsNullOrWhiteSpace(Options.InstallerProject)) { @@ -210,8 +218,6 @@ namespace Tango.PPC.Common.Publish } } - CreateTupPackage(tempFile).Wait(); - OnPublishProgress(0, 100, $"Starting version upload..."); using (StorageBlobUploader uploader = new StorageBlobUploader(response.BlobAddress, tempFile)) @@ -234,7 +240,7 @@ namespace Tango.PPC.Common.Publish Token = response.Token, }).Wait(); - remote_version = GetRemoteVersion(Options.MachineVersionGuid).Result; + remote_version = GetRemoteVersion(Options.MachineVersionGuid).Result.Version; local_version = GetLocalVersion(); OnPublishProgress(0, 0, $"Remote version: {remote_version}"); @@ -245,6 +251,55 @@ namespace Tango.PPC.Common.Publish throw new InvalidOperationException("The remote version does not seems to have been updated."); } + if (Options.CreateTag) + { + String repoPath = Path.GetFullPath("../../../../../"); + String tagVersion = System.Version.Parse(GetLocalVersion()).ToString(3); + String tagName = $"PPC_v{tagVersion}"; + + using (GitRepositoryManager git = new GitRepositoryManager(repoPath, Options.Email, Options.PersonalAccessToken)) + { + OnPublishProgress(0, 100, "Checking repository changes..."); + int changes = git.GetChanges().Count; + if (changes > 0) + { + if (Options.AutoCommitAndPush) + { + OnPublishProgress(0, 100, "Committing repository changes..."); + git.Commit(tagName); + } + else + { + throw new InvalidOperationException($"There are {changes} uncommitted changes on the repository. Please commit and push all changes before creating the Tag"); + } + } + + OnPublishProgress(0, 100, "Checking outgoing commits..."); + int commits = git.GetOutgoingCommits().Count; + if (commits > 0) + { + if (Options.AutoCommitAndPush) + { + OnPublishProgress(0, 100, "Pushing repository changes..."); + git.Sync(); + } + else + { + throw new InvalidOperationException($"There are {commits} outgoing commits on the repository. Please push all commits before creating the Tag"); + } + } + + git.Progress += (x, e) => + { + OnPublishProgress(e.Progress.Value, e.Progress.Maximum, $"Pushing Tag '{tagName}'..."); + }; + + OnPublishProgress(0, 100, $"Creating Tag '{tagName}'..."); + + git.CreatePushTag(tagName, Options.Comments, "Roy Ben Shabat"); + } + } + OnPublishProgress(0, 0, "Version published successfully."); } catch (Exception ex) @@ -289,13 +344,21 @@ namespace Tango.PPC.Common.Publish using (ZipFile zip = new ZipFile()) { - zip.AddFile(Options.TfpPath, "/").FileName = "firmware_package.tfp"; + zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression; + + if (Options.BuildConfig != "Debug") + { + zip.AddFile(Options.TfpPath, "/").FileName = "firmware_package.tfp"; + } PublishInfo versionInfo = new PublishInfo(); versionInfo.ApplicationVersion = GetLocalVersion(); versionInfo.Comments = Options.Comments; versionInfo.Firmware = GetVersionInfoFromTFP(Options.TfpPath); + //Validate the package. + versionInfo.Firmware.Validate(); + var versionInfoFile = TemporaryManager.CreateImaginaryFile(); File.WriteAllText(versionInfoFile, versionInfo.ToJson()); zip.AddFile(versionInfoFile, "/").FileName = "version.json"; @@ -362,6 +425,8 @@ namespace Tango.PPC.Common.Publish var cuf = zip.AddFile(update_config_file, update_dir); cuf.FileName = update_dir + "\\config.xml"; + zip.AddDirectory(folder + "\\" + "Packages", "/Packages"); + foreach (var file in Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly)) { zip.AddFile(file, "/"); @@ -403,6 +468,16 @@ namespace Tango.PPC.Common.Publish } } + /// + /// Gets the MCU version from the specified TFP file. + /// + /// The TFP file. + /// + public String GetLocalFirmwareVersion(String tfpFile) + { + return GetVersionInfoFromTFP(tfpFile).GetMcuVersion().ToString(); + } + /// /// Raises the publish progress event. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishInfo.cs index 77717254e..1bbdb80d0 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishInfo.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishInfo.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.PMR.FirmwareUpgrade; +using Tango.Web; namespace Tango.PPC.Common.Publish { @@ -13,6 +14,9 @@ namespace Tango.PPC.Common.Publish public String ApplicationVersion { get; set; } public VersionPackageDescriptor Firmware { get; set; } public String Comments { get; set; } + public bool IsMachineTupPackage { get; set; } + public String MachineSerialNumber { get; set; } + public DeploymentSlot MachineDeploymentSlot { get; set; } public PublishInfo() { @@ -24,9 +28,25 @@ namespace Tango.PPC.Common.Publish return JsonConvert.SerializeObject(this); } - public PublishInfo FromJson(String json) + public static PublishInfo FromJson(String json) { return JsonConvert.DeserializeObject(json); } + + public String GetFirmwareVersion() + { + Version version = new Version("1.0.0.0"); + + var s = Firmware.FileDescriptors.FirstOrDefault(x => x.Destination == VersionFileDestination.Mcu); + if (s != null) + { + if (Version.TryParse(s.Version,out version)) + { + return version.ToString(); + } + } + + return version.ToString(); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishOptions.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishOptions.cs index 4c40acb44..399a19f0d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishOptions.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishOptions.cs @@ -17,6 +17,7 @@ namespace Tango.PPC.Common.Publish public event EventHandler BuidConfigChanged; public event EventHandler BasicInfoChanged; public event EventHandler MachineVersionGuidChanged; + public event EventHandler TfpPathChanged; private String basePath; [Option("path", HelpText = "Specifies the application base path.", Required = false)] @@ -79,7 +80,7 @@ namespace Tango.PPC.Common.Publish public String TfpPath { get { return _tfpPath; } - set { _tfpPath = value; RaisePropertyChangedAuto(); } + set { _tfpPath = value; RaisePropertyChangedAuto(); TfpPathChanged?.Invoke(this, new EventArgs()); } } private String _installerProject; @@ -105,6 +106,28 @@ namespace Tango.PPC.Common.Publish set { _synchronization = value; RaisePropertyChangedAuto(); } } + private String _personalAccessToken; + public String PersonalAccessToken + { + get { return _personalAccessToken; } + set { _personalAccessToken = value; RaisePropertyChangedAuto(); } + } + + private bool _createTag; + public bool CreateTag + { + get { return _createTag; } + set { _createTag = value; RaisePropertyChangedAuto(); } + } + + private bool _autoCommitAndSync; + public bool AutoCommitAndPush + { + get { return _autoCommitAndSync; } + set { _autoCommitAndSync = value; RaisePropertyChangedAuto(); } + } + + public PublishOptions() { BasePath = AppDomain.CurrentDomain.BaseDirectory + "..\\"; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs new file mode 100644 index 000000000..477663342 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.RemoteActions +{ + public interface IRemoteActionsService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/DefaultRemoteAssistanceProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/DefaultRemoteAssistanceProvider.cs index eae13a882..c266ba7c0 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/DefaultRemoteAssistanceProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/DefaultRemoteAssistanceProvider.cs @@ -96,8 +96,12 @@ namespace Tango.PPC.Common.RemoteAssistance /// Installs the remote assistance. /// /// The machine serial number. + /// The remote assistance group. + /// The machine working environment. /// - public async Task InstallRemoteAssistance(String machineSerialNumber) + /// + /// The remote assistance service was installed but could not be found. + public async Task InstallRemoteAssistance(String machineSerialNumber, String group, String environment) { try { @@ -106,26 +110,21 @@ namespace Tango.PPC.Common.RemoteAssistance throw new FileNotFoundException($"The remote assistance installer file could not be found at {_installer_path}."); } - if (!(await IsRemoteAssistanceInstalled())) - { - CmdCommand command = new CmdCommand("msiexec.exe", $"/i \"{_installer_path}\" /qn CUSTOMCONFIGID=ke43ann APITOKEN=4765529-gon1LwO1N1TTrlLI21ji ASSIGNMENTOPTIONS=\" --reassign --alias {"TANGO-" + machineSerialNumber} --grant-easy-access\""); - command.Timeout = TimeSpan.FromSeconds(30); - await command.Run(); + String q = "\""; + //CmdCommand command = new CmdCommand("msiexec.exe", $"/i \"{_installer_path}\" /qn CUSTOMCONFIGID=ke43ann APITOKEN=4765529-gon1LwO1N1TTrlLI21ji ASSIGNMENTOPTIONS=\" --reassign --alias {"TANGO-" + machineSerialNumber}-{environment} --grant-easy-access\""); + CmdCommand command = new CmdCommand("msiexec.exe", $"/i {q}{_installer_path}{q} /qn CUSTOMCONFIGID=ke43ann APITOKEN=4765529-gon1LwO1N1TTrlLI21ji ASSIGNMENTOPTIONS={q} --group {q}{q} {group} {q}{q} --reassign --alias TANGO-{machineSerialNumber}-{environment} --grant-easy-access{q}"); + command.Timeout = TimeSpan.FromSeconds(30); + await command.Run(); - bool exist = await IsRemoteAssistanceInstalled(); + bool exist = await IsRemoteAssistanceInstalled(); - if (exist) - { - await DisableRemoteAssistance(); - } - else - { - throw new ApplicationException("The remote assistance service was installed but could not be found."); - } + if (exist) + { + await DisableRemoteAssistance(); } else { - LogManager.Log("Remote assistance is already installed."); + throw new ApplicationException("The remote assistance service was installed but could not be found."); } } catch (Exception ex) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/IRemoteAssistanceProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/IRemoteAssistanceProvider.cs index cafb8dab9..3b7d489e6 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/IRemoteAssistanceProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/IRemoteAssistanceProvider.cs @@ -32,7 +32,9 @@ namespace Tango.PPC.Common.RemoteAssistance /// Installs the remote assistance. /// /// The machine serial number. + /// The remote assistance group. + /// The machine working environment. /// - Task InstallRemoteAssistance(String machineSerialNumber); + Task InstallRemoteAssistance(String machineSerialNumber, String group, String environment); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs new file mode 100644 index 000000000..8535d45d4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs @@ -0,0 +1,584 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Security.Authentication; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using Tango.Core; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.Logging; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Common.OS; +using Tango.RemoteDesktop; +using Tango.RemoteDesktop.CaptureMethods; +using Tango.RemoteDesktop.Encoders; +using Tango.RemoteDesktop.Engines; +using Tango.RemoteDesktop.Frames; +using Tango.RemoteDesktop.Input; +using Tango.RemoteDesktop.Network; +using Tango.Settings; +using Tango.Transport; +using Tango.WebRTC; +using static Tango.RemoteDesktop.Input.MouseController; + +namespace Tango.PPC.Common.RemoteDesktop +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteDesktopService : ExtendedObject, IRemoteDesktopService, IExternalBridgeRequestHandler + { + private RemoteDesktopPacket _initialPacket; + private RasterScreenCaptureEngine _engine; + private PPCSettings _settings; + private List _clients; + private JsonSerializerSettings _jsonSettings; + private IOperationSystemManager _osManager; + private IPPCApplicationManager _appManager; + private bool _drawCursor; + private bool _isMouseDown; + private bool _ensureMouseDown; + + /// + /// Gets or sets a value indicating whether this is enabled. + /// + public bool Enabled { get; set; } = true; + + private bool _isStarted; + /// + /// Gets a value indicating whether the remote desktop service has started. + /// + public bool IsStarted + { + get { return _isStarted; } + private set { _isStarted = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets a value indicating whether there is any active remote desktop session with a remote peer. + /// + public bool InSession + { + get + { + return _clients.Count > 0; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The application manager. + /// The external bridge. + /// The os manager. + public DefaultRemoteDesktopService(IPPCApplicationManager applicationManager, IPPCExternalBridgeService externalBridge, IOperationSystemManager osManager) + { + _osManager = osManager; + _appManager = applicationManager; + + _jsonSettings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.All + }; + + _settings = SettingsManager.Default.GetOrCreate(); + Enabled = _settings.EnableRemoteDesktop; + + applicationManager.ApplicationReady += ApplicationManager_ApplicationReady; + + externalBridge.RegisterRequestHandler(this); + + _clients = new List(); + _engine = new RasterScreenCaptureEngine(); + + _engine.CaptureCursor = false; + + _engine.FrameRate = Math.Min(Math.Max(_settings.RemoteDesktopFrameRate, 1), 20); + _engine.FrameReceived += _engine_FrameReceived; + } + + private void ApplicationManager_ApplicationReady(object sender, EventArgs e) + { + + + var mainWindow = System.Windows.Application.Current.MainWindow; + + if (mainWindow.WindowStyle != System.Windows.WindowStyle.None) + { + mainWindow.LocationChanged += (_, __) => + { + _engine.CaptureRegion = new CaptureRegion() + { + Left = (int)mainWindow.Left + 10, + Top = (int)mainWindow.Top + 5, + Width = (int)mainWindow.Width - 20, + Height = (int)mainWindow.Height - 15 + }; + }; + + _engine.CaptureRegion = new CaptureRegion() + { + Left = (int)mainWindow.Left + 10, + Top = (int)mainWindow.Top + 5, + Width = (int)mainWindow.Width - 20, + Height = (int)mainWindow.Height - 15 + }; + } + else + { + //DirectX capturing is not working on PPC !! Maybe when we replace ? + //try + //{ + // _engine.CaptureMethod = new DirectXScreenCapture(); + //} + //catch (Exception ex) + //{ + // LogManager.Log(ex, "Could not initialize DirectX screen capture method on this device. Falling back to GDI."); + //} + } + + mainWindow.PreviewMouseDown += (_, __) => + { + _isMouseDown = true; + _ensureMouseDown = true; + }; + + mainWindow.PreviewMouseUp += (_, __) => + { + _isMouseDown = false; + }; + + _engine.Comparer.MaxDifferencesThrow = _engine.CaptureRegion.Width * _engine.CaptureRegion.Height / 2; + } + + [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteDesktopSessionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStartRemoteDesktopSessionRequestReceived(StartRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + _clients.Remove(client); + } + + RemoteDesktopClient newClient = new RemoteDesktopClient(); + newClient.Receiver = receiver; + newClient.Token = token; + newClient.WebRtcClient = new WebRtcClient(); + newClient.WebRtcClient.TextMessageReceived += WebRtcClient_TextMessageReceived; + _clients.Add(newClient); + + await receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + { + FrameRate = _engine.FrameRate + }, token); + + + if (!_engine.IsStarted) + { + _engine.Start(); + } + + RaisePropertyChanged(nameof(InSession)); + } + + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcIceCandidateRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnWebRtcIceCandidateRequestReceived(WebRtcIceCandidateRequest request, String token, ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + try + { + await receiver.SendGenericResponse(new WebRtcIceCandidateResponse() { }, token); + client.WebRtcClient.AddIceCandidate(request.IceCandidate); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error adding WebRTC ice candidate received from the remote connection."); + } + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcOfferRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnWebRtcOfferRequestReceived(WebRtcOfferRequest request, String token, ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + try + { + + try + { + client.WebRtcClient.NewIceCandidate += async (x, e) => + { + try + { + await receiver.SendGenericRequest(new WebRtcIceCandidateRequest() { IceCandidate = e.IceCandidate }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending ice candidate to remote peer."); + } + }; + client.WebRtcClient.Ready += (x, e) => + { + client.IsWebRtcReady = true; + }; + client.WebRtcClient.Disconnected += (x, e) => + { + client.IsWebRtcReady = false; + }; + + client.WebRtcClient.FrameWidth = 800; + client.WebRtcClient.FrameHeight = 1280; + client.WebRtcClient.FrameRate = _engine.FrameRate; + + await client.WebRtcClient.Init(); + + var answer = await client.WebRtcClient.CreateAnswer(request.Offer); + await receiver.SendGenericResponse(new WebRtcOfferResponse() { Answer = answer }, token); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error initializing the WebRTC client."); + } + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Error responding to WebRTC offer request."); + } + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(StopRemoteDesktopSessionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStopRemoteDesktopSessionRequestReceived(StopRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + _clients.Remove(client); + + if (client.WebRtcClient != null) + { + client.WebRtcClient.Dispose(); + } + } + + if (_clients.Count == 0) + { + _engine.Stop(); + } + + await receiver.SendGenericResponse(new StopRemoteDesktopSessionResponse(), token); + + if (client != null) + { + await receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse(), client.Token, new TransportResponseConfig() { Completed = true }); + } + + RaisePropertyChanged(nameof(InSession)); + } + + [ExternalBridgeRequestHandlerMethod(typeof(MouseStateRequest))] + public async Task OnMouseStateRequestReceived(MouseStateRequest request, String token, ExternalBridgeReceiver receiver) + { + MouseController.SetCursorPosition((int)request.Location.X, (int)request.Location.Y); + + if (request.EventType == MouseEventType.Up || request.EventType == MouseEventType.Down) + { + MouseEventFlags flag = MouseEventFlags.LeftUp; + + switch (request.EventType) + { + case MouseEventType.Down: + flag = request.Button == MouseButton.Right ? MouseEventFlags.RightDown : MouseEventFlags.LeftDown; + break; + case MouseEventType.Up: + flag = request.Button == MouseButton.Right ? MouseEventFlags.RightUp : MouseEventFlags.LeftUp; + break; + } + + MouseController.MouseEvent(flag); + } + else if (request.EventType == MouseEventType.DoubleClick) + { + MouseController.DoubleClick(); + } + else if (request.EventType == MouseEventType.Scroll) + { + MouseController.Scroll(request.ScrollDelta); + } + + if (receiver != null) + { + await receiver.SendGenericResponse(new MouseStateResponse(), token); + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(TouchStateRequest))] + public async Task OnTouchStateRequestReceived(TouchStateRequest request, String token, ExternalBridgeReceiver receiver) + { + switch (request.EventType) + { + case TouchEventType.TouchDown: + TouchController.TouchDown((int)request.Location.X, (int)request.Location.Y); + break; + case TouchEventType.TouchMove: + TouchController.TouchMove(request.MoveDeltaX, request.MoveDeltaY); + break; + case TouchEventType.TouchUp: + TouchController.TouchUp(); + break; + } + + if (receiver != null) + { + await receiver.SendGenericResponse(new TouchStateResponse(), token); + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(KeyboardStateRequest))] + public async Task OnKeyboardStateRequestReceived(KeyboardStateRequest request, String token, ExternalBridgeReceiver receiver) + { + if (request.EventType == KeyboardEventType.Down) + { + KeyboardController.KeyDown(request.Key, request.IsCtrlDown, request.IsShiftDown, request.IsAltDown); + } + else + { + KeyboardController.KeyUp(request.Key, request.IsCtrlDown, request.IsShiftDown, request.IsAltDown); + } + + if (receiver != null) + { + await receiver.SendGenericResponse(new KeyboardStateResponse(), token); + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteDesktopCommandRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRemoteDesktopCommandRequest(RemoteDesktopCommandRequest request, String token, ExternalBridgeReceiver receiver) + { + switch (request.Command) + { + case RemoteDesktopCommand.HideAndOpenShell: + _osManager.OpenShell(); + _appManager.SetWindowState(System.Windows.WindowState.Minimized); + break; + } + + await receiver.SendGenericResponse(new RemoteDesktopCommandResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(SetCursorVisibilityRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnSetCursorVisibilityRequest(SetCursorVisibilityRequest request, String token, ExternalBridgeReceiver receiver) + { + _drawCursor = request.Visible; + await receiver.SendGenericResponse(new SetCursorVisibilityResponse(), token); + } + + [ExternalBridgeRequestHandlerMethod(typeof(GetScreenshotRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetScreenshotRequest(GetScreenshotRequest request, String token, ExternalBridgeReceiver receiver) + { + GdiScreenCapture capture = new GdiScreenCapture(); + var bitmap = capture.GetDesktopBitmap(CaptureRegion.PrimaryScreenBounds()); + RasterFrame frame = new RasterFrame(bitmap); + var data = frame.ToEncoder().ToArray(80); + frame.Dispose(); + + await receiver.SendGenericResponse(new GetScreenshotResponse() { Bitmap = data }, token); + } + + private async void _engine_FrameReceived(object sender, ScreenCaptureFrameReceivedEventArgs e) + { + try + { + if (_drawCursor) + { + e.Frame.DrawImage((_isMouseDown || _ensureMouseDown) ? Properties.Resources.tap : Properties.Resources.finger3, new System.Drawing.Point(System.Windows.Forms.Cursor.Position.X - 5, System.Windows.Forms.Cursor.Position.Y - 4)); + _ensureMouseDown = false; + } + + _initialPacket = new RemoteDesktopPacket() + { + Bitmap = e.Frame.ToEncoder().ToArray(), + }; + + if (_clients.Count > 0) + { + bool useWebRTC = _clients.ToList().All(x => x.IsWebRtcReady); + + if (useWebRTC) + { + _engine.EnableComparer = false; + + foreach (var client in _clients.ToList()) + { + try + { + client.WebRtcClient.PushFrame(e.Frame.ToBitmap()); + } + catch (Exception ex) + { + LogManager.Log(ex, LogCategory.Debug, "Error pushing remote desktop frame via WebRTC channel."); + } + } + + e.Frame.Dispose(); + } + else + { + _engine.EnableComparer = true; + + foreach (var client in _clients.ToList().Where(x => !x.InitialPacketSent)) + { + try + { + await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + { + Packet = _initialPacket, + }, client.Token, new TransportResponseConfig() + { + Immediate = false, + }); + + client.InitialPacketSent = true; + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + if (e.Frame.DifferenceCount > 0) + { + RemoteDesktopPacket packet = null; + + Point mousePosition = new Point(System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y); + + if (!e.Frame.DifferenceAvailable) + { + packet = new RemoteDesktopPacket() + { + Bitmap = e.Frame.ToEncoder().ToArray(30), + MousePosition = mousePosition, + CursorVisible = _drawCursor + }; + } + else + { + var diffFrame = e.Frame.ToDifference(); + diffFrame = diffFrame.OptimizeBounds(); + + packet = new RemoteDesktopPacket() + { + Bitmap = diffFrame.ToEncoder().ToArray(), + IsPartial = true, + PartialRegion = new CaptureRegion(diffFrame.Left, diffFrame.Top, diffFrame.Width, diffFrame.Height), + MousePosition = mousePosition, + CursorVisible = _drawCursor + }; + + diffFrame.Dispose(); + } + + Debug.WriteLine($"Remote Desktop Bitmap Size: {packet.Bitmap.Length / 1000} kb"); + + foreach (var client in _clients.ToList().Where(x => x.InitialPacketSent)) + { + try + { + await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + { + Packet = packet + }, client.Token, new TransportResponseConfig() + { + Immediate = false, + }); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred on remote desktop engine frame received event."); + } + finally + { + e.Frame.Dispose(); + } + } + + private async void WebRtcClient_TextMessageReceived(object sender, DataMessageReceivedEventArgs e) + { + try + { + var request = JsonConvert.DeserializeObject(e.Data, _jsonSettings); + + if (request.GetType() == typeof(MouseStateRequest)) + { + await OnMouseStateRequestReceived(request as MouseStateRequest, null, null); + } + else if (request.GetType() == typeof(KeyboardStateRequest)) + { + await OnKeyboardStateRequestReceived(request as KeyboardStateRequest, null, null); + } + else if (request.GetType() == typeof(TouchStateRequest)) + { + await OnTouchStateRequestReceived(request as TouchStateRequest, null, null); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error deserializing incoming message on the WebRTC data Channel."); + } + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + LogManager.Log("Remote desktop client disconnected. Disposing WebRTC channel..."); + + _clients.Remove(client); + + try + { + if (client.WebRtcClient != null) + { + client.WebRtcClient.Dispose(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disposing the WebRTC channel."); + } + } + + if (_clients.Count == 0) + { + _engine.Stop(); + } + + RaisePropertyChanged(nameof(InSession)); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs new file mode 100644 index 000000000..5e4a801d7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.RemoteDesktop +{ + /// + /// Represents a PPC remote desktop service. + /// + public interface IRemoteDesktopService : IPPCService + { + /// + /// Gets a value indicating whether the remote desktop service has started. + /// + bool IsStarted { get; } + + /// + /// Gets a value indicating whether there is any active remote desktop session with a remote peer. + /// + bool InSession { get; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs new file mode 100644 index 000000000..f0f0a87de --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.ExternalBridge; +using Tango.WebRTC; + +namespace Tango.PPC.Common.RemoteDesktop +{ + public class RemoteDesktopClient + { + public String Token { get; set; } + public ExternalBridgeReceiver Receiver { get; set; } + public bool InitialPacketSent { get; set; } + public WebRtcClient WebRtcClient { get; set; } + public bool IsWebRtcReady { get; set; } + } + +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/DefaultRemoteJobService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/DefaultRemoteJobService.cs new file mode 100644 index 000000000..8826a8be3 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/DefaultRemoteJobService.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Core; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.Integration.Operation; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Jobs; + +namespace Tango.PPC.Common.RemoteJob +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteJobService : IRemoteJobService, IExternalBridgeRequestHandler + { + private class RunningJobUpdateClient + { + public String Token { get; set; } + public ExternalBridgeReceiver Receiver { get; set; } + public bool JobSent { get; set; } + } + + private List _clients; + private JobHandler _handler; + private JobDTO _currentJobDTO; + private ProcessParametersTableDTO _currentJobProcessParameters; + + public bool Enabled { get; set; } = true; + + private IMachineProvider MachineProvider { get; set; } + + public DefaultRemoteJobService(IPPCExternalBridgeService externalBridge, IMachineProvider machineProvider) + { + externalBridge.RegisterRequestHandler(this); + + MachineProvider = machineProvider; + + _clients = new List(); + MachineProvider.MachineOperator.PrintingStarted += MachineOperator_PrintingStarted; + } + + private async void MachineOperator_PrintingStarted(object sender, Integration.Operation.PrintingEventArgs e) + { + _handler = e.JobHandler; + + e.JobHandler.StatusChanged += JobHandler_StatusChanged; + e.JobHandler.Stopped += JobHandler_Stopped; + + _currentJobDTO = JobDTO.FromObservable(e.Job); + _currentJobProcessParameters = ProcessParametersTableDTO.FromObservable(_handler.ProcessParameters); + + foreach (var client in _clients.ToList()) + { + try + { + RemoteJobProgress progress = new RemoteJobProgress(); + progress.Stage = RemoteJobStage.Started; + progress.JobStatus = _handler.JobStatus; + + await client.Receiver.SendGenericResponse(new RemoteJobUpdateResponse() + { + Job = _currentJobDTO, + ProcessParameters = _currentJobProcessParameters, + Progress = progress + }, client.Token); + + client.JobSent = true; + } + catch { } + } + } + + private async void JobHandler_StatusChanged(object sender, RunningJobStatus e) + { + foreach (var client in _clients.ToList()) + { + if (client.JobSent) + { + try + { + await client.Receiver.SendGenericResponse(new RemoteJobUpdateResponse() + { + Progress = GetJobProgress(_handler) + }, client.Token); + } + catch { } + } + else + { + try + { + RemoteJobProgress progress = new RemoteJobProgress(); + progress.Stage = RemoteJobStage.Started; + progress.JobStatus = _handler.JobStatus; + + await client.Receiver.SendGenericResponse(new RemoteJobUpdateResponse() + { + Job = _currentJobDTO, + ProcessParameters = _currentJobProcessParameters, + Progress = progress + }, client.Token); + + client.JobSent = true; + } + catch { } + } + } + } + + private async void JobHandler_Stopped(object sender, EventArgs e) + { + foreach (var client in _clients.ToList().Where(x => x.JobSent)) + { + try + { + await client.Receiver.SendGenericResponse(new RemoteJobUpdateResponse() + { + Progress = GetJobProgress(_handler), + }, client.Token); + + client.JobSent = false; + } + catch { } + } + } + + private RemoteJobProgress GetJobProgress(JobHandler handler) + { + RemoteJobStage stage = RemoteJobStage.Running; + + if (_handler.Status.IsCanceled) + { + stage = RemoteJobStage.Aborted; + } + else if (_handler.Status.IsCompleted) + { + stage = RemoteJobStage.Completed; + } + else if (_handler.Status.IsFailed) + { + stage = RemoteJobStage.Failed; + } + + return new RemoteJobProgress() + { + Stage = stage, + JobStatus = handler.JobStatus, + }; + } + + [ExternalBridgeRequestHandlerMethod(typeof(RemoteJobUpdateRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnRunningJobUpdateRequest(RemoteJobUpdateRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + if (!_clients.ToList().Exists(x => x.Receiver == receiver)) + { + _clients.Add(new RunningJobUpdateClient() + { + Receiver = receiver, + Token = token + }); + } + + await receiver.SendGenericResponse(new RemoteJobUpdateResponse(), token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + _clients.RemoveAll(x => x.Receiver == receiver); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/IRemoteJobService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/IRemoteJobService.cs new file mode 100644 index 000000000..e7bfdbec1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/IRemoteJobService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.ExternalBridge; + +namespace Tango.PPC.Common.RemoteJob +{ + public interface IRemoteJobService : IPPCService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Colors.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Colors.xaml index 03f4b6f36..5fdbcf5f8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Colors.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Colors.xaml @@ -2,6 +2,17 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Tango.PPC.Common.Resources"> + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml index 730066b46..09762d7ce 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml @@ -21,6 +21,9 @@ + + + @@ -51,6 +54,13 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.png b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.png new file mode 100644 index 000000000..c0a6ce9cd Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.png b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.png new file mode 100644 index 000000000..4fa679b81 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs new file mode 100644 index 000000000..e5ac43d3f --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.SQL; + +namespace Tango.PPC.Common.SQL +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteSqlService : IRemoteSqlService, IExternalBridgeRequestHandler + { + public bool Enabled { get; set; } = true; + + public DefaultRemoteSqlService(IPPCExternalBridgeService externalBridge) + { + externalBridge.RegisterRequestHandler(this); + } + + [ExternalBridgeRequestHandlerMethod(typeof(ExecuteSqlRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnExecuteSqlRequest(ExecuteSqlRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + RemoteSqlDataSet dataSet = new RemoteSqlDataSet(); + int affected = 0; + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + using (SqlConnection connection = new SqlConnection(db.Database.Connection.ConnectionString)) + { + SqlCommand command = new SqlCommand(request.SQL, connection); + connection.Open(); + + SqlDataReader reader = command.ExecuteReader(); + affected = reader.RecordsAffected; + + dataSet = await RemoteSqlDataSet.Load(reader); + } + } + + await receiver.SendGenericResponse(new ExecuteSqlResponse() + { + DataSet = dataSet, + AffectedRecords = affected + }, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs new file mode 100644 index 000000000..f70589090 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.SQL +{ + public interface IRemoteSqlService : IPPCService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SafetyLevelOperations.csv b/Software/Visual_Studio/PPC/Tango.PPC.Common/SafetyLevelOperations.csv new file mode 100644 index 000000000..e8fe002b6 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SafetyLevelOperations.csv @@ -0,0 +1,3 @@ +MessageType, +MotorHomingRequest, +MotorJoggingRequest \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/DefaultStorageProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/DefaultStorageProvider.cs index 46315e4b8..5f097d303 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/DefaultStorageProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/DefaultStorageProvider.cs @@ -21,7 +21,7 @@ namespace Tango.PPC.Common.Storage public class DefaultStorageProvider : ExtendedObject, IStorageProvider { private Thread _scanThread; - private Dictionary> _fileHandlers; + private Dictionary>> _fileHandlers; /// /// Occurs when a new storage drive has been inserted. @@ -58,7 +58,7 @@ namespace Tango.PPC.Common.Storage /// public DefaultStorageProvider(IPPCApplicationManager applicationManager) { - _fileHandlers = new Dictionary>(); + _fileHandlers = new Dictionary>>(); var drives = DriveInfo.GetDrives().Where(x => x.DriveType == DriveType.Removable).ToList(); if (drives.Count > 0) @@ -86,7 +86,7 @@ namespace Tango.PPC.Common.Storage /// The file extension. /// The handler. /// Cannot register multiple file handlers for the same extension. - public void RegisterFileHandler(string extension, Action handler) + public void RegisterFileHandler(string extension, Action> handler) { if (_fileHandlers.ContainsKey(extension)) { @@ -99,7 +99,7 @@ namespace Tango.PPC.Common.Storage /// Unregisters the file handler. /// /// The handler. - public void UnregisterFileHandler(Action handler) + public void UnregisterFileHandler(Action> handler) { var h = _fileHandlers.SingleOrDefault(x => x.Value == handler); @@ -112,14 +112,17 @@ namespace Tango.PPC.Common.Storage /// /// Submits a file selection. /// - /// The file item. - public void SubmitFileSelection(ExplorerFileItem fileItem) + /// The file item. + public void SubmitFileSelection(List fileItems) { - String extension = Path.GetExtension(fileItem.Path); - - if (_fileHandlers.ContainsKey(extension)) + if (fileItems != null && fileItems.Count > 0) { - _fileHandlers[extension].Invoke(fileItem); + String extension = Path.GetExtension(fileItems.First().Path); + + if (_fileHandlers.ContainsKey(extension)) + { + _fileHandlers[extension].Invoke(fileItems); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/IStorageProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/IStorageProvider.cs index 902021002..2a9cf4e90 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/IStorageProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/IStorageProvider.cs @@ -38,18 +38,18 @@ namespace Tango.PPC.Common.Storage /// /// The file extension. /// The handler. - void RegisterFileHandler(String extension, Action handler); + void RegisterFileHandler(String extension, Action> handler); /// /// Unregisters the file handler. /// /// The handler. - void UnregisterFileHandler(Action handler); + void UnregisterFileHandler(Action> handler); /// /// Submits a file selection. /// /// The file item. - void SubmitFileSelection(ExplorerFileItem fileItem); + void SubmitFileSelection(List fileItems); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/DefaultMachineDataSynchronizer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/DefaultMachineDataSynchronizer.cs new file mode 100644 index 000000000..5a951e9fa --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/DefaultMachineDataSynchronizer.cs @@ -0,0 +1,662 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using Tango.BL; +using Tango.PPC.Common.Web; +using System.Data.Entity; +using Tango.BL.DTO; +using Tango.PPC.Common.Connection; +using Tango.BL.Builders; +using Tango.Settings; +using Tango.Core; +using Tango.PPC.Common.Authentication; +using Tango.Logging; +using System.Diagnostics; +using Tango.BL.Enumerations; +using Tango.PPC.Common.Application; +using Tango.Core.DI; + +namespace Tango.PPC.Common.Synchronization +{ + public class DefaultMachineDataSynchronizer : ExtendedObject, IMachineDataSynchronizer + { + private Timer _synchTimer; + private PPCWebClient client; + private IMachineProvider _machineProvider; + private IAuthenticationProvider _authenticationProvider; + private List _logs; + private bool _synchronizedOnce; + + [TangoInject(TangoInjectMode.WhenAvailable)] + private IPPCApplicationManager _appManager; + + public event EventHandler CurrentStatusChanged; + public event EventHandler SynchronizationStarted; + public event EventHandler SynchronizationEnded; + + public int MaxJobs { get; set; } + public int MaxJobRuns { get; set; } + public int MaxMachinesEvents { get; set; } + public int MaxOfflineUpdates { get; set; } + public int MaxDataStoreItems { get; set; } + + private SynchronizationStatus _currentStatus; + public SynchronizationStatus CurrentStatus + { + get { return _currentStatus; } + private set { _currentStatus = value; RaisePropertyChangedAuto(); } + } + + private SynchronizationStatus _lastStatus; + public SynchronizationStatus LastStatus + { + get { return _lastStatus; } + private set { _lastStatus = value; RaisePropertyChangedAuto(); } + } + + public SynchronizedObservableCollection StatusHistory { get; private set; } + + public TimeSpan Interval { get; set; } + + private bool _isEnabled; + public bool IsEnabled + { + get { return _isEnabled; } + set { _isEnabled = value; OnEnableChanged(); RaisePropertyChangedAuto(); } + } + + private bool _isSynchronizing; + public bool IsSynchronizing + { + get { return _isSynchronizing; } + set { _isSynchronizing = value; RaisePropertyChangedAuto(); } + } + + public DefaultMachineDataSynchronizer() + { + StatusHistory = new SynchronizedObservableCollection(); + + MaxJobs = 10; + MaxJobRuns = 10; + MaxMachinesEvents = 10; + MaxOfflineUpdates = 10; + MaxDataStoreItems = 100; + + var settings = SettingsManager.Default.GetOrCreate(); + Interval = settings.SynchronizationInterval; + + _synchTimer = new Timer(Interval.TotalMilliseconds); + _synchTimer.Elapsed += _synchTimer_Elapsed; + _synchTimer.Enabled = true; + + ExecuteNewStatus(TimeSpan.FromMinutes(2)); + LastStatus = CurrentStatus; + } + + public DefaultMachineDataSynchronizer(PPCWebClient ppcWebClient, IMachineProvider machineProvider, IAuthenticationProvider authenticationProvider) : this() + { + _logs = new List(); + _machineProvider = machineProvider; + client = new PPCWebClient(ppcWebClient, TimeSpan.FromMinutes(10)); + _authenticationProvider = authenticationProvider; + + LogManager.NewLog += LogManager_NewLog; + } + + private void LogManager_NewLog(object sender, LogItemBase e) + { + if (IsSynchronizing) + { + _logs.Add(e); + } + } + + private String GetLogsStringAndClear() + { + String logsString = String.Join(Environment.NewLine, _logs.ToList().Select(x => x.ToString())); + _logs.Clear(); + return logsString; + } + + private void OnEnableChanged() + { + _synchTimer.Interval = Interval.TotalMilliseconds; + + if (IsEnabled) + { + CurrentStatus.State = SynchronizationState.Pending; + } + else + { + CurrentStatus.State = SynchronizationState.Disabled; + } + } + + private void _synchTimer_Elapsed(object sender, ElapsedEventArgs e) + { + _synchTimer.Interval = Interval.TotalMilliseconds; + + try + { + Synchronize().GetAwaiter().GetResult(); + } + catch { } + } + + private async Task CreateUploadMachineDataRequest(bool syncJobs, bool syncDiagnostics) + { + UploadMachineDataRequest request = new UploadMachineDataRequest(); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + if (syncJobs) + { + LogManager.Log("Checking Jobs..."); + + var jobs = await new JobsCollectionBuilder(db).Set(x => !x.IsSynchronized).WithSegments().WithBrushStops().Query(x => x.Take(MaxJobs).OrderByDescending(z => z.LastUpdated)).BuildListAsync(); + List dtos = new List(); + + foreach (var job in jobs) + { + var dto = JobDTO.FromObservable(job); + request.Jobs.Add(dto); + } + } + + if (syncDiagnostics) + { + LogManager.Log("Checking Job Runs..."); + + var jobRuns = await db.JobRuns.Where(x => !x.IsSynchronized).Take(MaxJobRuns).OrderByDescending(x => x.LastUpdated).ToListAsync(); + List dtos = new List(); + + foreach (var jobRun in jobRuns) + { + var dto = JobRunDTO.FromObservable(jobRun); + request.JobRuns.Add(dto); + } + } + + if (syncDiagnostics) + { + LogManager.Log("Checking Events..."); + + var machineEvents = await db.MachinesEvents.Where(x => !x.IsSynchronized).Take(MaxMachinesEvents).OrderByDescending(x => x.LastUpdated).ToListAsync(); + List dtos = new List(); + + foreach (var machineEvent in machineEvents) + { + machineEvent.IsSynchronized = true; + var dto = MachinesEventDTO.FromObservable(machineEvent); + request.MachineEvents.Add(dto); + } + } + + if (syncDiagnostics) + { + LogManager.Log("Checking Offline Updates..."); + + var tangoUpdates = await db.TangoUpdates.Where(x => !x.IsSynchronized && (x.Status == (int)TangoUpdateStatuses.OfflineUpdateCompleted || x.Status == (int)TangoUpdateStatuses.OfflineUpdateFailed || x.Status == (int)TangoUpdateStatuses.OfflineFirmwareUpgradeCompleted || x.Status == (int)TangoUpdateStatuses.OfflineFirmwareUpgradeFailed)).Take(MaxOfflineUpdates).OrderByDescending(x => x.LastUpdated).ToListAsync(); + List dtos = new List(); + + foreach (var tangoUpdate in tangoUpdates) + { + tangoUpdate.IsSynchronized = true; + var dto = TangoUpdateDTO.FromObservable(tangoUpdate); + request.OfflineUpdates.Add(dto); + } + } + + { //Always synchronize data store items + LogManager.Log("Checking Data Store Items..."); + + var dataStoreItems = await db.DataStoreItems.Where(x => !x.IsSynchronized).Take(MaxDataStoreItems).ToListAsync(); + List dtos = new List(); + + foreach (var item in dataStoreItems) + { + item.IsSynchronized = true; + var dto = DataStoreItemDTO.FromObservable(item); + dto.MachineGuid = null; + request.DataStoreItems.Add(dto); + } + } + } + + return request; + } + + private async Task FinalizeMachineDataUpload(UploadMachineDataRequest request, UploadMachineDataResponse response) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + //Finalize jobs + foreach (var job in request.Jobs) + { + var failedJob = response.FailedJobs.SingleOrDefault(x => x.Guid == job.Guid); + + if (failedJob == null) + { + var dbJob = await db.Jobs.SingleOrDefaultAsync(x => x.Guid == job.Guid); + dbJob.IsSynchronized = true; + } + else + { + LogManager.Log($"Synchronization Error - Job '{job.Name}' cannot be stored on the server due to the following reason:\n{failedJob.Reason}", LogCategory.Error); + } + } + + //Finalize job runs + foreach (var jobRun in request.JobRuns) + { + var failedJobRun = response.FailedJobRuns.SingleOrDefault(x => x.Guid == jobRun.Guid); + + if (failedJobRun == null) + { + var dbJobRun = await db.JobRuns.SingleOrDefaultAsync(x => x.Guid == jobRun.Guid); + dbJobRun.IsSynchronized = true; + } + else + { + LogManager.Log($"Synchronization Error - JobRun '{jobRun.ID}' cannot be stored on the server due to the following reason:\n{failedJobRun.Reason}", LogCategory.Error); + } + } + + //Finalize machine events + foreach (var machineEvent in request.MachineEvents) + { + var failedMachineEvent = response.FailedMachineEvents.SingleOrDefault(x => x.Guid == machineEvent.Guid); + + if (failedMachineEvent == null) + { + var dbMachineEvent = await db.MachinesEvents.SingleOrDefaultAsync(x => x.Guid == machineEvent.Guid); + dbMachineEvent.IsSynchronized = true; + } + else + { + LogManager.Log($"Synchronization Error - Event '{machineEvent.ID}' cannot be stored on the server due to the following reason:\n{failedMachineEvent.Reason}", LogCategory.Error); + } + } + + //Finalize tango updates + foreach (var tangoUpdate in request.OfflineUpdates) + { + var failedTangoUpdate = response.FailedOfflineUpdates.SingleOrDefault(x => x.Guid == tangoUpdate.Guid); + + if (failedTangoUpdate == null) + { + var dbTangoUpdate = await db.TangoUpdates.SingleOrDefaultAsync(x => x.Guid == tangoUpdate.Guid); + dbTangoUpdate.IsSynchronized = true; + } + else + { + LogManager.Log($"Synchronization Error - TangoUpdate '{tangoUpdate.ID}' cannot be stored on the server due to the following reason:\n{failedTangoUpdate.Reason}", LogCategory.Error); + } + } + + //Finalize data store items + foreach (var dataStoreItem in request.DataStoreItems) + { + var failedDataStoreItem = response.FailedDataStoreItems.SingleOrDefault(x => x.Guid == dataStoreItem.Guid); + + if (failedDataStoreItem == null) + { + var dbDataStoreItem = await db.DataStoreItems.SingleOrDefaultAsync(x => x.Guid == dataStoreItem.Guid); + dbDataStoreItem.IsSynchronized = true; + } + else + { + LogManager.Log($"Synchronization Error - DataStoreItem '{dataStoreItem.Key}' cannot be stored on the server due to the following reason:\n{failedDataStoreItem.Reason}", LogCategory.Error); + } + } + + await db.SaveChangesAsync(); + } + } + + private async Task DownloadMachineData(bool syncJobs, bool syncDiagnostics) + { + return await client.DownloadMachineData(new DownloadMachineDataRequest() + { + RequestJobs = syncJobs, + RequestJobRuns = syncDiagnostics, + RequestMachineEvents = syncDiagnostics, + RequestDataStoreItems = true, + MaxJobs = MaxJobs, + MaxJobRuns = MaxJobRuns, + MaxMachinesEvents = MaxMachinesEvents, + MaxDataStoreItems = MaxDataStoreItems, + }); + } + + private async Task InsertReplaceMachineData(DownloadMachineDataResponse response) + { + NotifyMachineDataDownloadCompletedRequest request = new NotifyMachineDataDownloadCompletedRequest(); + + //Insert/Replace Jobs. + if (response.Jobs.Count > 0) + { + LogManager.Log("Inserting/Replacing Jobs..."); + } + foreach (var dto in response.Jobs) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + try + { + var job = dto.ToObservable(); + + job.ID = 0; + job.UserGuid = null; + job.CustomerGuid = null; + job.IsSynchronized = true; + + var existingJob = await db.Jobs.SingleOrDefaultAsync(x => x.Guid == job.Guid); + + if (existingJob == null) + { + db.Jobs.Add(job); + await db.SaveChangesAsync(); + } + else if (job.LastUpdated > existingJob.LastUpdated) + { + existingJob.Delete(db); + db.Jobs.Add(job); + await db.SaveChangesAsync(); + } + + request.SynchronizedJobs.Add(job.Guid); + } + catch (Exception ex) + { + LogManager.Log($"Synchronization Error - Job '{dto.Name}' cannot be stored locally due to the following reason:\n{ex.FlattenMessage()}", LogCategory.Error); + } + } + } + + //Insert/Update Data Store Items. + if (response.DataStoreItems.Count > 0) + { + LogManager.Log("Inserting/Updating Data Store Items..."); + } + foreach (var dto in response.DataStoreItems) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + try + { + var dataStoreItem = dto.ToObservable(); + + dataStoreItem.ID = 0; + dataStoreItem.MachineGuid = null; + dataStoreItem.IsSynchronized = true; + + var existingItem = db.DataStoreItems.SingleOrDefault(x => x.Guid == dataStoreItem.Guid); + + if (existingItem == null) + { + db.DataStoreItems.Add(dataStoreItem); + db.SaveChanges(); + } + else if (dataStoreItem.LastUpdated >= existingItem.LastUpdated) + { + existingItem.DataType = dataStoreItem.DataType; + existingItem.Value = dataStoreItem.Value; + existingItem.IsSynchronized = true; + existingItem.LastUpdated = dataStoreItem.LastUpdated; + db.SaveChanges(); + } + + request.SynchronizedDataStoreItems.Add(dataStoreItem.Guid); + } + catch (Exception ex) + { + LogManager.Log($"Synchronization Error - DataStoreItem '{dto.Key}' cannot be stored locally due to the following reason:\n{ex.FlattenMessage()}", LogCategory.Error); + } + } + } + + //Insert JobRuns. + if (response.JobRuns.Count > 0) + { + LogManager.Log("Inserting/Replacing Job Runs..."); + } + foreach (var dto in response.JobRuns) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + try + { + var run = dto.ToObservable(); + run.ID = 0; + run.IsSynchronized = true; + + if (await db.JobRuns.SingleOrDefaultAsync(x => x.Guid == run.Guid) == null) + { + db.JobRuns.Add(run); + await db.SaveChangesAsync(); + } + + request.SynchronizedJobRuns.Add(run.Guid); + } + catch (Exception ex) + { + LogManager.Log($"Synchronization Error - JobRun '{dto.ID}' cannot be stored locally due to the following reason:\n{ex.FlattenMessage()}", LogCategory.Error); + } + } + } + + //Insert MachineEvents. + if (response.MachineEvents.Count > 0) + { + LogManager.Log("Inserting/Replacing Events..."); + } + foreach (var dto in response.MachineEvents) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + try + { + var ev = dto.ToObservable(); + ev.ID = 0; + ev.UserGuid = null; + ev.IsSynchronized = true; + + if (await db.MachinesEvents.SingleOrDefaultAsync(x => x.Guid == ev.Guid) == null) + { + db.MachinesEvents.Add(ev); + await db.SaveChangesAsync(); + } + + request.SynchronizedMachineEvents.Add(ev.Guid); + } + catch (Exception ex) + { + LogManager.Log($"Synchronization Error - Event '{dto.ID}' cannot be stored locally due to the following reason:\n{ex.FlattenMessage()}", LogCategory.Error); + } + } + } + + return request; + } + + public async Task Synchronize() + { + _synchronizedOnce = true; + + if (!IsEnabled || IsSynchronizing) return; + + var settings = SettingsManager.Default.GetOrCreate(); + + var syncJobs = settings.SynchronizeJobs; + var syncDiagnostics = settings.SynchronizeDiagnostics; + + IsSynchronizing = true; + SynchronizationStarted?.Invoke(this, new EventArgs()); + + _logs.Clear(); + + _synchTimer.Stop(); + + LogManager.Log("Starting machine data synchronization..."); + LogManager.Log($"Synchronization interval: {Interval}."); + + CurrentStatus.StartDateTime = DateTime.Now; + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Starting synchronization..."); + + Stopwatch watch = new Stopwatch(); + watch.Start(); + + String notifyToken = null; + + int newChangedJobs = 0; + int newJobRuns = 0; + int newMachineEvents = 0; + + try + { + LogManager.Log("Authenticating with machine service..."); + + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Authenticating with machine service..."); + + if (!this.client.IsAuthenticated) + { + await this.client.Login(new LoginRequest() + { + Mode = LoginMode.Machine, + MachineGuid = _machineProvider.Machine.Guid, + }); + } + + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Preparing machine data for upload..."); + LogManager.Log("Preparing machine data for upload..."); + var request = await CreateUploadMachineDataRequest(syncJobs, syncDiagnostics); + request.ApplicationVersion = _appManager.Version.ToString(); + request.FirmwareVersion = _appManager.FirmwareVersion.ToString(); + + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Uploading machine data..."); + LogManager.Log($"Uploading machine data:\nJobs: {request.Jobs.Count}\nJob Runs: {request.JobRuns.Count}\nEvents: {request.MachineEvents.Count}\nOffline Updates: {request.OfflineUpdates.Count}"); + var response = await this.client.UploadMachineData(request); + notifyToken = response.NotifyCompletedToken; + LogManager.Log($"Upload response received:\nFailed Jobs: {response.FailedJobs.Count}\nFailed Job Runs: {response.FailedJobRuns.Count}\nFailed Events: {response.FailedMachineEvents.Count}\nFailed Offline Updates: {response.FailedOfflineUpdates.Count}"); + LogManager.Log("Finalizing upload..."); + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Finalizing upload..."); + await FinalizeMachineDataUpload(request, response); + + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Downloading machine data from service..."); + LogManager.Log("Downloading machine data from server..."); + var downloadResponse = await DownloadMachineData(syncJobs, syncDiagnostics); + + newChangedJobs = downloadResponse.Jobs.Count; + newJobRuns = downloadResponse.JobRuns.Count; + newMachineEvents = downloadResponse.MachineEvents.Count; + + LogManager.Log($"Download response received:\nJobs: {downloadResponse.Jobs.Count}\nJob Runs: {downloadResponse.JobRuns.Count}\nEvents: {downloadResponse.MachineEvents.Count}"); + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Updating local database..."); + LogManager.Log("Updating local database..."); + var notifyRequest = await InsertReplaceMachineData(downloadResponse); + LogManager.Log($"Finalizing download:\nSynchronized Jobs: {notifyRequest.SynchronizedJobs.Count}\nSynchronized Job Runs: {notifyRequest.SynchronizedJobRuns.Count}\nSynchronized Events: {notifyRequest.SynchronizedMachineEvents.Count}"); + UpdateCurrentStatus(SynchronizationState.Synchronizing, "Finalizing download..."); + var notifyResponse = await this.client.NotifyMachineDataDownloadCompleted(notifyRequest); + + if (notifyToken != null) + { + try + { + await client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = notifyToken, + Status = TangoUpdateStatuses.SynchronizationCompleted, + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Synchronization completed successfully but an error occurred when trying to notify about the completion."); + } + } + + LogManager.Log("Machine data synchronization completed successfully."); + UpdateCurrentStatus(SynchronizationState.Completed, "Synchronization completed successfully.", null, watch.Elapsed); + } + catch (Exception ex) + { + if (notifyToken != null) + { + try + { + await client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + { + Token = notifyToken, + Status = TangoUpdateStatuses.SynchronizationFailed, + FailedReason = ex.FlattenMessage(), + FailedLog = GetLogsStringAndClear(), + }); + } + catch (Exception ee) + { + LogManager.Log(ee, "Synchronization completed successfully but an error occurred when trying to notify about the completion."); + } + } + + UpdateCurrentStatus(SynchronizationState.Failed, "Synchronization failed.", ex.FlattenMessage(), watch.Elapsed); + throw LogManager.Log(ex, "Error occurred while synchronizing machine data."); + } + finally + { + watch.Stop(); + LogManager.Log($"Synchronization duration: {watch.Elapsed}."); + LastStatus = CurrentStatus; + CreateNewStatus(); + IsSynchronizing = false; + SynchronizationEnded?.Invoke(this, new SynchronizationEndedEventArgs() + { + NewChangedJobs = newChangedJobs, + NewJobRuns = newJobRuns, + NewMachineEvents = newMachineEvents, + }); + } + + _synchTimer.Start(); + } + + private void CreateNewStatus() + { + CurrentStatus = new SynchronizationStatus(); + CurrentStatus.State = SynchronizationState.Pending; + CurrentStatus.StartDateTime = DateTime.Now.Add(Interval); + StatusHistory.Insert(0, CurrentStatus); + } + + private async void ExecuteNewStatus(TimeSpan delay) + { + CurrentStatus = new SynchronizationStatus(); + CurrentStatus.State = SynchronizationState.Pending; + CurrentStatus.StartDateTime = DateTime.Now.Add(delay); + StatusHistory.Insert(0, CurrentStatus); + await Task.Delay(delay); + try + { + if (!_synchronizedOnce) + { + await Synchronize(); + } + } + catch { } + } + + private void UpdateCurrentStatus(SynchronizationState state, String message, String errorReason = null, TimeSpan? duration = null) + { + CurrentStatus.State = state; + CurrentStatus.Message = message; + CurrentStatus.ErrorReason = errorReason; + CurrentStatus.Duration = duration; + CurrentStatusChanged?.Invoke(this, new SynchronizationStatusChangedEventArgs() + { + Status = CurrentStatus, + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/IMachineDataSynchronizer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/IMachineDataSynchronizer.cs new file mode 100644 index 000000000..bfd527a05 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/IMachineDataSynchronizer.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Common.Synchronization +{ + public interface IMachineDataSynchronizer + { + event EventHandler SynchronizationStarted; + event EventHandler SynchronizationEnded; + event EventHandler CurrentStatusChanged; + int MaxJobs { get; set; } + int MaxJobRuns { get; set; } + int MaxMachinesEvents { get; set; } + SynchronizationStatus CurrentStatus { get; } + SynchronizationStatus LastStatus { get; } + SynchronizedObservableCollection StatusHistory { get; } + TimeSpan Interval { get; set; } + bool IsEnabled { get; set; } + bool IsSynchronizing { get; } + Task Synchronize(); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationEndedEventArgs.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationEndedEventArgs.cs new file mode 100644 index 000000000..4b8040e95 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationEndedEventArgs.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Synchronization +{ + public class SynchronizationEndedEventArgs : EventArgs + { + public int NewChangedJobs { get; set; } + public int NewJobRuns { get; set; } + public int NewMachineEvents { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationState.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationState.cs new file mode 100644 index 000000000..5797f449f --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationState.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Synchronization +{ + public enum SynchronizationState + { + [Description("Pending...")] + Pending, + [Description("Synchronizing...")] + Synchronizing, + [Description("Failed")] + Failed, + [Description("Completed")] + Completed, + [Description("Disabled")] + Disabled + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatus.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatus.cs new file mode 100644 index 000000000..5b1d5d1d2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatus.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Common.Synchronization +{ + public class SynchronizationStatus : ExtendedObject + { + private SynchronizationState _state; + public SynchronizationState State + { + get { return _state; } + set { _state = value; RaisePropertyChangedAuto(); } + } + + private String _message; + public String Message + { + get { return _message; } + set { _message = value; RaisePropertyChangedAuto(); } + } + + private String _errorReason; + public String ErrorReason + { + get { return _errorReason; } + set { _errorReason = value; RaisePropertyChangedAuto(); } + } + + private TimeSpan? _duration; + public TimeSpan? Duration + { + get { return _duration; } + set { _duration = value; RaisePropertyChangedAuto(); } + } + + private DateTime _startDateTime; + public DateTime StartDateTime + { + get { return _startDateTime; } + set { _startDateTime = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatusChangedEventArgs.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatusChangedEventArgs.cs new file mode 100644 index 000000000..1f0a9a27f --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatusChangedEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Synchronization +{ + public class SynchronizationStatusChangedEventArgs : EventArgs + { + public SynchronizationStatus Status { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs new file mode 100644 index 000000000..0c818483c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs @@ -0,0 +1,138 @@ +using Microsoft.WindowsAPICodePack.Net; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.Connectivity; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.Information; +using Tango.Settings; +using Tango.SystemInfo; + +namespace Tango.PPC.Common.SystemInfo +{ + [TangoCreateWhenRegistered] + public class DefaultSystemInfoService : ExtendedObject, ISystemInfoService, IExternalBridgeRequestHandler + { + public bool Enabled { get; set; } = true; + + private List _baseSystemInfo; + private IPPCApplicationManager _applicationManager; + private IConnectivityProvider _connectivityProvider; + + public DefaultSystemInfoService(IPPCExternalBridgeService externalBridge, IPPCApplicationManager applicationManager, IConnectivityProvider connectivityProvider) + { + _applicationManager = applicationManager; + _connectivityProvider = connectivityProvider; + externalBridge.RegisterRequestHandler(this); + } + + [ExternalBridgeRequestHandlerMethod(typeof(GetMachineInformationRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnGetMachineInformationRequest(GetMachineInformationRequest request, String token, ExternalBridgeReceiver receiver) + { + if (_baseSystemInfo == null) //Create hardware info just once. + { + _baseSystemInfo = new List(); + + if (!Debugger.IsAttached) + { + _baseSystemInfo = SystemObjectsCollection.Create(); + } + } + + //Now always update the latest custom objects.. + var system = _baseSystemInfo.ToList(); + + //Get the networks that are currently connected to + var connectedNetwork = NetworkListManager.GetNetworks(NetworkConnectivityLevels.Connected).FirstOrDefault(); + + var settings = SettingsManager.Default.GetOrCreate(); + + var applicationCollection = new SystemObjectsCollection(); + applicationCollection.Name = "Application"; + system.Insert(0, applicationCollection); + + //Application. + applicationCollection.Objects.Add(new SystemObject() + { + Name = "Tango PPC", + Properties = new List() + { + new SystemObjectProperty() { Name = "Version", Value = _applicationManager.Version.ToString(3) }, + new SystemObjectProperty() { Name = "Build Date", Value = _applicationManager.BuildDate }, + new SystemObjectProperty() { Name = "Previous Version", Value = settings.PreviousApplicationVersion }, + new SystemObjectProperty() { Name = "Firmware Version", Value = _applicationManager.FirmwareVersion.ToStringSafe() }, + new SystemObjectProperty() { Name = "Technician Mode", Value = _applicationManager.IsInTechnicianMode.ToStringYesNo() }, + new SystemObjectProperty() { Name = "After Update", Value = _applicationManager.IsAfterUpdate.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Startup Date", Value = _applicationManager.StartUpDate.ToString() }, + }, + }); + + + //Network. + if (connectedNetwork != null) + { + applicationCollection.Objects.Add(new SystemObject() + { + Name = "Network", + Properties = new List() + { + new SystemObjectProperty() { Name = "Network Name", Value = connectedNetwork.Name }, + new SystemObjectProperty() { Name = "Category", Value = connectedNetwork.Category.ToString() }, + new SystemObjectProperty() { Name = "Type", Value = connectedNetwork.Connectivity.ToString() }, + new SystemObjectProperty() { Name = "Domain", Value = connectedNetwork.DomainType.ToString() }, + new SystemObjectProperty() { Name = "Connected Time", Value = connectedNetwork.ConnectedTime.ToString() }, + new SystemObjectProperty() { Name = "Internet Connection", Value = connectedNetwork.IsConnectedToInternet.ToStringYesNo() }, + }, + }); + } + + //Settings. + applicationCollection.Objects.Add(new SystemObject() + { + Name = "Settings", + Properties = new List() + { + new SystemObjectProperty() { Name = "Application State", Value = settings.ApplicationState.ToString() }, + new SystemObjectProperty() { Name = "Auto Update Check", Value = settings.AutoCheckForUpdates.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Auto Update Interval", Value = settings.AutoUpdateCheckInterval.ToString() }, + new SystemObjectProperty() { Name = "Automatic Thread Loading", Value = settings.EnableAutomaticThreadLoading.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Firmware Logs Enabled", Value = settings.EnableEmbeddedDebugLogs.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Emergency Switch Enabled", Value = settings.EnableEmergencyNotifications.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Liquid Quantity Validation Enabled", Value = settings.EnableJobLiquidQuantityValidation.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Remote Assistance Enabled", Value = settings.EnableRemoteAssistance.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Remote Desktop Enabled", Value = settings.EnableRemoteDesktop.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Start in Technician Mode", Value = settings.EnableTechnicianModeByDefault.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Watchdog Enabled", Value = settings.EnableWatchDog.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Job Units Method", Value = settings.JobUnitsMethod.ToString() }, + new SystemObjectProperty() { Name = "PowerUp Screen Enabled", Value = settings.DisplayPowerUpScreen.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Firmware COM Port", Value = settings.EmbeddedComPort.ToStringOrEmpty() }, + new SystemObjectProperty() { Name = "Emergency COM Port", Value = settings.EmergencyComPort.ToStringOrEmpty() }, + new SystemObjectProperty() { Name = "Job Upload Method", Value = settings.JobUploadStrategy.ToString() }, + new SystemObjectProperty() { Name = "Diagnostics Synchronization", Value = settings.SynchronizeDiagnostics.ToStringYesNo() }, + new SystemObjectProperty() { Name = "Jobs Synchronization", Value = settings.SynchronizeJobs.ToStringYesNo() }, + new SystemObjectProperty() { Name = "TCP Write Mode", Value = settings.TcpTransportAdapterWriteMode.ToString() }, + }.OrderBy(x => x.Name).ToList(), + }); + + await receiver.SendGenericResponse(new GetMachineInformationResponse() + { + Package = new InformationPackage() + { + System = system, + } + }, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs new file mode 100644 index 000000000..47ea7bd4b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.SystemInfo +{ + /// + /// Represents a PPC system information service. + /// + /// + public interface ISystemInfoService : IPPCService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index d130a8002..9d39c96d9 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -72,6 +72,10 @@ + + + ..\..\packages\Microsoft.WindowsAPICodePack-Core.1.1.0.0\lib\Microsoft.WindowsAPICodePack.dll + ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll @@ -120,7 +124,15 @@ GlobalVersionInfo.cs - + + + + + + + + + @@ -131,23 +143,66 @@ + + + TwineCatalogControl.xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -158,12 +213,16 @@ + + + + @@ -171,9 +230,9 @@ + - @@ -205,8 +264,13 @@ + + + + + @@ -217,6 +281,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -293,8 +361,29 @@ SettingsSingleFileGenerator Settings.Designer.cs + + + {ee088ff7-04d1-41fb-9d6a-cedeee7a7b9c} + Tango.DataStore.Editing + + + {88d9906b-8fc4-4fe0-b7eb-127a0a8fcee4} + Tango.DataStore.EF + + + {fa96bc0c-4055-475c-9dcc-70a5a9436b10} + Tango.DataStore.Lite + + + {29448f3c-9b3e-4da6-8555-46a8b9a6b3aa} + Tango.DataStore.Remote + + + {e0364dfa-0721-4637-9d32-9d22aac109d6} + Tango.DataStore + {c5df1816-34e5-4700-824c-29623a1baa22} Tango.AdvancedInstaller @@ -307,10 +396,18 @@ {b4fe6485-4161-4b36-bc08-67e0b53d01b7} Tango.ColorConversion + + {199e8359-cad3-433d-9eed-2027652b24a4} + Tango.Console + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {58e8825f-0c96-449c-b320-1e82b0aa876b} + Tango.CSV + {63561e19-ff5a-414b-a5ef-e30711543e1d} Tango.Emulations @@ -319,6 +416,18 @@ {4399AF76-DB52-4CFB-8020-6F85BDB29FD5} Tango.Explorer + + {c6ebbbbe-2123-44dc-aef7-a0d47d736ac0} + Tango.FileSystem + + + {99081c0e-065c-4d68-bf60-f82330cca02d} + Tango.Git + + + {4a55c185-3f8d-41b0-8815-c15f6213a14a} + Tango.Insights + {4206ac58-3b57-4699-8835-90bf6db01a61} Tango.Integration @@ -331,6 +440,10 @@ {e4927038-348d-4295-aaf4-861c58cb3943} Tango.PMR + + {a78068d4-2061-4376-8ede-583d8d880dec} + Tango.RemoteDesktop + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} Tango.Settings @@ -343,6 +456,10 @@ {e1e66ed9-597d-45fa-8048-de90a6930484} Tango.SQLExaminer + + {997a961c-beda-4b56-aa0f-c39e532f7ffa} + Tango.SystemInfo + {fd86424c-6e84-491b-8df9-3d0f5c236a2a} Tango.Touch @@ -351,6 +468,10 @@ {74e700b0-1156-4126-be40-ee450d3c3026} Tango.Transport + + {09f81a12-0f77-4336-854d-9e0a74a17f9e} + Tango.WebRTC + {5001990f-977b-48ff-b217-0236a5022ad8} Tango.Web @@ -359,6 +480,10 @@ {6aa425c9-ea6a-4b01-aaed-5ff122e8b663} Tango.WiFi + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + @@ -375,6 +500,16 @@ + + + + + + + + + + @@ -385,7 +520,7 @@ - + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/ThreadLoading/IThreadLoadingService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/ThreadLoading/IThreadLoadingService.cs new file mode 100644 index 000000000..0394a17c2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/ThreadLoading/IThreadLoadingService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.ThreadLoading +{ + public interface IThreadLoadingService + { + void StartThreadLoadingWizard(); + void StartThreadBreakWizard(); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/AlternativeUnifiedWriteFilterManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/AlternativeUnifiedWriteFilterManager.cs index 5fb74b2fe..ea57ca0d8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/AlternativeUnifiedWriteFilterManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/AlternativeUnifiedWriteFilterManager.cs @@ -4,19 +4,15 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using Tango.Core; using Tango.Core.Components; namespace Tango.PPC.Common.UWF { - public class AlternativeUnifiedWriteFilterManager : IUnifiedWriteFilterManager + public class AlternativeUnifiedWriteFilterManager : ExtendedObject, IUnifiedWriteFilterManager { private const string UWF_PATH = "C:\\Windows\\Sysnative\\uwfmgr.exe"; - /// - /// Gets a value indicating whether UWF if currently enabled on the system. - /// - public bool IsEnabled { get; private set; } - /// /// Installs and configures the service (requires restart). /// @@ -47,14 +43,15 @@ namespace Tango.PPC.Common.UWF command.OutputEncoding = CmdCommand.OutEncoding.Unicode; await command.Run(); - command = new CmdCommand("wmic", $"computersystem where name=\"%computername%\" set AutomaticManagedPagefile=False"); - await command.Run(); + //We don't use page file anymore since upgrade to 4GB RAM. But keep this just in case. + //command = new CmdCommand("wmic", $"computersystem where name=\"%computername%\" set AutomaticManagedPagefile=False"); + //await command.Run(); - command = new CmdCommand("wmic", $"pagefileset create name=\"p:\\pagefile.sys\""); - await command.Run(); + //command = new CmdCommand("wmic", $"pagefileset create name=\"p:\\pagefile.sys\""); + //await command.Run(); - command = new CmdCommand("wmic", $"pagefileset where name=\"p:\\\\pagefile.sys\" set InitialSize=16,MaximumSize=3870"); - await command.Run(); + //command = new CmdCommand("wmic", $"pagefileset where name=\"p:\\\\pagefile.sys\" set InitialSize=16,MaximumSize=3870"); + //await command.Run(); } /// @@ -67,5 +64,32 @@ namespace Tango.PPC.Common.UWF command.OutputEncoding = CmdCommand.OutEncoding.Unicode; await command.Run(); } + + /// + /// Gets a value indicating whether UWF if currently enabled on the system. + /// + /// + public async Task IsEnabled() + { + String pattern = @"Next Session Settings[\n\r]+FILTER SETTINGS[\n\r]+\s+Filter state:\s+(OFF|ON)"; + + LogManager.Log($"Getting UWF status using pattern '{pattern}'..."); + CmdCommand command = new CmdCommand(UWF_PATH, $"get-config"); + command.ExitStrategy = CmdCommand.ExitStrategies.StandardOutput; + command.OutputEncoding = CmdCommand.OutEncoding.Unicode; + var result = await command.Run(); + + Match match = Regex.Match(result.StandardOutput, pattern); + if (match != null && match.Success && match.Groups.Count > 1) + { + var value = match.Groups[1].Value; + + LogManager.Log($"UWF pattern parsing result: '{value}'."); + + return value.ToStringOrEmpty().Trim() == "ON"; + } + + return false; + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/DefaultUnifiedWriteFilterManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/DefaultUnifiedWriteFilterManager.cs index 65cb3f466..5684f6926 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/DefaultUnifiedWriteFilterManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/DefaultUnifiedWriteFilterManager.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; +using Tango.Core; using Tango.Core.Components; namespace Tango.PPC.Common.UWF @@ -11,7 +13,7 @@ namespace Tango.PPC.Common.UWF /// Represents the default unified writer filter manager. /// /// - public class DefaultUnifiedWriteFilterManager : IUnifiedWriteFilterManager + public class DefaultUnifiedWriteFilterManager : ExtendedObject, IUnifiedWriteFilterManager { private const int UWF_CAPACITY_MB = 5000; private const string UWF_PATH = "C:\\Windows\\Sysnative\\uwfmgr.exe"; @@ -23,11 +25,6 @@ namespace Tango.PPC.Common.UWF @"C:\Program Files (x86)\Twine", }; - /// - /// Gets a value indicating whether UWF if currently enabled on the system. - /// - public bool IsEnabled { get; } - /// /// Installs and configures the service (requires restart). /// @@ -95,5 +92,31 @@ namespace Tango.PPC.Common.UWF command.OutputEncoding = CmdCommand.OutEncoding.Unicode; await command.Run(); } + + /// + /// Gets a value indicating whether UWF if currently enabled on the system. + /// + /// + public async Task IsEnabled() + { + String pattern = @"Next Session Settings[\n\r]+FILTER SETTINGS[\n\r]+\s+Filter state:\s+(OFF|ON)"; + + LogManager.Log($"Getting UWF status using pattern '{pattern}'..."); + CmdCommand command = new CmdCommand(UWF_PATH, $"get-config"); + command.OutputEncoding = CmdCommand.OutEncoding.Unicode; + var result = await command.Run(); + + Match match = Regex.Match(result.StandardOutput, pattern); + if (match != null && match.Success && match.Groups.Count > 1) + { + var value = match.Groups[1].Value; + + LogManager.Log($"UWF pattern parsing result: '{value}'."); + + return value.ToStringOrEmpty().Trim() == "ON"; + } + + return false; + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/IUnifiedWriteFilterManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/IUnifiedWriteFilterManager.cs index 05fa1876a..b6a661ab5 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/IUnifiedWriteFilterManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/IUnifiedWriteFilterManager.cs @@ -14,7 +14,8 @@ namespace Tango.PPC.Common.UWF /// /// Gets a value indicating whether UWF if currently enabled on the system. /// - bool IsEnabled { get; } + /// + Task IsEnabled(); /// /// Installs and configures the service (requires restart). diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/DefaultPackageRunner.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/DefaultPackageRunner.cs new file mode 100644 index 000000000..68b31da4e --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/DefaultPackageRunner.cs @@ -0,0 +1,362 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.DI; +using Tango.Core.Helpers; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class DefaultPackageRunner : ExtendedObject, IPackageRunner + { + private JsonSerializerSettings _jsonSettings; + private String _configFile; + private PackagesFile _packagesFile; + + public event EventHandler PackageStateChanged; + public event EventHandler PackageProgress; + + public DefaultPackageRunner() + { + _jsonSettings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + Error = (sender, args) => + { + args.ErrorContext.Handled = true; + LogManager.Log(args.ErrorContext.Error.Message); + } + }; + + _jsonSettings.Converters.Add(new StringEnumConverter(false)); + + _configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Packages", "packages.json"); + } + + public Task GetPackagesFile() + { + return Task.Factory.StartNew(() => + { + if (_packagesFile != null) + { + return _packagesFile; + } + else + { + Directory.CreateDirectory(Path.GetDirectoryName(_configFile)); + + _packagesFile = new PackagesFile(); + + try + { + if (File.Exists(_configFile)) + { + LogManager.Log("Loading packages config from " + _configFile + "..."); + _packagesFile = JsonConvert.DeserializeObject(File.ReadAllText(_configFile), _jsonSettings); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading packages file."); + } + + return _packagesFile; + } + }); + } + + private void SavePackagesConfig() + { + Directory.CreateDirectory(Path.GetDirectoryName(_configFile)); + + String json = String.Empty; + + if (_packagesFile != null) + { + json = JsonConvert.SerializeObject(_packagesFile, _jsonSettings); + } + else + { + json = JsonConvert.SerializeObject(new PackagesFile(), _jsonSettings); + } + + File.WriteAllText(_configFile, json); + } + + public Task Run(PackageType type, Version deltaVersion, String packagesFolder) + { + return Task.Factory.StartNew(() => + { + PackageRunnerResult result = new PackageRunnerResult(); + + PackageContext context = new PackageContext(); + context.ApplicationManager = TangoIOC.Default.GetInstance(); + context.MachineProvider = TangoIOC.Default.GetInstance(); + context.NotificationProvider = TangoIOC.Default.GetInstance(); + context.InstalledVersion = context.ApplicationManager.Version; + context.DeltaVersion = deltaVersion; + + LogManager.Log($"Running {type}-update packages..."); + + //Get installed packages. + _packagesFile = GetPackagesFile().Result; + + LogManager.Log($"Installed packages file:\n{_packagesFile}"); + + if (Debugger.IsAttached) + { + LogManager.Log("Debugger attached detected. switching packages folder to main application path..."); + + //TO DEBUG PACKAGES -- + // + //On DEBUG build the packages assemblies are copied to the main application output folder using post-build events. + //Then, if a debugger is attached, we change the packages folder to the main output folder so they can be debugged easily. + packagesFolder = AssemblyHelper.GetCurrentAssemblyFolder(); + } + + LogManager.Log($"Scanning for packages on '{packagesFolder}'..."); + + //Get all packages in folder. + foreach (var packageFile in Directory.GetFiles(packagesFolder, "*.dll")) + { + LogManager.Log($"Loading assembly '{Path.GetFileName(packageFile)}'..."); + + Assembly asm; + + //Load assembly and investigate for types based on package type. + try + { + asm = Assembly.LoadFile(packageFile); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading assembly!"); + continue; + } + + try + { + foreach (var packageType in asm.GetTypes().Where( + x => typeof(IPPCPackage).IsAssignableFrom(x) && + x.GetCustomAttribute() != null && + x.GetCustomAttribute().Type == type)) + { + LogManager.Log($"Checking package '{packageType.FullName}'..."); + + try + { + //Getting installed package from file. + var installedPackage = _packagesFile.PackageInstallations.SingleOrDefault(x => x.PackageName == packageType.FullName); + + //Check if requires installation. + if (installedPackage == null || installedPackage.State != PackageInstallationState.Installed) + { + if (installedPackage == null) + { + LogManager.Log("Package was never installed."); + + installedPackage = new PackageInstallation(); + installedPackage.State = PackageInstallationState.NotInstalled; + installedPackage.PackageName = packageType.FullName; + installedPackage.Type = type; + _packagesFile.PackageInstallations.Add(installedPackage); + } + else + { + LogManager.Log($"Package installation state is '{installedPackage.State}' due to {installedPackage.FailedReason}"); + } + + LogManager.Log("Installing package..."); + + //Install package... + var att = packageType.GetCustomAttribute(); + + var packageInstance = Activator.CreateInstance(packageType) as IPPCPackage; + + if (packageInstance != null) + { + try + { + OnPackageRuns(att.Name, installedPackage.State, installedPackage.Type); + installedPackage.InstallationDate = DateTime.Now; + context.ProgressAction = (message, isIntermediate, progress, total) => + { + PackageProgress?.Invoke(this, new PackageProgressEventArgs() + { + PackageName = att.Name, + Message = message, + IsIntermediate = isIntermediate, + Progress = progress, + Total = total + }); + }; + + PackageProgress?.Invoke(this, new PackageProgressEventArgs() + { + PackageName = type == PackageType.Pre ? "Preparing" : "Finalizing", + Message = att.Name, + IsIntermediate = true, + Progress = 0, + Total = 100 + }); + + packageInstance.Run(context).GetAwaiter().GetResult(); + installedPackage.State = PackageInstallationState.Installed; + installedPackage.FailedReason = null; + OnPackageRuns(att.Name, installedPackage.State, installedPackage.Type); + LogManager.Log("Package installed successfully."); + + if (att.RequiresRestart) + { + result.RestartRequired = true; + } + + Thread.Sleep(2000); + } + catch (Exception ex) + { + LogManager.Log(ex, "Package installation failed."); + installedPackage.State = PackageInstallationState.Failed; + installedPackage.FailedReason = ex.FlattenMessage(); + OnPackageRuns(att.Name, installedPackage.State, installedPackage.Type); + continue; + } + } + } + else + { + LogManager.Log("Package is already installed."); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error in handling the package!"); + continue; + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error investigating assembly!"); + continue; + } + } + + //Save package file. + LogManager.Log("Running packages has completed. Saving packages config file."); + + try + { + SavePackagesConfig(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving packages file!"); + } + + return result; + }); + } + + public Task IsPackageInstallationRequired(PackageType type, String packagesFolder) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Checking if any package installation is required..."); + + _packagesFile = GetPackagesFile().Result; + + //Get all packages in folder. + foreach (var packageFile in Directory.GetFiles(packagesFolder, "*.dll")) + { + LogManager.Log($"Loading assembly '{Path.GetFileName(packageFile)}'..."); + + Assembly asm; + + //Load assembly and investigate for types based on package type. + try + { + asm = Assembly.LoadFile(packageFile); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading assembly!"); + continue; + } + + try + { + foreach (var packageType in asm.GetTypes().Where( + x => typeof(IPPCPackage).IsAssignableFrom(x) && + x.GetCustomAttribute() != null && + x.GetCustomAttribute().Type == type)) + { + LogManager.Log($"Checking package '{packageType.FullName}'..."); + + try + { + //Getting installed package from file. + var installedPackage = _packagesFile.PackageInstallations.SingleOrDefault(x => x.PackageName == packageType.FullName); + + //Check if requires installation. + if (installedPackage == null || installedPackage.State != PackageInstallationState.Installed) + { + if (installedPackage == null) + { + LogManager.Log("Package was never installed."); + return true; + } + else + { + LogManager.Log($"Package installation state is '{installedPackage.State}' due to {installedPackage.FailedReason}"); + return true; + } + } + else + { + LogManager.Log("Package is already installed."); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error in handling the package!"); + continue; + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error investigating assembly!"); + continue; + } + } + + LogManager.Log("No packages to install."); + + return false; + }); + } + + protected virtual void OnPackageRuns(String packageName, PackageInstallationState state, PackageType type) + { + PackageStateChanged?.Invoke(this, new PackageStateChangedEventArgs() + { + PackageName = packageName, + State = state, + PackageType = type, + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPPCPackage.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPPCPackage.cs new file mode 100644 index 000000000..d9dc70135 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPPCPackage.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.UpdatePackages +{ + public interface IPPCPackage + { + Task Run(PackageContext context); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPackageRunner.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPackageRunner.cs new file mode 100644 index 000000000..cdffd1ddc --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPackageRunner.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Common.UpdatePackages +{ + public interface IPackageRunner + { + event EventHandler PackageStateChanged; + event EventHandler PackageProgress; + Task GetPackagesFile(); + Task Run(PackageType type, Version deltaVersion, String packagesFolder); + Task IsPackageInstallationRequired(PackageType type, String packagesFolder); + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PPCPackageAttribute.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PPCPackageAttribute.cs new file mode 100644 index 000000000..6067b0c18 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PPCPackageAttribute.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Common.UpdatePackages +{ + [AttributeUsage(AttributeTargets.Class)] + public class PPCPackageAttribute : Attribute + { + public String Name { get; set; } + + public PackageType Type { get; set; } + + public bool RequiresRestart { get; set; } + + public PPCPackageAttribute(PackageType type, String name, bool requiresRestart) + { + Type = type; + Name = name; + RequiresRestart = requiresRestart; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageContext.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageContext.cs new file mode 100644 index 000000000..7c8736112 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageContext.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class PackageContext + { + public delegate void PackageProgressDelegate(String message, bool isIntermediate = true, double progress = 0, double maximum = 100); + + public IPPCApplicationManager ApplicationManager { get; set; } + public IMachineProvider MachineProvider { get; set; } + public INotificationProvider NotificationProvider { get; set; } + public Version InstalledVersion { get; set; } + public Version DeltaVersion { get; set; } + internal PackageProgressDelegate ProgressAction { get; set; } + + public void ReportProgress(String message, bool isIntermediate = true, double progress = 0, double maximum = 100) + { + ProgressAction?.Invoke(message, isIntermediate, progress, maximum); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageProgressEventArgs.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageProgressEventArgs.cs new file mode 100644 index 000000000..ebf0b23a6 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageProgressEventArgs.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class PackageProgressEventArgs : EventArgs + { + public String PackageName { get; set; } + public String Message { get; set; } + public bool IsIntermediate { get; set; } + public double Progress { get; set; } + public double Total { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageRunnerResult.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageRunnerResult.cs new file mode 100644 index 000000000..55f3a490a --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageRunnerResult.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class PackageRunnerResult + { + public bool RestartRequired { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageStateChangedEventArgs.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageStateChangedEventArgs.cs new file mode 100644 index 000000000..cadba4c72 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageStateChangedEventArgs.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class PackageStateChangedEventArgs : EventArgs + { + public PackageInstallationState State { get; set; } + public String PackageName { get; set; } + public PackageType PackageType { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackagesFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackagesFile.cs new file mode 100644 index 000000000..7af30d2ec --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackagesFile.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Common.UpdatePackages +{ + public class PackagesFile + { + public List PackageInstallations { get; set; } + + public PackagesFile() + { + PackageInstallations = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateRequest.cs index b98848e4f..8e13ea7c4 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateRequest.cs @@ -9,7 +9,21 @@ namespace Tango.PPC.Common.Web { public class CheckForUpdateRequest : WebRequestMessage { - public String SerialNumber { get; set; } public String Version { get; set; } + public String FirmwareVersion { get; set; } + + public List Rmls { get; set; } + public List HardwareVersions { get; set; } + public List Catalogs { get; set; } + public DateTime MachineLastUpdated { get; set; } + public List UsedRmlsGuids { get; set; } + + public CheckForUpdateRequest() + { + Rmls = new List(); + HardwareVersions = new List(); + Catalogs = new List(); + UsedRmlsGuids = new List(); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateResponse.cs index 370c0f5ea..2fb33ebdc 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateResponse.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateResponse.cs @@ -10,8 +10,18 @@ namespace Tango.PPC.Common.Web public class CheckForUpdateResponse : WebResponseMessage { public bool IsUpdateAvailable { get; set; } + public bool IsDatabaseUpdateAvailable { get; set; } public String Version { get; set; } + public String FirmwareVersion { get; set; } public bool SetupFirmware { get; set; } public bool SetupFPGA { get; set; } + public UpdateDBResponse UpdateDBResponse { get; set; } + public List UsedNotExistingRmlsGuids { get; set; } + + public CheckForUpdateResponse() + { + UpdateDBResponse = new UpdateDBResponse(); + UsedNotExistingRmlsGuids = new List(); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataRequest.cs new file mode 100644 index 000000000..bbb0e883b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataRequest.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class DownloadMachineDataRequest : WebRequestMessage + { + public bool RequestJobs { get; set; } + public bool RequestJobRuns { get; set; } + public bool RequestMachineEvents { get; set; } + public bool RequestDataStoreItems { get; set; } + + public int MaxJobs { get; set; } + public int MaxJobRuns { get; set; } + public int MaxMachinesEvents { get; set; } + public int MaxDataStoreItems { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataResponse.cs new file mode 100644 index 000000000..e90c7c2ac --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataResponse.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class DownloadMachineDataResponse : WebResponseMessage + { + public List Jobs { get; set; } + public List JobRuns { get; set; } + public List MachineEvents { get; set; } + public List DataStoreItems { get; set; } + + public DownloadMachineDataResponse() + { + Jobs = new List(); + JobRuns = new List(); + MachineEvents = new List(); + DataStoreItems = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateRequest.cs index a32d3d497..db4080dff 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateRequest.cs @@ -9,6 +9,6 @@ namespace Tango.PPC.Common.Web { public class DownloadUpdateRequest : WebRequestMessage { - public String SerialNumber { get; set; } + } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateResponse.cs index 3b09c1525..2fc7e4810 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateResponse.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateResponse.cs @@ -10,10 +10,16 @@ namespace Tango.PPC.Common.Web { public class DownloadUpdateResponse : WebResponseMessage { + public String NotifyCompletedToken { get; set; } + public String Version { get; set; } + public String FirmwareVersion { get; set; } + public String BlobAddress { get; set; } + public String CdnAddress { get; set; } + public DataSource DataSource { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LatestVersionResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LatestVersionResponse.cs index d2ed08f7d..eb5ef7f5a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LatestVersionResponse.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LatestVersionResponse.cs @@ -11,5 +11,6 @@ namespace Tango.PPC.Common.Web public class LatestVersionResponse : WebResponseMessage { public String Version { get; set; } + public String FirmwareVersion { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LoginRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LoginRequest.cs index f8588f6b0..9ae0d65ae 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LoginRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LoginRequest.cs @@ -11,6 +11,7 @@ namespace Tango.PPC.Common.Web { public LoginMode Mode { get; set; } public String SerialNumber { get; set; } + public String MachineGuid { get; set; } public String Email { get; set; } public String Password { get; set; } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupRequest.cs index 821828a48..a9e68df36 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupRequest.cs @@ -9,7 +9,6 @@ namespace Tango.PPC.Common.Web { public class MachineSetupRequest : WebRequestMessage { - public String SerialNumber { get; set; } public String DeviceID { get; set; } public String DeviceName { get; set; } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupResponse.cs index b5a4c425d..f5d03c6ce 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupResponse.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupResponse.cs @@ -10,10 +10,16 @@ namespace Tango.PPC.Common.Web { public class MachineSetupResponse : WebResponseMessage { + public String NotifyCompletedToken { get; set; } + public String Version { get; set; } + public String FirmwareVersion { get; set; } + public String BlobAddress { get; set; } + public String CdnAddress { get; set; } + public DataSource DataSource { get; set; } public String OSKey { get; set; } @@ -25,5 +31,6 @@ namespace Tango.PPC.Common.Web public bool SetupFPGA { get; set; } public bool IsDemo { get; set; } public String DeviceComPort { get; set; } + public String Organization { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedRequest.cs new file mode 100644 index 000000000..dffe1f15b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class MachineUpdateCompletedRequest : WebRequestMessage + { + public String Token { get; set; } + public TangoUpdateStatuses Status { get; set; } + public String FailedReason { get; set; } + public String FailedLog { get; set; } + public bool ReportsAboutDbCheckNoDifferences { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedResponse.cs new file mode 100644 index 000000000..72517d108 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedResponse.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class MachineUpdateCompletedResponse : WebResponseMessage + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedRequest.cs new file mode 100644 index 000000000..fda7a4666 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedRequest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class NotifyMachineDataDownloadCompletedRequest : WebRequestMessage + { + public List SynchronizedJobs { get; set; } + public List SynchronizedJobRuns { get; set; } + public List SynchronizedMachineEvents { get; set; } + public List SynchronizedDataStoreItems { get; set; } + + public NotifyMachineDataDownloadCompletedRequest() + { + SynchronizedJobs = new List(); + SynchronizedJobRuns = new List(); + SynchronizedMachineEvents = new List(); + SynchronizedDataStoreItems = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedResponse.cs new file mode 100644 index 000000000..6d5769885 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedResponse.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class NotifyMachineDataDownloadCompletedResponse : WebResponseMessage + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClient.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClient.cs index 52c9fdef3..318512fbb 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClient.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClient.cs @@ -30,5 +30,10 @@ namespace Tango.PPC.Common.Web public PPCWebClient(string address, string token) : base(address, token) { } + + public PPCWebClient(PPCWebClient other, TimeSpan requestTimeout) : base(other) + { + RequestTimeout = requestTimeout; + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs index 2df343241..ff972acb2 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs @@ -40,6 +40,15 @@ namespace Tango.PPC.Common.Web } + /// + /// Initializes a new instance of the class. + /// + /// Other instance. + public PPCWebClientBase(PPCWebClientBase cloned) : base(cloned) + { + + } + /// /// Executes the MachineSetup action and returns Tango.PPC.Common.Web.MachineSetupResponse. /// @@ -58,6 +67,15 @@ namespace Tango.PPC.Common.Web return Post("MachineUpdate", request); } + /// + /// Executes the NotifyUpdateCompleted action and returns Tango.PPC.Common.Web.MachineUpdateCompletedResponse. + /// + /// + public Task NotifyUpdateCompleted(Tango.PPC.Common.Web.MachineUpdateCompletedRequest request) + { + return Post("NotifyUpdateCompleted", request); + } + /// /// Executes the CheckForUpdates action and returns Tango.PPC.Common.Web.CheckForUpdateResponse. /// @@ -76,6 +94,33 @@ namespace Tango.PPC.Common.Web return Post("UpdateDB", request); } + /// + /// Executes the UploadMachineData action and returns Tango.PPC.Common.Web.UploadMachineDataResponse. + /// + /// + public Task UploadMachineData(Tango.PPC.Common.Web.UploadMachineDataRequest request) + { + return Post("UploadMachineData", request); + } + + /// + /// Executes the DownloadMachineData action and returns Tango.PPC.Common.Web.DownloadMachineDataResponse. + /// + /// + public Task DownloadMachineData(Tango.PPC.Common.Web.DownloadMachineDataRequest request) + { + return Post("DownloadMachineData", request); + } + + /// + /// Executes the NotifyMachineDataDownloadCompleted action and returns Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedResponse. + /// + /// + public Task NotifyMachineDataDownloadCompleted(Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedRequest request) + { + return Post("NotifyMachineDataDownloadCompleted", request); + } + /// /// Executes the GetLatestVersion action and returns Tango.PPC.Common.Web.LatestVersionResponse. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/SynchronizationFailedEntity.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/SynchronizationFailedEntity.cs new file mode 100644 index 000000000..c50044cbe --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/SynchronizationFailedEntity.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.Web +{ + public class SynchronizationFailedEntity + { + public String Guid { get; set; } + public String Reason { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs index f3b4ccb34..4d8433a56 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs @@ -9,6 +9,7 @@ namespace Tango.PPC.Common.Web { public class UpdateDBRequest : WebRequestMessage { - public String SerialNumber { get; set; } + public String ApplicationVersion { get; set; } + public String FirmwareVersion { get; set; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs index be7c0d076..179cb7934 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs @@ -10,6 +10,7 @@ namespace Tango.PPC.Common.Web { public class UpdateDBResponse : WebResponseMessage { + public String NotifyCompletedToken { get; set; } public DataSource DataSource { get; set; } public bool PerformSchemaUpdate { get; set; } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdatedEntity.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdatedEntity.cs new file mode 100644 index 000000000..faee20678 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdatedEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; + +namespace Tango.PPC.Common.Web +{ + public class UpdatedEntity + { + public UpdatedEntity() + { + + } + + public UpdatedEntity(IObservableEntity entity) : this() + { + Guid = entity.Guid; + LastUpdated = entity.LastUpdated; + } + + public String Guid { get; set; } + public DateTime LastUpdated { get; set; } + + public override string ToString() + { + return $"{Guid} | {LastUpdated}"; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataRequest.cs new file mode 100644 index 000000000..8eee667cd --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataRequest.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class UploadMachineDataRequest : WebRequestMessage + { + public List Jobs { get; set; } + public List JobRuns { get; set; } + public List MachineEvents { get; set; } + public List OfflineUpdates { get; set; } + public List DataStoreItems { get; set; } + public String ApplicationVersion { get; set; } + public String FirmwareVersion { get; set; } + + public UploadMachineDataRequest() + { + Jobs = new List(); + JobRuns = new List(); + MachineEvents = new List(); + OfflineUpdates = new List(); + DataStoreItems = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataResponse.cs new file mode 100644 index 000000000..ba0b4089b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataResponse.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.Web +{ + public class UploadMachineDataResponse : WebResponseMessage + { + public List FailedJobs { get; set; } + public List FailedJobRuns { get; set; } + public List FailedMachineEvents { get; set; } + public List FailedOfflineUpdates { get; set; } + public List FailedDataStoreItems { get; set; } + + public String NotifyCompletedToken { get; set; } + + public UploadMachineDataResponse() + { + FailedJobs = new List(); + FailedJobRuns = new List(); + FailedMachineEvents = new List(); + FailedOfflineUpdates = new List(); + FailedDataStoreItems = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/packages.config b/Software/Visual_Studio/PPC/Tango.PPC.Common/packages.config index 50785f217..adc33d349 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/packages.config +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/packages.config @@ -6,6 +6,7 @@ + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/App.config b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/App.config new file mode 100644 index 000000000..a46da65da --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/App.config @@ -0,0 +1,28 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs new file mode 100644 index 000000000..091ef8f13 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.SQLExaminer; + +namespace Tango.PPC.DataSynchronizer.CLI +{ + class Program + { + static void Main(string[] args) + { + DataSynchronizer synchronizer = new DataSynchronizer(); + synchronizer.Synchronize(); + Console.ReadLine(); + } + } + + public class DataSynchronizer + { + private Core.DataSource source; + private Core.DataSource target; + private String machineGuid; + + public void Synchronize() + { + try + { + Console.WriteLine("Starting PPC data synchronization..."); + + source = new Core.DataSource(); + source.IntegratedSecurity = false; + source.Address = "twine.database.windows.net"; + source.Catalog = "Tango_DEV"; + source.UserName = "Roy"; + source.Password = "Aa123456"; + + using (ObservablesContext db = ObservablesContext.CreateDefault(source)) + { + machineGuid = db.Machines.Where(x => x.SerialNumber == "LENA_TABLET").Take(1).Select(x => x.Guid).First(); + } + + target = new Core.DataSource(); + target.Address = "localhost\\SQLPPC"; + target.Catalog = "Tango"; + + OverrideData(); + UpdateMachine(); + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Synchronization Completed Successfully."); + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(ex.ToString()); + } + } + + private void OverrideData() + { + Console.WriteLine("Executing override data script..."); + + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.OverrideData); + builder.SetSource(source).SetTarget(target).Synchronize(); + var process = new ExaminerProcess(builder.Build(), ExaminerProcessType.Data); + process.Progress += (x, msg) => + { + if (msg != null && !msg.Contains("SQL Examiner")) + { + Console.WriteLine(msg); + } + }; + var result = process.Execute().Result; + + if (result.ExitCode != ExaminerProcessExitCode.Success) + { + throw new InvalidOperationException(result.Output); + } + } + + private void UpdateMachine() + { + Console.WriteLine("Executing update machine script..."); + + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.UpdateMachine); + builder.SetSource(source).SetTarget(target).SetMachineSerialNumber(machineGuid).Synchronize(); + var process = new ExaminerProcess(builder.Build(), ExaminerProcessType.Data); + process.Progress += (x, msg) => + { + if (msg != null && !msg.Contains("SQL Examiner")) + { + Console.WriteLine(msg); + } + }; + var result = process.Execute().Result; + + if (result.ExitCode != ExaminerProcessExitCode.Success) + { + throw new InvalidOperationException(result.Output); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..450b7dc72 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.DataSynchronizer.CLI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.DataSynchronizer.CLI")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3e07ed4e-a755-443f-b18c-3775555a2dd7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Tango.PPC.DataSynchronizer.CLI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Tango.PPC.DataSynchronizer.CLI.csproj new file mode 100644 index 000000000..aeab763bc --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Tango.PPC.DataSynchronizer.CLI.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {3E07ED4E-A755-443F-B18C-3775555A2DD7} + Exe + Tango.PPC.DataSynchronizer.CLI + Tango.PPC.DataSynchronizer.CLI + v4.6.1 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll + + + ..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll + + + + + + + + + + + + + + + + + + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {e1e66ed9-597d-45fa-8048-de90a6930484} + Tango.SQLExaminer + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/packages.config b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/packages.config new file mode 100644 index 000000000..b3daf0d6c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindow.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindow.xaml index f74194222..e772a4b87 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindow.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindow.xaml @@ -10,7 +10,7 @@ xmlns:web="clr-namespace:Tango.Web;assembly=Tango.Web" xmlns:local="clr-namespace:Tango.PPC.Publisher.UI" mc:Ignorable="d" - Title="Tango PPC Publisher" Height="1100" Width="500" d:DataContext="{d:DesignInstance Type=local:MainWindowVM, IsDesignTimeCreatable=False}"> + Title="Tango PPC Publisher" Height="1000" Width="500" d:DataContext="{d:DesignInstance Type=local:MainWindowVM, IsDesignTimeCreatable=False}" WindowStartupLocation="CenterScreen"> @@ -67,15 +67,17 @@ - Remote Version: - + Remote Versions: + , + - Local Version: - + Local Versions: + , + @@ -129,6 +131,13 @@ Password + + + Create Tag On Repository + Auto Commit & Push + Personal Access Token + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs index 98b35ed3f..bf4c7af30 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; @@ -67,6 +68,13 @@ namespace Tango.PPC.Publisher.UI set { _localVersion = value; RaisePropertyChangedAuto(); } } + private String _localFirmwareVersion; + public String LocalFirmwareVersion + { + get { return _localFirmwareVersion; } + set { _localFirmwareVersion = value; RaisePropertyChangedAuto(); } + } + private String _remoteVersion; public String RemoteVersion { @@ -74,6 +82,13 @@ namespace Tango.PPC.Publisher.UI set { _remoteVersion = value; RaisePropertyChangedAuto(); } } + private String _remoteFirmwareVersion; + public String RemoteFirmwareVersion + { + get { return _remoteFirmwareVersion; } + set { _remoteFirmwareVersion = value; RaisePropertyChangedAuto(); } + } + private ICollectionView _provisionSequenceItemsView; public ICollectionView ProvisionSequenceItemsView { @@ -127,6 +142,7 @@ namespace Tango.PPC.Publisher.UI Options.BasicInfoChanged += (_, __) => InvalidateRelayCommands(); Options.EnvironmentChanged += async (_, __) => await OnEnvironmentChanged(); Options.BuidConfigChanged += async (_, __) => await UpdateVersions(); + Options.TfpPathChanged += async (_, __) => await UpdateVersions(); Init(); } @@ -165,9 +181,18 @@ namespace Tango.PPC.Publisher.UI { IsFree = false; LocalVersion = _publisher.GetLocalVersion(); + + try + { + LocalFirmwareVersion = _publisher.GetLocalFirmwareVersion(Options.TfpPath); + } + catch {} + if (SelectedMachineVersion != null) { - RemoteVersion = await _publisher.GetRemoteVersion(SelectedMachineVersion.Guid); + var latestVersion = await _publisher.GetRemoteVersion(SelectedMachineVersion.Guid); + RemoteVersion = latestVersion.Version; + RemoteFirmwareVersion = latestVersion.FirmwareVersion; } InvalidateRelayCommands(); IsFree = true; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.csproj index f40a4b338..332554ffc 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.csproj @@ -66,6 +66,7 @@ + @@ -133,6 +134,7 @@ SettingsSingleFileGenerator Settings.Designer.cs + @@ -146,6 +148,10 @@ {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {99081c0e-065c-4d68-bf60-f82330cca02d} + Tango.Git + {D8F1AD85-526A-4F50-B6DC-D437AF63D8D8} Tango.Settings diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.json b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.json new file mode 100644 index 000000000..19dea4781 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.json @@ -0,0 +1,164 @@ +{ + "$type": "System.Collections.Generic.List`1[[Tango.Settings.SettingsBase, Tango.Settings]], mscorlib", + "$values": [ + { + "$type": "Tango.PPC.Common.PPCSettings, Tango.PPC.Common", + "ApplicationState": "PreSetup", + "MachineScanningTimeoutSeconds": 20, + "AutoConnectWiFiName": null, + "AutoConnectWiFiPassword": null, + "EmbeddedComPort": null, + "EmbeddedDeviceHint": "Tango USB Serial Port", + "EnableExternalBridge": false, + "ExternalBridgePassword": "Aa123456", + "EnableHotSpot": false, + "HotSpotPassword": "Aa123456", + "EnableRemoteAssistance": false, + "DeploymentSlot": "DEV", + "EnableWatchDog": true, + "EnableTechnicianModeByDefault": false, + "JobUploadStrategy": "JobDescriptionFile", + "EnableGradientGeneration": true, + "GradientGenerationResolution": 20, + "EnableLockScreen": false, + "LockScreenTimeout": "00:10:00", + "LockScreenPassword": "1111", + "EnableEmergencyNotifications": true, + "EmergencyComPort": "COM1", + "EnableJobLiquidQuantityValidation": true, + "JobUnitsMethod": "Device", + "LoadedRmlGuid": null, + "DefaultRmlGuid": null, + "SupportedColorSpaces": { + "$type": "System.Collections.Generic.List`1[[Tango.BL.Enumerations.ColorSpaces, Tango.BL]], mscorlib", + "$values": [] + }, + "SupportedJobTypes": { + "$type": "System.Collections.Generic.List`1[[Tango.BL.Enumerations.JobTypes, Tango.BL]], mscorlib", + "$values": [] + }, + "DefaultSpoolTypeGuid": null, + "DefaultSegmentLength": 100, + "PreviousApplicationVersion": "1.0.0.0", + "SynchronizeJobs": true, + "SynchronizeDiagnostics": true, + "SynchronizationInterval": "01:00:00", + "FirmwareVersion": "1.0.0.0", + "DisplayPowerUpScreen": true, + "PowerUpScreenTimeout": "00:00:20", + "AutoCheckForUpdates": true, + "AutoUpdateCheckInterval": "00:30:00", + "EnableAutomaticThreadLoading": true, + "DisplayAutomaticThreadLoadingScreen": true, + "EnableEmbeddedDebugLogs": true, + "TcpTransportAdapterWriteMode": "Interval", + "EnableExternalBridgeSignalR": true, + "ExternalBridgeSignalRHub": "ExternalBridgeHub", + "EnableRemoteDesktop": true, + "RemoteDesktopFrameRate": 5 + }, + { + "$type": "Tango.Core.CoreSettings, Tango.Core", + "DataSource": { + "$type": "Tango.Core.DataSource, Tango.Core", + "Type": "SQLServer", + "Address": "localhost\\SQLEXPRESS", + "Catalog": "Tango", + "IntegratedSecurity": true, + "UserName": "", + "Password": "", + "AccessToken": null, + "AccessTokenExpiration": "0001-01-01T00:00:00" + } + }, + { + "$type": "Tango.PPC.Publisher.UI.PublisherSettings, Tango.PPC.Publisher.UI", + "Options": { + "$type": "Tango.PPC.Common.Publish.PublishOptions, Tango.PPC.Common", + "BasePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Build\\PPC\\Debug\\..\\", + "BuildConfig": "Release", + "Email": "roy@twine-s.com", + "Password": "1Creativity", + "Comments": "Several bug fixes.", + "Environment": "TEST", + "MachineVersionGuid": "997a53b0-e752-474e-9618-7262c02d0127", + "TfpPath": "P:\\Software\\FirmwareUpgrade\\Version 1.4.6.20\\firmware_package.tfp", + "InstallerProject": "D:\\Development\\Tango\\Software\\Visual_Studio\\Advanced Installer Projects\\PPC Installer.aip", + "InstallerOutputFolder": "D:\\Development\\Tango\\Software\\Visual_Studio\\Build\\Installers\\PPC", + "Synchronization": { + "$type": "Tango.PPC.Common.Publish.SynchronizationOptions, Tango.PPC.Common", + "ProvisionSequenceItems": { + "$type": "System.Collections.ObjectModel.ObservableCollection`1[[Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common]], System", + "$values": [ + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Schema", + "Direction": "SourceToTarget", + "Index": 0, + "Name": "Synchronizing schema", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\Schema.xml", + "RequiresSerialNumber": false, + "FileName": "Schema.xml" + }, + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Data", + "Direction": "SourceToTarget", + "Index": 1, + "Name": "Synchronizing collections", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\OverrideData.xml", + "RequiresSerialNumber": false, + "FileName": "OverrideData.xml" + }, + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Data", + "Direction": "SourceToTarget", + "Index": 2, + "Name": "Configuring machine", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\ProvisionMachine.xml", + "RequiresSerialNumber": true, + "FileName": "ProvisionMachine.xml" + } + ] + }, + "UpdateSequenceItems": { + "$type": "System.Collections.ObjectModel.ObservableCollection`1[[Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common]], System", + "$values": [ + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Schema", + "Direction": "SourceToTarget", + "Index": 0, + "Name": "Updating schema", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\Schema.xml", + "RequiresSerialNumber": false, + "FileName": "Schema.xml" + }, + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Data", + "Direction": "SourceToTarget", + "Index": 1, + "Name": "Updating collections", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\OverrideData.xml", + "RequiresSerialNumber": false, + "FileName": "OverrideData.xml" + }, + { + "$type": "Tango.PPC.Common.Publish.SequenceItem, Tango.PPC.Common", + "Type": "Data", + "Direction": "SourceToTarget", + "Index": 2, + "Name": "Updating machine", + "FilePath": "D:\\Development\\Tango\\Software\\Visual_Studio\\Tango.SQLExaminer\\SQLExaminer\\Configurations\\UpdateMachine.xml", + "RequiresSerialNumber": true, + "FileName": "UpdateMachine.xml" + } + ] + } + } + } + } + ] +} \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/App.config b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/App.config new file mode 100644 index 000000000..731f6de6c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Program.cs b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Program.cs new file mode 100644 index 000000000..d77192de2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Program.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.SQLExaminer; + +namespace Tango.PPC.SchemaSynchronizer.CLI +{ + class Program + { + static void Main(string[] args) + { + Core.DataSource source = new Core.DataSource(); + source.Address = "localhost\\SQLEXPRESS"; + source.Catalog = "Tango"; + + Core.DataSource target = new Core.DataSource(); + target.Address = "localhost\\SQLPPC"; + target.Catalog = "Tango"; + + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.Schema); + + builder. + SetSource(source). + SetTarget(target). + Synchronize(); + + var config = builder.Build(); + + ExaminerProcess process = new ExaminerProcess(config, ExaminerProcessType.Schema); + process.Progress += (x, msg) => + { + Console.WriteLine(msg); + }; + var result = process.Execute().Result; + + if (result.ExitCode == ExaminerProcessExitCode.Success) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Completed!"); + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed!"); + } + + Console.ReadLine(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..61246489d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.SchemaSynchronizer.CLI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.SchemaSynchronizer.CLI")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f3746f2b-e4ae-498b-9d42-74f95d992460")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Tango.PPC.SchemaSynchronizer.CLI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Tango.PPC.SchemaSynchronizer.CLI.csproj new file mode 100644 index 000000000..529815ba2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Tango.PPC.SchemaSynchronizer.CLI.csproj @@ -0,0 +1,63 @@ + + + + + Debug + AnyCPU + {F3746F2B-E4AE-498B-9D42-74F95D992460} + Exe + Tango.PPC.SchemaSynchronizer.CLI + Tango.PPC.SchemaSynchronizer.CLI + v4.6.1 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + + + {e1e66ed9-597d-45fa-8048-de90a6930484} + Tango.SQLExaminer + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventRequest.cs new file mode 100644 index 000000000..3546c285f --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventRequest.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Diagnostics; + +namespace Tango.PPC.Shared.Events +{ + public class PushEmulatedEventRequest + { + public Event Event { get; set; } + public TimeSpan Timeout { get; set; } + + public PushEmulatedEventRequest() + { + Timeout = TimeSpan.FromSeconds(5); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventResponse.cs new file mode 100644 index 000000000..2fb3a2a70 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Events +{ + public class PushEmulatedEventResponse + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationRequest.cs new file mode 100644 index 000000000..1464c15ac --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Information +{ + public class GetMachineInformationRequest + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationResponse.cs new file mode 100644 index 000000000..e88bfce05 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Information +{ + public class GetMachineInformationResponse + { + public InformationPackage Package { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/InformationPackage.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/InformationPackage.cs new file mode 100644 index 000000000..e48413db6 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/InformationPackage.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.SystemInfo; + +namespace Tango.PPC.Shared.Information +{ + public class InformationPackage + { + public List System { get; set; } + + public InformationPackage() + { + System = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedRequest.cs new file mode 100644 index 000000000..f298f6a6b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsDownloadCompletedRequest + { + public String InisightsFilePath { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedResponse.cs new file mode 100644 index 000000000..04fd3d1b9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsDownloadCompletedResponse + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateRequest.cs new file mode 100644 index 000000000..1bb70c396 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsMinDateRequest + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateResponse.cs new file mode 100644 index 000000000..7d0e0db84 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsMinDateResponse + { + public DateTime? MinDate { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs new file mode 100644 index 000000000..b34895e78 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsRequest + { + public DateTime StartDateUTC { get; set; } + public DateTime EndDateUTC { get; set; } + + public bool IncludeEvents { get; set; } + public bool IncludeStatuses { get; set; } + public bool IncludeApplicationExceptions { get; set; } + + public InsightsRequest() + { + IncludeEvents = true; + IncludeStatuses = true; + IncludeApplicationExceptions = true; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsResponse.cs new file mode 100644 index 000000000..38333a459 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsResponse.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Insights +{ + public class InsightsResponse + { + public String InisightsFilePath { get; set; } + public long InsightsFileLength { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs new file mode 100644 index 000000000..d91d612d1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.PMR.Printing; + +namespace Tango.PPC.Shared.Jobs +{ + public class RemoteJobProgress + { + public RemoteJobStage Stage { get; set; } + public JobStatus JobStatus { get; set; } + + public RemoteJobProgress() + { + JobStatus = new JobStatus(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs new file mode 100644 index 000000000..5235b995b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Jobs +{ + public enum RemoteJobStage + { + None, + Started, + Running, + Failed, + Aborted, + Completed + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateRequest.cs new file mode 100644 index 000000000..1322031ac --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Jobs +{ + public class RemoteJobUpdateRequest + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateResponse.cs new file mode 100644 index 000000000..0bb32d266 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateResponse.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; +using Tango.Core; + +namespace Tango.PPC.Shared.Jobs +{ + public class RemoteJobUpdateResponse + { + public JobDTO Job { get; set; } + public ProcessParametersTableDTO ProcessParameters { get; set; } + public RemoteJobProgress Progress { get; set; } + + public RemoteJobUpdateResponse() + { + Progress = new RemoteJobProgress(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs new file mode 100644 index 000000000..bb5d21837 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class GetLogFilesRequest + { + public RemoteLogFileType LogFileType { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs new file mode 100644 index 000000000..cf5d59726 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class GetLogFilesResponse + { + public List LogFiles { get; set; } + + public GetLogFilesResponse() + { + LogFiles = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs new file mode 100644 index 000000000..fc2ba88c4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public class RemoteLogFile + { + public String Name { get; set; } + public DateTime DateModified { get; set; } + public DateTime DateCreated { get; set; } + public String Path { get; set; } + public long Length { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs new file mode 100644 index 000000000..958b4c195 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Logs +{ + public enum RemoteLogFileType + { + Application, + Firmware + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/PerformancePackage.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/PerformancePackage.cs new file mode 100644 index 000000000..855437bcc --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/PerformancePackage.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Performance +{ + public class PerformancePackage + { + public int CPU { get; set; } + public int ApplicationCPU { get; set; } + + public int RAM { get; set; } + public int ApplicationRAM { get; set; } + public int MaxRAM { get; set; } + + public int Temperature { get; set; } + + public int AvailableDiskSpace { get; set; } + public int DiskCapacity { get; set; } + + public DateTime DateTime { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesRequest.cs new file mode 100644 index 000000000..69fbaf631 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Performance +{ + public class StartPerformanceUpdatesRequest + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesResponse.cs new file mode 100644 index 000000000..196225572 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Performance +{ + public class StartPerformanceUpdatesResponse + { + public PerformancePackage Package { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c9efeb790 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango Panel PC Shared Library")] +[assembly: AssemblyVersion("1.0.0.0")] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +//Friends With +[assembly: InternalsVisibleTo("Tango.PPC.UI")] diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.Designer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.Designer.cs new file mode 100644 index 000000000..416184c0f --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.Designer.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Shared.Properties { + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if ((resourceMan == null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.PPC.Shared.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.resx b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.Designer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.Designer.cs new file mode 100644 index 000000000..0b65472a5 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.PPC.Shared.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.settings b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs new file mode 100644 index 000000000..76216edad --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteActions +{ + public class SimulateApplicationExceptionRequest + { + public bool CrashApplication { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs new file mode 100644 index 000000000..e0b71ddf4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteActions +{ + public class SimulateApplicationExceptionResponse + { + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs new file mode 100644 index 000000000..bd2d6eba3 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteApplicationUpgradeRequest + { + public String RemoteTupFilePath { get; set; } + public bool SetupFirmware { get; set; } = true; + public bool SetupFPGA { get; set; } = true; + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs new file mode 100644 index 000000000..89f2b4e71 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteApplicationUpgradeResponse + { + public TangoProgress Progress { get; set; } + + public StartRemoteApplicationUpgradeResponse() + { + Progress = new TangoProgress() + { + Message = "Initializing...", + IsIndeterminate = true, + Maximum = 100 + }; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs new file mode 100644 index 000000000..9dedc0b2d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteFirmwareUpgradeRequest + { + public String RemoteTfpFilePath { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs new file mode 100644 index 000000000..32fcd19c0 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.PPC.Shared.RemoteUpgrade +{ + public class StartRemoteFirmwareUpgradeResponse + { + public TangoProgress Progress { get; set; } + + public StartRemoteFirmwareUpgradeResponse() + { + Progress = new TangoProgress() + { + Message = "Initializing...", + IsIndeterminate = true, + Maximum = 100 + }; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs new file mode 100644 index 000000000..7802fc3f7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + public class ExecuteSqlRequest + { + public String SQL { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs new file mode 100644 index 000000000..2db90a336 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + public class ExecuteSqlResponse + { + public int AffectedRecords { get; set; } + public RemoteSqlDataSet DataSet { get; set; } + + public ExecuteSqlResponse() + { + DataSet = new RemoteSqlDataSet(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs new file mode 100644 index 000000000..54431bdbe --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + /// + /// Represents a column. + /// + public class RemoteSqlColumn + { + /// + /// Gets or sets the column name. + /// + public String Name { get; set; } + + /// + /// Gets or sets the column index. + /// + public int Index { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public RemoteSqlColumn() + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// The column name. + public RemoteSqlColumn(String name) + { + Name = name; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumnCollection.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumnCollection.cs new file mode 100644 index 000000000..dfda6c3b7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumnCollection.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + /// + /// Represents a columns collection. + /// + /// + public class RemoteSqlColumnCollection : Collection + { + private Dictionary _dictionary; + + /// + /// Initializes a new instance of the class. + /// + public RemoteSqlColumnCollection() + { + _dictionary = new Dictionary(); + } + + /// + /// Inserts an element into the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The object to insert. The value can be null for reference types. + protected override void InsertItem(int index, RemoteSqlColumn item) + { + item.Index = Count; + _dictionary.Add(item.Name, item); + base.InsertItem(index, item); + } + + /// + /// Removes the element at the specified index of the . + /// + /// The zero-based index of the element to remove. + /// + protected override void RemoveItem(int index) + { + throw new NotSupportedException(); + } + + /// + /// Removes all elements from the . + /// + protected override void ClearItems() + { + _dictionary.Clear(); + base.ClearItems(); + } + + /// + /// Replaces the element at the specified index. + /// + /// The zero-based index of the element to replace. + /// The new value for the element at the specified index. The value can be null for reference types. + /// + protected override void SetItem(int index, RemoteSqlColumn item) + { + throw new NotSupportedException(); + } + + /// + /// Gets the column index by column name. + /// + /// Column name. + /// + public int GetIndexOf(String columnName) + { + return _dictionary[columnName].Index; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs new file mode 100644 index 000000000..72b8d2eb2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + /// + /// Represents remote database query result composed of rows and columns. + /// + /// + /// + /// + /// The following example demonstrates how to set the connected machine's demo state and query for the connected machine's jobs. + /// + /// + /// + /// + public class RemoteSqlDataSet + { + /// + /// Gets or sets the dataset columns. + /// + public RemoteSqlColumnCollection Columns { get; set; } + + private ObservableCollection _rows; + /// + /// Gets or sets the dataset rows. + /// + public ObservableCollection Rows + { + get { return _rows; } + set { _rows = value; OnRowsChanged(); } + } + + /// + /// Initializes a new instance of the class. + /// + public RemoteSqlDataSet() + { + Columns = new RemoteSqlColumnCollection(); + Rows = new ObservableCollection(); + } + + private void OnRowsChanged() + { + if (Rows != null) + { + Rows.CollectionChanged -= Rows_CollectionChanged; + Rows.CollectionChanged += Rows_CollectionChanged; + + InitRows(); + } + } + + private void Rows_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + InitRows(); + } + + private void InitRows() + { + if (Rows != null) + { + foreach (var row in Rows.ToList()) + { + row.Init( + (key) => + { + return row.Values[Columns.GetIndexOf(key)]; + }, + (index) => + { + return row.Values[index]; + }); + } + } + } + + /// + /// Creates a new using the specified . + /// + /// The reader. + /// + public static Task Load(SqlDataReader reader) + { + return Task.Factory.StartNew(() => + { + bool columnsRead = false; + RemoteSqlDataSet dataSet = new RemoteSqlDataSet(); + + try + { + while (reader.Read()) + { + RemoteSqlRow row = new RemoteSqlRow(); + + for (int i = 0; i < reader.FieldCount; i++) + { + if (!columnsRead) + { + dataSet.Columns.Add(new RemoteSqlColumn() + { + Name = reader.GetName(i) + }); + } + + row.Values.Add(reader.GetValue(i)); + } + + columnsRead = true; + dataSet.Rows.Add(row); + } + } + finally + { + reader.Close(); + } + + return dataSet; + }); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return String.Join(", ", Columns.Select(x => x.Name)) + "\n" + String.Join(Environment.NewLine, Rows.Select(x => x.ToString())); + } + + /// + /// Formats this dataset as a string with columns and rows. + /// + /// + public String ToTableString() + { + Dictionary columnsMaxLength = new Dictionary(); + + for (int i = 0; i < Columns.Count; i++) + { + columnsMaxLength.Add(i, Columns[i].Name.Length); + } + + foreach (var row in Rows) + { + for (int i = 0; i < row.Values.Count; i++) + { + int valueLength = row.Values[i].ToStringSafe().Length; + + if (valueLength > columnsMaxLength[i]) + { + columnsMaxLength[i] = valueLength; + } + } + } + + String str = String.Empty; + + for (int i = 0; i < Columns.Count; i++) + { + str += $"{Columns[i].Name.PadRight(columnsMaxLength[i])}{(i < Columns.Count - 1 ? " | " : "")}"; + } + + int width = str.Length; + str += Environment.NewLine + String.Empty.PadRight(width, '-'); + + foreach (var row in Rows) + { + str += Environment.NewLine; + + for (int i = 0; i < row.Values.Count; i++) + { + str += $"{row.Values[i].ToStringSafe().PadRight(columnsMaxLength[i])}{(i < Columns.Count - 1 ? " | " : "")}"; + } + } + + return str; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs new file mode 100644 index 000000000..dfabacfea --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; + +namespace Tango.PPC.Shared.SQL +{ + /// + /// Represents a row. + /// + /// + /// + /// + /// The following example demonstrates how to set the connected machine's demo state and query for the connected machine's jobs. + /// + /// + /// + /// + public class RemoteSqlRow + { + private Func _getFuncKey; + private Func _getFuncIndex; + + /// + /// Gets or sets the row values. + /// + public List Values { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public RemoteSqlRow() + { + Values = new List(); + } + + /// + /// Gets a row value by its column name. + /// + /// Name of the column. + /// The column value. + public Object Get(String columnName) + { + return _getFuncKey.Invoke(columnName); + } + + /// + /// Gets a row value by its column index. + /// + /// Index of the column. + /// The column value. + public Object Get(int columnIndex) + { + return _getFuncIndex.Invoke(columnIndex); + } + + /// + /// Gets a row value as type T by its column name. + /// + /// Expected column type. + /// Name of the column. + /// The column value. + public T Get(String columnName) + { + var value = _getFuncKey.Invoke(columnName); + + if (typeof(T) != value.GetType()) + { + return (T)Convert.ChangeType(value, typeof(T)); + } + else + { + return (T)value; + } + } + + /// + /// Gets a row value by its column index. + /// + /// Expected column type + /// Index of the column. + /// The column value. + public T Get(int columnIndex) + { + var value = _getFuncIndex.Invoke(columnIndex); + + if (typeof(T) != value.GetType()) + { + return (T)Convert.ChangeType(value, typeof(T)); + } + else + { + return (T)value; + } + } + + internal void Init(Func getFuncKey, Func getFuncIndex) + { + _getFuncKey = getFuncKey; + _getFuncIndex = getFuncIndex; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return String.Join(", ", Values); + } + + /// + /// Creates an object of type T and maps this row to it based on its properties decorated with . + /// + /// + /// + public T Map() where T : class, new() + { + var obj = Activator.CreateInstance(); + Map(obj); + return obj; + } + + /// + /// Maps this row to the specified object based on its properties decorated with . + /// + /// Model type + /// The object. + public void Map(T obj) where T : class + { + foreach (var prop in typeof(T).GetPropertiesWithAttribute()) + { + try + { + var columnName = prop.GetCustomAttribute().Name; + var value = Get(columnName).ToStringSafe(); + prop.SetValue(obj, Convert.ChangeType(value, prop.PropertyType)); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj new file mode 100644 index 000000000..8c3908bba --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {208C8BD8-72C6-4E3C-ACAA-351091A2ACC7} + library + Tango.PPC.Shared + Tango.PPC.Shared + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + true + full + false + ..\..\Build\PPC\Debug\ + DEBUG;TRACE + prompt + 4 + ..\..\Build\PPC\Debug\Tango.PPC.Shared.xml + 1591 + + + pdbonly + true + ..\..\Build\PPC\Release\ + TRACE + prompt + 4 + ..\..\Build\PPC\Release\Tango.PPC.Shared.xml + 1591 + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + GlobalVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {f441feee-322a-4943-b566-110e12fd3b72} + Tango.BL + + + {A34EE0F0-649D-41C8-8489-B6F1CC6924EE} + Tango.Core + + + {E4927038-348D-4295-AAF4-861C58CB3943} + Tango.PMR + + + {997a961c-beda-4b56-aa0f-c39e532f7ffa} + Tango.SystemInfo + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Themes/Generic.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Themes/Generic.xaml new file mode 100644 index 000000000..1226f66d1 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Themes/Generic.xaml @@ -0,0 +1,6 @@ + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesRequest.cs new file mode 100644 index 000000000..f8cadc49d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Updates +{ + public class GetUpdatesAndPackagesRequest + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesResponse.cs new file mode 100644 index 000000000..d264739d7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesResponse.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.DTO; + +namespace Tango.PPC.Shared.Updates +{ + public class GetUpdatesAndPackagesResponse + { + public List Updates { get; set; } + + public List Packages { get; set; } + + public GetUpdatesAndPackagesResponse() + { + Updates = new List(); + Packages = new List(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallation.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallation.cs new file mode 100644 index 000000000..639fd76bf --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallation.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Updates +{ + public class PackageInstallation + { + public String PackageName { get; set; } + + public PackageType Type { get; set; } + + public DateTime InstallationDate { get; set; } + + public PackageInstallationState State { get; set; } + + public String FailedReason { get; set; } + + public PackageInstallation() + { + InstallationDate = DateTime.Now; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallationState.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallationState.cs new file mode 100644 index 000000000..51ae2abce --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallationState.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Updates +{ + public enum PackageInstallationState + { + NotInstalled, + Installed, + Failed, + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageType.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageType.cs new file mode 100644 index 000000000..0e553ca21 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.Updates +{ + public enum PackageType + { + Pre, + Post + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config index 77255b814..5272eb35d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config @@ -8,8 +8,13 @@ - + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml.cs new file mode 100644 index 000000000..fdd7bfc30 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.AppBarItems +{ + /// + /// Interaction logic for PowerOffAppBarItemView.xaml + /// + public partial class PowerOffAppBarItemView : UserControl + { + public PowerOffAppBarItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs new file mode 100644 index 000000000..966e78769 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PMR.Power; +using Tango.PPC.Common.Notifications; + +namespace Tango.PPC.UI.AppBarItems +{ + public class PowerUpAppBarItem : AppBarItem + { + private StartPowerUpResponse _status; + public StartPowerUpResponse Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the view type. + /// + public override Type ViewType + { + get + { + return typeof(PowerUpAppBarItemView); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml new file mode 100644 index 000000000..b6b769c69 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + % + Completed + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml.cs new file mode 100644 index 000000000..599f24d3b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.AppBarItems +{ + /// + /// Interaction logic for PowerOffAppBarItemView.xaml + /// + public partial class PowerUpAppBarItemView : UserControl + { + public PowerUpAppBarItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Authentication/DefaultAuthenticationProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Authentication/DefaultAuthenticationProvider.cs index 04e968da2..e7be61b0a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Authentication/DefaultAuthenticationProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Authentication/DefaultAuthenticationProvider.cs @@ -45,6 +45,11 @@ namespace Tango.PPC.UI.Authentication } } + /// + /// Gets a value indicating whether the authentication provider is using a null user. + /// + public bool AuthenticationRequired { get; private set; } + /// /// Performs a user login by the specified email and password. /// @@ -56,6 +61,9 @@ namespace Tango.PPC.UI.Authentication { return Task.Factory.StartNew(() => { + + AuthenticationRequired = true; + String hash = encrypt ? User.GetPasswordHash(password) : password; LogManager.Log($"Logging in user {email}..."); @@ -82,6 +90,16 @@ namespace Tango.PPC.UI.Authentication }); } + public Task Login() + { + return Task.Factory.StartNew(() => + { + AuthenticationRequired = false; + CurrentUser = null; + CurrentUserChanged?.Invoke(this, CurrentUser); + }); + } + /// /// Logs-out the current logged-in user. /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Connectivity/DefaultConnectivityProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Connectivity/DefaultConnectivityProvider.cs index 53e143def..5218d9f70 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Connectivity/DefaultConnectivityProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Connectivity/DefaultConnectivityProvider.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Net; +using System.Net.NetworkInformation; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -29,7 +30,9 @@ namespace Tango.PPC.UI.Connectivity private IMachineProvider _machineProvider; private Rfc2898Cryptographer _cryptographer; private System.Timers.Timer _updateTimer; + private System.Timers.Timer _lanUpdateTimer; private WiFiNetwork _connectedNetwork; + private PPCSettings _settings; /// /// Occurs when the connectivity provider state has changed (e.g network connected/disconnected). @@ -43,7 +46,17 @@ namespace Tango.PPC.UI.Connectivity public bool IsConnected { get { return _isConnected; } - set { _isConnected = value; RaisePropertyChangedAuto(); } + private set { _isConnected = value; RaisePropertyChangedAuto(); } + } + + private bool _isLanConnected; + /// + /// Gets a value indicating whether there is LAN connection. + /// + public bool IsLanConnected + { + get { return _isLanConnected; } + private set { _isLanConnected = value; RaisePropertyChangedAuto(); } } private bool _isHotspoActive; @@ -116,6 +129,8 @@ namespace Tango.PPC.UI.Connectivity { await RefreshAvailableWiFiNetworks(); }); + + _settings = SettingsManager.Default.GetOrCreate(); } /// @@ -153,6 +168,28 @@ namespace Tango.PPC.UI.Connectivity _updateTimer = new System.Timers.Timer(TimeSpan.FromSeconds(30).TotalMilliseconds); _updateTimer.Elapsed += _updateTimer_Elapsed; _updateTimer.Start(); + + _lanUpdateTimer = new System.Timers.Timer(TimeSpan.FromSeconds(10).TotalMilliseconds); + _lanUpdateTimer.Elapsed += _lanUpdateTimer_Elapsed; + _lanUpdateTimer.Start(); + } + + private void _lanUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + foreach (NetworkInterface net in NetworkInterface.GetAllNetworkInterfaces()) + { + if ((net.NetworkInterfaceType == NetworkInterfaceType.Ethernet + || net.NetworkInterfaceType == NetworkInterfaceType.Ethernet3Megabit + || net.NetworkInterfaceType == NetworkInterfaceType.FastEthernetFx + || net.NetworkInterfaceType == NetworkInterfaceType.FastEthernetT + || net.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet) && net.Name.ToStringOrEmpty().StartsWith("Ethernet") && net.OperationalStatus == OperationalStatus.Up) + { + IsLanConnected = true; + return; + } + } + + IsLanConnected = false; } /// @@ -223,6 +260,11 @@ namespace Tango.PPC.UI.Connectivity /// public Task CheckInternetConnection() { + if (_settings.BypassInternetConnectivityCheck) + { + return Task.FromResult(true); + } + return Task.Factory.StartNew(() => { try diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml new file mode 100644 index 000000000..3404c032a --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml @@ -0,0 +1,49 @@ + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml.cs new file mode 100644 index 000000000..61ecef0ad --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Controls +{ + /// + /// Interaction logic for MachineStatusControl.xaml + /// + public partial class MachineStatusControl : UserControl + { + public MachineStatusControl() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml new file mode 100644 index 000000000..66bd0392d --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml @@ -0,0 +1,28 @@ + + + + + CANCEL + UPGRADE + + + + Tango Firmware Upgrade + The selected file contains a firmware upgrade package. Press 'UPGRADE' to start updating your system. + + + Firmware: + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml.cs new file mode 100644 index 000000000..e7e1eb86c --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Dialogs +{ + /// + /// Interaction logic for UpdateFromFileView.xaml + /// + public partial class FirmwareUpgradeFromFileView : UserControl + { + public FirmwareUpgradeFromFileView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileViewVM.cs new file mode 100644 index 000000000..9a7322565 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileViewVM.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common.Publish; +using Tango.SharedUI; + +namespace Tango.PPC.UI.Dialogs +{ + public class FirmwareUpgradeFromFileViewVM : DialogViewVM + { + public String Version { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml index f3c471954..ad1c2ece3 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" + xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" xmlns:local="clr-namespace:Tango.PPC.UI.Dialogs" mc:Ignorable="d" Background="{StaticResource TangoPrimaryBackgroundBrush}" Width="700" Height="800" d:DataContext="{d:DesignInstance Type=local:InsufficientLiquidQuantityViewVM, IsDesignTimeCreatable=False}"> @@ -20,28 +20,59 @@ The job cannot be completed. - + - + - - - + + + + + + + + + + + + + - + - - + + - + + + + + + + + + - + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml.cs index 9ec1eec0e..e0f02e4af 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml.cs @@ -33,7 +33,7 @@ namespace Tango.PPC.UI.Dialogs Grid parent = border.Parent as Grid; IDSPackLevel packLevel = border.DataContext as IDSPackLevel; - border.Height = ((double)packLevel.Current / (double)MachineOperator.MAX_DISPENSER_NANOLITER) * parent.ActualHeight; + border.Width = Math.Max(((double)packLevel.Current / (double)MachineOperator.MAX_DISPENSER_NANOLITER) * parent.ActualWidth, 0); } private void Limit_Loaded(object sender, RoutedEventArgs e) @@ -42,8 +42,8 @@ namespace Tango.PPC.UI.Dialogs Grid parent = rect.Parent as Grid; IDSPackLevel packLevel = rect.DataContext as IDSPackLevel; - var top = ((double)packLevel.Required / (double)MachineOperator.MAX_DISPENSER_NANOLITER) * parent.ActualHeight; - rect.Margin = new Thickness(0, 0, 0, top); + var left = ((double)packLevel.Required / (double)MachineOperator.MAX_DISPENSER_NANOLITER) * parent.ActualWidth; + rect.Margin = new Thickness(left, 0, 0, 0); if (packLevel.IsValid) { diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml new file mode 100644 index 000000000..081778434 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml @@ -0,0 +1,32 @@ + + + + + Continue getting ready for: + + + + + + + Minimal temperature + + + CONTINUE + + + auto select in + + sec + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs new file mode 100644 index 000000000..a9767276a --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Dialogs +{ + /// + /// Interaction logic for PowerUpView.xaml + /// + public partial class PowerUpView : UserControl + { + public PowerUpView() + { + InitializeComponent(); + } + + protected override void OnPreviewMouseUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseUp(e); + (DataContext as PowerUpViewVM).IsTimeoutEnabled = false; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs new file mode 100644 index 000000000..ec4b3bb2b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using Tango.BL.Entities; +using Tango.PPC.Common; +using Tango.Settings; +using Tango.SharedUI; + +namespace Tango.PPC.UI.Dialogs +{ + public class PowerUpViewVM : DialogViewVM + { + private Timer _timer; + + private List _rmls; + public List Rmls + { + get { return _rmls; } + set { _rmls = value; RaisePropertyChangedAuto(); } + } + + private Rml _selectedRml; + public Rml SelectedRml + { + get { return _selectedRml; } + set { _selectedRml = value; RaisePropertyChangedAuto(); } + } + + private bool _isSelectedRml; + public bool IsSelectedRml + { + get { return _isSelectedRml; } + set + { + _isSelectedRml = value; + RaisePropertyChangedAuto(); + + if (_isSelectedRml) + { + IsMinimalTemperature = false; + } + } + } + + private bool _isMinimalTemperature; + public bool IsMinimalTemperature + { + get { return _isMinimalTemperature; } + set + { + _isMinimalTemperature = value; + RaisePropertyChangedAuto(); + + if (_isMinimalTemperature) + { + IsSelectedRml = false; + } + } + } + + private int _remainingSeconds; + public int RemainingSeconds + { + get { return _remainingSeconds; } + set { _remainingSeconds = value; RaisePropertyChangedAuto(); } + } + + private bool _isTimeoutEnabled; + public bool IsTimeoutEnabled + { + get { return _isTimeoutEnabled; } + set + { + _isTimeoutEnabled = value; RaisePropertyChangedAuto(); + + if (!_isTimeoutEnabled) + { + _timer.Stop(); + } + } + } + + public PowerUpViewVM() + { + RemainingSeconds = (int)SettingsManager.Default.GetOrCreate().PowerUpScreenTimeout.TotalSeconds; + CanClose = true; + IsMinimalTemperature = true; + IsTimeoutEnabled = true; + _timer = new Timer(); + _timer.Interval = TimeSpan.FromSeconds(1).TotalMilliseconds; + _timer.Elapsed += _timer_Elapsed; + } + + private void _timer_Elapsed(object sender, ElapsedEventArgs e) + { + RemainingSeconds--; + + if (RemainingSeconds == 0) + { + InvokeUI(() => + { + Accept(); + }); + } + } + + protected override void Cancel() + { + _timer.Stop(); + base.Cancel(); + } + + protected override void Accept() + { + _timer.Stop(); + base.Accept(); + } + + public override void OnShow() + { + base.OnShow(); + _timer.Start(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml new file mode 100644 index 000000000..e96b39a63 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml @@ -0,0 +1,52 @@ + + + + + DECLINE + + + + + + + APPROVE + + + + Safety Level Access Request + + A remote client is requesting a safety level connection to this machine. + + Once approved, the remote user will be able to perform any mechanical operation remotely. + + + + + Request Information + + Address: + + + Host Name: + + + App ID: + + + User: + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml.cs new file mode 100644 index 000000000..ef689f1de --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Dialogs +{ + /// + /// Interaction logic for SafetyLevelOperationsConfirmationView.xaml + /// + public partial class SafetyLevelOperationsConfirmationView : UserControl + { + public SafetyLevelOperationsConfirmationView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationViewVM.cs new file mode 100644 index 000000000..f8027b4c2 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationViewVM.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; +using Tango.Integration.ExternalBridge; +using Tango.PMR.Integration; +using Tango.SharedUI; + +namespace Tango.PPC.UI.Dialogs +{ + public class SafetyLevelOperationsConfirmationViewVM : DialogViewVM + { + private DispatcherTimer _timer; + + private int _maxSeconds; + public int MaxSeconds + { + get { return _maxSeconds; } + set { _maxSeconds = value; RaisePropertyChangedAuto(); } + } + + private int _secondsRemaining; + public int SecondsRemaining + { + get { return _secondsRemaining; } + set { _secondsRemaining = value; RaisePropertyChangedAuto(); } + } + + private ExternalBridgeClientConnectedEventArgs _connection; + /// + /// Gets or sets the last client connection event arguments. + /// + public ExternalBridgeClientConnectedEventArgs Connection + { + get { return _connection; } + set { _connection = value; RaisePropertyChangedAuto(); } + } + + public SafetyLevelOperationsConfirmationViewVM(ExternalBridgeClientConnectedEventArgs connection) + { + Connection = connection; + + MaxSeconds = 30; + SecondsRemaining = 30; + + _timer = new DispatcherTimer(DispatcherPriority.Background, Application.Current.Dispatcher); + _timer.Interval = TimeSpan.FromMilliseconds(800); + _timer.Tick += _timer_Tick; + } + + public override void OnShow() + { + base.OnShow(); + _timer.Start(); + } + + protected override void Accept() + { + _timer.Stop(); + base.Accept(); + } + + protected override void Cancel() + { + _timer.Stop(); + base.Cancel(); + } + + private void _timer_Tick(object sender, EventArgs e) + { + SecondsRemaining--; + + if (SecondsRemaining == 0) + { + Cancel(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml new file mode 100644 index 000000000..f17860d42 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml @@ -0,0 +1,225 @@ + + + + + + Thread Break Wizard + + + + + + + + + + Back + + + + + + + + + + + + Found But Can't Fix + Found and Fixed + Can't Find It + + + + Please check guiding units on both sides of the system and fix/tie the thread if possible. + + + + + + + + + + + + + + Found and Fixed + Can't Fix + + + if the thread is out of is route or tangle on one of the components you can go to the maintenance screen and open the component to solve the problem + + + + + Open the covers and check the feeder and puller and fix/tie if possible. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Removed Successfully + Can't Remove + + + + + HOT SURFACE! + + + Recommended to cool down and/or to wear safety gloves + + + + + + Open the dryer, cut the thread and remove any residue. + + + + + + + + + + + + + + + + + + + Open The Thread Loading Wizard + + + You will be able to open the thread loading wizard once the dryer door is closed + + + + + Close the dryer door + + + + + + + + + + + + + + + + + + Close + + + + + Please Contact Twine Customer Care + + + + + support@twine-s.com + + + + + + + + + + + + Verifying thread movement + + + + + working... + + + + + + + + + + + Close + + + + + Issue Resolved + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs new file mode 100644 index 000000000..c105a9a15 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Dialogs +{ + /// + /// Interaction logic for ThreadBreakWizard.xaml + /// + public partial class ThreadBreakView : UserControl + { + public ThreadBreakView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs new file mode 100644 index 000000000..e737f3b12 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Logging; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.SharedUI; + +namespace Tango.PPC.UI.Dialogs +{ + public class ThreadBreakViewVM : DialogViewVM + { + public enum ThreadBreakWizardResult + { + None, + StartThreadLoading + } + + public enum WizardStage + { + Welcome, + GuidingUnits, + FeedingUnits, + Jogging, + TheDryer, + DryerClose, + Fixed, + ContactSupport, + } + + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + [TangoInject] + private INotificationProvider NotificationProvider { get; set; } + + public ThreadBreakWizardResult Result { get; set; } + + private WizardStage _stage; + public WizardStage Stage + { + get { return _stage; } + set { _stage = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _isArcHead; + public bool IsArcHead + { + get { return _isArcHead; } + set { _isArcHead = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand BackCommand { get; set; } + + //Guiding Units + public RelayCommand GuidingUnitsFoundCantFixCommand { get; set; } + public RelayCommand GuidingUnitsCantFindItCommand { get; set; } + public RelayCommand GuidingUnitsFoundAndFixedCommand { get; set; } + + //Feeding Units + public RelayCommand FeedingUnitsCantFixCommand { get; set; } + public RelayCommand FeedingUnitsFoundAndFixedCommand { get; set; } + + //The Dryer + public RelayCommand TheDryerCantRemoveCommand { get; set; } + public RelayCommand TheDryerRemovedSuccessfullyCommand { get; set; } + + //Dryer Close + public RelayCommand OpenThreadLoadingWizardCommand { get; set; } + + public ThreadBreakViewVM() + { + CanClose = true; + TangoIOC.Default.Inject(this); + + MachineProvider.MachineOperator.MachineEventsStateProvider.EventsChanged += MachineEventsStateProvider_EventsChanged; + MachineProvider.MachineDisconnected += MachineProvider_MachineDisconnected; + + IsArcHead = MachineProvider.Machine.MachineHeadType == BL.Enumerations.HeadTypes.Arc; + + BackCommand = new RelayCommand(GoBack, CanGoBack); + + //Guiding Units Commands + GuidingUnitsFoundCantFixCommand = new RelayCommand(GuidingUnitsFoundCantFix); + GuidingUnitsCantFindItCommand = new RelayCommand(GuidingUnitsCantFindIt); + GuidingUnitsFoundAndFixedCommand = new RelayCommand(GuidingUnitsFoundAndFixed); + + //Feeding Units Commands + FeedingUnitsCantFixCommand = new RelayCommand(FeedingUnitsCantFix); + FeedingUnitsFoundAndFixedCommand = new RelayCommand(FeedingUnitsFoundAndFixed); + + //The Dryer Commands + TheDryerRemovedSuccessfullyCommand = new RelayCommand(TheDryerRemovedSuccessfully); + TheDryerCantRemoveCommand = new RelayCommand(TheDryerCantRemove); + + OpenThreadLoadingWizardCommand = new RelayCommand(OpenThreadLoadingWizard, () => !MachineProvider.MachineOperator.MachineEventsStateProvider.Events.Any(x => x.Type == BL.Enumerations.EventTypes.DRYER_DOOR_OPEN)); + } + + private void MachineProvider_MachineDisconnected(object sender, EventArgs e) + { + InvokeUI(() => + { + Cancel(); + }); + } + + private void MachineEventsStateProvider_EventsChanged(object sender, IEnumerable e) + { + InvalidateRelayCommands(); + } + + #region Back + + private bool CanGoBack() + { + return Stage != WizardStage.GuidingUnits && + Stage != WizardStage.Jogging && + Stage != WizardStage.Fixed; + } + + private void GoBack() + { + switch (Stage) + { + case WizardStage.FeedingUnits: + Stage = WizardStage.GuidingUnits; + break; + case WizardStage.TheDryer: + Stage = WizardStage.GuidingUnits; + break; + case WizardStage.ContactSupport: + Stage = WizardStage.TheDryer; + break; + case WizardStage.DryerClose: + Stage = WizardStage.TheDryer; + break; + } + } + + #endregion + + #region Guiding Units Commands + + private async void GuidingUnitsFoundAndFixed() + { + Stage = WizardStage.Jogging; + + try + { + await MachineProvider.MachineOperator.AttemptThreadJogging(); + Stage = WizardStage.Fixed; + } + catch (Exception ex) + { + LogManager.Log(ex, LogCategory.Warning, "Error occurred while attempting to perform thread jogging."); + await NotificationProvider.ShowError($"Thread movement verification failed.\n{ex.FlattenMessage()}"); + Stage = WizardStage.FeedingUnits; + } + } + + private void GuidingUnitsCantFindIt() + { + Stage = WizardStage.FeedingUnits; + } + + private void GuidingUnitsFoundCantFix() + { + Stage = WizardStage.TheDryer; + } + + #endregion + + #region Feeding Units Commands + + private void FeedingUnitsCantFix() + { + Stage = WizardStage.TheDryer; + } + + private async void FeedingUnitsFoundAndFixed() + { + Stage = WizardStage.Jogging; + + try + { + await MachineProvider.MachineOperator.AttemptThreadJogging(); + Stage = WizardStage.Fixed; + } + catch (Exception ex) + { + LogManager.Log(ex, LogCategory.Warning, "Error occurred while attempting to perform thread jogging."); + await NotificationProvider.ShowError($"Thread movement verification failed.\n{ex.FlattenMessage()}"); + Stage = WizardStage.TheDryer; + } + } + + #endregion + + #region The Dryer Commands + + private void TheDryerCantRemove() + { + Stage = WizardStage.ContactSupport; + } + + private void TheDryerRemovedSuccessfully() + { + Stage = WizardStage.DryerClose; + } + + #endregion + + #region Dryer Close Commands + + private void OpenThreadLoadingWizard() + { + Result = ThreadBreakWizardResult.StartThreadLoading; + Accept(); + } + + #endregion + + protected override void Accept() + { + base.Accept(); + CleanUp(); + } + + protected override void Cancel() + { + base.Cancel(); + CleanUp(); + } + + private void CleanUp() + { + MachineProvider.MachineOperator.MachineEventsStateProvider.EventsChanged -= MachineEventsStateProvider_EventsChanged; + MachineProvider.MachineDisconnected -= MachineProvider_MachineDisconnected; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml new file mode 100644 index 000000000..e45065c61 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml @@ -0,0 +1,170 @@ + + + + + + Thread Loading + + + + + + + + + Continue + + + + Welcome to the automatic thread loading wizard. + + + + Please ensure there are no thread residue in the system and press + continue + + + + + + + + + + + + + Continue + + + + + The system is now preparing... + + + + + + + + + + + + Continue + + + + + Please select the thread type you are going to load and press + continue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Continue + + + + + The system is now loading the thread... + + + + + + + + + + + + + + Close + + + + Thread loading completed successfully! + + + + + + + + + + + Close + Retry + + + + Something went wrong, press 'retry' to try again + + + + + + + + + + + + Close + Retry + + + + Something went wrong, press 'retry' to try again + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs new file mode 100644 index 000000000..d4c737bcc --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Dialogs +{ + /// + /// Interaction logic for PowerUpView.xaml + /// + public partial class ThreadLoadingView : UserControl + { + public ThreadLoadingView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs new file mode 100644 index 000000000..bb503e718 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Builders; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.Integration.Operation; +using Tango.PMR.ThreadLoading; +using Tango.PPC.Common; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.Settings; +using Tango.SharedUI; + +namespace Tango.PPC.UI.Dialogs +{ + public class ThreadLoadingViewVM : DialogViewVM + { + public enum ThreadLoadingStage + { + Welcome, + Preparing, + ReadyForLoading, + Finalizing, + Completed, + PreparationError, + FinalizationError, + } + + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + [TangoInject] + private INotificationProvider NotificationProvider { get; set; } + + private PPCSettings _settings; + + private StartThreadLoadingResponse _status; + public StartThreadLoadingResponse Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + private List _rmls; + public List Rmls + { + get { return _rmls; } + set { _rmls = value; RaisePropertyChangedAuto(); } + } + + private Rml _selectedRml; + public Rml SelectedRml + { + get { return _selectedRml; } + set { _selectedRml = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private ThreadLoadingStage _stage; + public ThreadLoadingStage Stage + { + get { return _stage; } + set { _stage = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _isArcHead; + public bool IsArcHead + { + get { return _isArcHead; } + set { _isArcHead = value; RaisePropertyChangedAuto(); } + } + + private String _error; + public String Error + { + get { return _error; } + set { _error = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand ContinueCommand { get; set; } + public RelayCommand AbortCommand { get; set; } + + public ThreadLoadingViewVM(bool userInvoked = false) + { + CanClose = false; + + TangoIOC.Default.Inject(this); + _settings = SettingsManager.Default.GetOrCreate(); + + MachineProvider.MachineOperator.ThreadLoadingStatusChanged += MachineOperator_ThreadLoadingStatusChanged; + MachineProvider.MachineDisconnected += MachineProvider_MachineDisconnected; + + IsArcHead = MachineProvider.Machine.MachineHeadType == BL.Enumerations.HeadTypes.Arc; + + ContinueCommand = new RelayCommand(Continue, CanContinue); + AbortCommand = new RelayCommand(Abort); + + AdaptToState(userInvoked); + } + + private void MachineProvider_MachineDisconnected(object sender, EventArgs e) + { + InvokeUI(() => + { + Cancel(); + }); + } + + private void AdaptToState(bool userInvoked = false) + { + var status = MachineProvider.MachineOperator.ThreadLoadingStatus; + + if (status != null) + { + if (status.State == ThreadLoadingState.Preparing) + { + Stage = ThreadLoadingStage.Preparing; + } + else if (status.State == ThreadLoadingState.ReadyForLoading) + { + Stage = ThreadLoadingStage.ReadyForLoading; + } + else if (status.State == ThreadLoadingState.Finalizing) + { + Stage = ThreadLoadingStage.Finalizing; + } + else if (status.State == ThreadLoadingState.PreparationError) + { + OnPreparationError(status.ErrorReason); + } + else if (status.State == ThreadLoadingState.FinalizationError) + { + OnFinalizationError(status.ErrorReason); + } + else if (status.State == ThreadLoadingState.Completed) + { + if (userInvoked) + { + Stage = ThreadLoadingStage.Welcome; + } + else + { + Stage = ThreadLoadingStage.Completed; + } + } + } + } + + private void MachineOperator_ThreadLoadingStatusChanged(object sender, StartThreadLoadingResponse e) + { + Status = e; + AdaptToState(); + } + + private void Continue() + { + if (Stage == ThreadLoadingStage.Welcome) + { + Stage = ThreadLoadingStage.Preparing; + StartPreparing(); + } + else if (Stage == ThreadLoadingStage.ReadyForLoading) + { + ContinueThreadLoading(); + } + else if (Stage == ThreadLoadingStage.Completed) + { + Accept(); + } + else if (Stage == ThreadLoadingStage.PreparationError) + { + Stage = ThreadLoadingStage.Preparing; + StartPreparing(); + } + else if (Stage == ThreadLoadingStage.FinalizationError) + { + ContinueThreadLoading(); + } + } + + private async void StartPreparing() + { + try + { + await MachineProvider.MachineOperator.StartThreadLoading(); + } + catch (Exception ex) + { + OnPreparationError(ex.Message); + } + } + + private async void ContinueThreadLoading() + { + try + { + Stage = ThreadLoadingStage.Finalizing; + await MachineProvider.MachineOperator.ContinueThreadLoading(SelectedRml.GetActiveProcessGroup().ProcessParametersTables.FirstOrDefault()); + } + catch (Exception ex) + { + OnFinalizationError(ex.Message); + } + } + + private bool CanContinue() + { + bool canContinue = false; + + if (Stage != ThreadLoadingStage.Preparing && Stage != ThreadLoadingStage.Finalizing) + { + canContinue = true; + } + + if (Stage == ThreadLoadingStage.ReadyForLoading && SelectedRml == null) + { + canContinue = false; + } + + return canContinue; + } + + private void OnPreparationError(String error) + { + Error = error; + Stage = ThreadLoadingStage.PreparationError; + } + + private void OnFinalizationError(String error) + { + Error = error; + Stage = ThreadLoadingStage.FinalizationError; + } + + private void Abort() + { + Cancel(); + } + + public async override void OnShow() + { + base.OnShow(); + + LogManager.Log("Loading site RMLS..."); + + List rmls = new List(); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + rmls = await new RmlsCollectionBuilder(db).SetAll().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).WithActiveParametersGroup().BuildListAsync(); + } + + var selectedRml = rmls.SingleOrDefault(x => x.Guid == _settings.LoadedRmlGuid); + + Rmls = rmls; + SelectedRml = selectedRml != null ? selectedRml : rmls.FirstOrDefault(); + } + + protected override void Cancel() + { + CleanUp(); + base.Cancel(); + } + + protected override void Accept() + { + CleanUp(); + base.Accept(); + } + + private void CleanUp() + { + MachineProvider.MachineOperator.ThreadLoadingStatusChanged -= MachineOperator_ThreadLoadingStatusChanged; + MachineProvider.MachineDisconnected -= MachineProvider_MachineDisconnected; + + if (SelectedRml != null) + { + _settings.LoadedRmlGuid = SelectedRml.Guid; + _settings.Save(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml index 231f5dabb..6f70b954d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml @@ -6,21 +6,24 @@ xmlns:local="clr-namespace:Tango.PPC.UI.Dialogs" xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" mc:Ignorable="d" - Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="550" Height="450" d:DataContext="{d:DesignInstance Type=local:UpdateFromFileViewVM, IsDesignTimeCreatable=False}"> + Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="570" Height="700" d:DataContext="{d:DesignInstance Type=local:UpdateFromFileViewVM, IsDesignTimeCreatable=False}"> - - CANCEL - UPDATE - + + CANCEL + UPDATE + - UPDATE PACKAGE + Tango Update Package The selected file contains a software update package. Press 'UPDATE' to start updating your system. - - Version - + + Application: + + + Firmware: + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs index b9e876809..a38b0431a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs @@ -3,12 +3,18 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.PPC.Common.Publish; using Tango.SharedUI; namespace Tango.PPC.UI.Dialogs { public class UpdateFromFileViewVM : DialogViewVM { - public String Version { get; set; } + public PublishInfo PublishInfo { get; set; } + + public String FirmwareVersion + { + get { return PublishInfo.GetFirmwareVersion(); } + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.png new file mode 100644 index 000000000..b4b50e4ac Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.png new file mode 100644 index 000000000..a0dc77f92 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.png new file mode 100644 index 000000000..ba351ee66 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.png new file mode 100644 index 000000000..9aa8e2db6 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.png new file mode 100644 index 000000000..158bab095 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpg new file mode 100644 index 000000000..3b2f58620 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpg new file mode 100644 index 000000000..a2f5ae568 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpg new file mode 100644 index 000000000..6069e9c29 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpg new file mode 100644 index 000000000..7588d68e2 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPG new file mode 100644 index 000000000..68921f1ca Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPG new file mode 100644 index 000000000..a8b5d9ba4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPG new file mode 100644 index 000000000..407f1eae6 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPG new file mode 100644 index 000000000..52063b213 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpg new file mode 100644 index 000000000..68921f1ca Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpg new file mode 100644 index 000000000..a8b5d9ba4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpg new file mode 100644 index 000000000..407f1eae6 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpg new file mode 100644 index 000000000..52063b213 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpg new file mode 100644 index 000000000..fa2c8312d Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPG new file mode 100644 index 000000000..8d58771d4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg new file mode 100644 index 000000000..81aa412ec Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPG new file mode 100644 index 000000000..68921f1ca Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPG new file mode 100644 index 000000000..a8b5d9ba4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPG new file mode 100644 index 000000000..9f200198d Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPG new file mode 100644 index 000000000..fa2c8312d Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPG b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPG new file mode 100644 index 000000000..7956b0695 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPG differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg new file mode 100644 index 000000000..4ca8677cd Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg new file mode 100644 index 000000000..f41898bc1 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpg new file mode 100644 index 000000000..212edc547 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpg new file mode 100644 index 000000000..d8da5726d Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpg new file mode 100644 index 000000000..a8b5d9ba4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpg new file mode 100644 index 000000000..86dd6f397 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpg new file mode 100644 index 000000000..9d36f3642 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpg b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpg new file mode 100644 index 000000000..6ac67aa46 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpg differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.png new file mode 100644 index 000000000..3a712af49 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.png new file mode 100644 index 000000000..15be3b163 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.png new file mode 100644 index 000000000..af3ea4850 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gif b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gif new file mode 100644 index 000000000..793007cc4 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gif differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.png new file mode 100644 index 000000000..277599070 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gif b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gif new file mode 100644 index 000000000..dd07593e2 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gif differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gif b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gif new file mode 100644 index 000000000..867107140 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gif differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gif b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gif new file mode 100644 index 000000000..f435d38d1 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gif differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.png new file mode 100644 index 000000000..e60aaf425 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gif b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gif new file mode 100644 index 000000000..b6a974084 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gif differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.png new file mode 100644 index 000000000..5d536e7ae Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.png new file mode 100644 index 000000000..9bbea3368 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.png b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.png new file mode 100644 index 000000000..c95dfa015 Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/InternalModule.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/InternalModule.cs new file mode 100644 index 000000000..e960fa020 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/InternalModule.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.BL.Enumerations; +using Tango.PPC.Common; +using Tango.PPC.UI.Views; + +namespace Tango.PPC.UI +{ + [PPCModule(100)] + public class InternalModule : PPCModuleBase + { + public InternalModule() + { + IsVisibleInMenu = false; + } + + /// + /// Gets the module name. + /// + public override string Name + { + get + { + return "Internal"; + } + } + + /// + /// Gets the module description. + /// + public override string Description + { + get + { + return "Internal Module"; + } + } + + /// + /// Gets the module cover image. + /// + public override BitmapSource Image + { + get + { + return null; + } + } + + /// + /// Gets the module entry point view type. + /// + public override Type MainViewType + { + get + { + return typeof(InternalModuleView); + } + } + + /// + /// Gets the permission required to see and load this module. + /// + public override Permissions Permission + { + get + { + return Permissions.RunPPC; + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public override void Dispose() + { + //Dispose module here... + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/MainWindow.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/MainWindow.xaml.cs index b90a1afff..bf621ff2e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/MainWindow.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/MainWindow.xaml.cs @@ -61,6 +61,12 @@ namespace Tango.PPC.UI has_touch = true; } } + +#if !DEBUG + ForceTouch(); + has_touch = true; +#endif + #endif if (!has_touch) @@ -72,7 +78,7 @@ namespace Tango.PPC.UI gridMain.Height = 1280; viewBox.Child = gridMain; LockAspectRatio(); - this.SizeChanged += (x, y) => + this.SizeChanged += (x, y) => { LockAspectRatio(); }; @@ -81,6 +87,18 @@ namespace Tango.PPC.UI Closing += MainWindow_Closing; } + private void ForceTouch() + { + WindowStyle = WindowStyle.None; + ResizeMode = ResizeMode.NoResize; + WindowStartupLocation = WindowStartupLocation.Manual; + Topmost = false; // sure? + Left = 0; + Top = 0; + Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; + Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height; + } + protected override void OnSourceInitialized(EventArgs e) { //var hwndSource = PresentationSource.FromVisual(this) as HwndSource; @@ -98,6 +116,7 @@ namespace Tango.PPC.UI private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { + e.Cancel = true; TangoIOC.Default.GetInstance().ShutDown(); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs new file mode 100644 index 000000000..bbabed225 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.BL.Entities; +using Tango.Logging; +using Tango.PPC.Common.Authentication; +using Tango.PPC.Common.Modules; +using Tango.PPC.Common; +using Tango.PPC.Jobs; +using System.Windows.Data; +using Tango.Core.DI; + +namespace Tango.PPC.UI.Modules +{ + /// + /// Represents the default PPC . + /// + /// + /// + public class DefaultPPCModuleLoader : ExtendedObject, IPPCModuleLoader + { + private static object _syncObject = new object(); + private IAuthenticationProvider _authenticationProvider; + private bool _loaded; + + /// + /// Occurs when the user has logged in and user modules are loaded. + /// + public event EventHandler ModulesLoaded; + + /// + /// Initializes a new instance of the class. + /// + /// The authentication provider. + public DefaultPPCModuleLoader(IAuthenticationProvider authenticationProvider) + { + _authenticationProvider = authenticationProvider; + AllModules = new ObservableCollection(); + UserModules = new ObservableCollection(); + + BindingOperations.EnableCollectionSynchronization(UserModules, _syncObject); + + _authenticationProvider.CurrentUserChanged += _authenticationProvider_CurrentUserChanged; + } + + /// + /// Handles the authentication provider user changed event. + /// + /// The sender. + /// The e. + private void _authenticationProvider_CurrentUserChanged(object sender, User e) + { + LoadModules(); + } + + private ObservableCollection _allModules; + /// + /// Gets all loaded modules. + /// + public ObservableCollection AllModules + { + get { return _allModules; } + private set { _allModules = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection _userModules; + /// + /// Gets all the user permitted modules. + /// + public ObservableCollection UserModules + { + get { return _userModules; } + private set { _userModules = value; RaisePropertyChangedAuto(); } + } + + /// + /// Loads all available PPC modules. + /// + public void LoadModules() + { + if (!_loaded) + { + //Preloaded + LogManager.Log(String.Format("Loading module '{0}'...", nameof(JobsModule))); + AllModules.Add(new JobsModule()); + //Preloaded + + AllModules.Clear(); + string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + foreach (var file in Directory.GetFiles(assemblyFolder, "*.dll").Where(x => x.Contains("Tango.PPC"))) + { + try + { + Assembly moduleAssembly = null; + moduleAssembly = Assembly.LoadFrom(file); + + if (moduleAssembly != null) + { + foreach (var moduleType in moduleAssembly.GetLoadableTypes().Where(x => !x.IsInterface && typeof(IPPCModule).IsAssignableFrom(x) && !x.IsAbstract)) + { + if (!AllModules.ToList().Exists(x => x.GetType() == moduleType)) + { + try + { + LogManager.Log(String.Format("Loading module '{0}'...", moduleType.Name)); + var module = Activator.CreateInstance(moduleType) as IPPCModule; + AllModules.Add(module); + } + catch (Exception ex) + { + LogManager.Log(ex, "Could not load module " + moduleType.Name); + } + } + } + } + } + catch { } + } + + _loaded = true; + } + + AllModules = AllModules.OrderBy(x => x.GetType().GetCustomAttribute().Index).ToObservableCollection(); + + UserModules.Clear(); + + if (_authenticationProvider.AuthenticationRequired && _authenticationProvider.CurrentUser != null) + { + UserModules = AllModules.Where(x => _authenticationProvider.CurrentUser.HasPermission(x.Permission)).ToObservableCollection(); + } + else if (!_authenticationProvider.AuthenticationRequired) + { + UserModules = AllModules.ToObservableCollection(); + } + + ModulesLoaded?.Invoke(this, new EventArgs()); + } + + /// + /// Gets the PPC module of type T if loaded. + /// + /// + /// + public T GetPPCModule() where T : IPPCModule + { + return UserModules.OfType().FirstOrDefault(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs deleted file mode 100644 index feb7e371f..000000000 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Tango.Core; -using Tango.BL.Entities; -using Tango.Logging; -using Tango.PPC.Common.Authentication; -using Tango.PPC.Common.Modules; -using Tango.PPC.Common; -using Tango.PPC.Jobs; -using System.Windows.Data; -using Tango.Core.DI; - -namespace Tango.PPC.UI.Modules -{ - /// - /// Represents the default PPC . - /// - /// - /// - public class DefaultPPCModuleLoader : ExtendedObject, IPPCModuleLoader - { - private static object _syncObject = new object(); - private IAuthenticationProvider _authenticationProvider; - private bool _loaded; - - /// - /// Occurs when the user has logged in and user modules are loaded. - /// - public event EventHandler ModulesLoaded; - - /// - /// Initializes a new instance of the class. - /// - /// The authentication provider. - public DefaultPPCModuleLoader(IAuthenticationProvider authenticationProvider) - { - _authenticationProvider = authenticationProvider; - AllModules = new ObservableCollection(); - UserModules = new ObservableCollection(); - - BindingOperations.EnableCollectionSynchronization(UserModules, _syncObject); - - _authenticationProvider.CurrentUserChanged += _authenticationProvider_CurrentUserChanged; - } - - /// - /// Handles the authentication provider user changed event. - /// - /// The sender. - /// The e. - private void _authenticationProvider_CurrentUserChanged(object sender, User e) - { - LoadModules(); - } - - private ObservableCollection _allModules; - /// - /// Gets all loaded modules. - /// - public ObservableCollection AllModules - { - get { return _allModules; } - private set { _allModules = value; RaisePropertyChangedAuto(); } - } - - private ObservableCollection _userModules; - /// - /// Gets all the user permitted modules. - /// - public ObservableCollection UserModules - { - get { return _userModules; } - private set { _userModules = value; RaisePropertyChangedAuto(); } - } - - /// - /// Loads all available PPC modules. - /// - public void LoadModules() - { - if (!_loaded) - { - //Preloaded - LogManager.Log(String.Format("Loading module '{0}'...", nameof(JobsModule))); - AllModules.Add(new JobsModule()); - //Preloaded - - AllModules.Clear(); - string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - foreach (var file in Directory.GetFiles(assemblyFolder, "*.dll").Where(x => x.Contains("Tango.PPC"))) - { - try - { - Assembly moduleAssembly = null; - moduleAssembly = Assembly.LoadFrom(file); - - if (moduleAssembly != null) - { - foreach (var moduleType in moduleAssembly.GetTypes().Where(x => !x.IsInterface && typeof(IPPCModule).IsAssignableFrom(x) && !x.IsAbstract)) - { - if (!AllModules.ToList().Exists(x => x.GetType() == moduleType)) - { - try - { - LogManager.Log(String.Format("Loading module '{0}'...", moduleType.Name)); - var module = Activator.CreateInstance(moduleType) as IPPCModule; - AllModules.Add(module); - } - catch (Exception ex) - { - LogManager.Log(ex, "Could not load module " + moduleType.Name); - } - } - } - } - } - catch { } - } - - _loaded = true; - } - - AllModules = AllModules.OrderBy(x => x.GetType().GetCustomAttribute().Index).ToObservableCollection(); - - UserModules.Clear(); - - if (_authenticationProvider.CurrentUser != null) - { - UserModules = AllModules.Where(x => _authenticationProvider.CurrentUser.HasPermission(x.Permission)).ToObservableCollection(); - } - - ModulesLoaded?.Invoke(this, new EventArgs()); - } - - /// - /// Gets the PPC module of type T if loaded. - /// - /// - /// - public T GetPPCModule() where T : IPPCModule - { - return UserModules.OfType().FirstOrDefault(); - } - } -} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs index fe3cabcc1..d247ab23c 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -12,6 +13,7 @@ using Tango.Core.Commands; using Tango.PPC.Common; using Tango.PPC.Common.Modules; using Tango.PPC.Common.Navigation; +using Tango.PPC.Common.Notifications; using Tango.PPC.Common.Threading; using Tango.PPC.UI.Views; using Tango.SharedUI.Controls; @@ -24,23 +26,49 @@ namespace Tango.PPC.UI.Navigation /// public class DefaultNavigationManager : ExtendedObject, INavigationManager { - private event Action NavigationCycleCompleted; + //private event Action NavigationCycleCompleted; + //private event Action BeforeNavigationCycleCompleted; + private class AwaitingVMResult + { + public PPCViewModel FromVM { get; set; } + public PPCViewModel ToVM { get; set; } + public Action Action { get; set; } + } + private List _awaitingVMResults; private IDispatcherProvider _dispatcherProvider; private IPPCModuleLoader _moduleLoader; - private Object _currentVM; + private INotificationProvider _notificationProvider; private String _lastFullPath; private bool _preventHistory; private bool _navigating_back; + public event EventHandler CurrentVMChanged; + private Stack _navigationHistory; + private Object _currentVM; /// /// Gets the current view model. /// public PPCViewModel CurrentVM { - get { return _currentVM as PPCViewModel; } + set + { + var previous = _currentVM; + _currentVM = value; + + var vm = _currentVM as PPCViewModel; + + if (_currentVM != previous && vm != null) + { + CurrentVMChanged?.Invoke(this, vm); + } + } + get + { + return _currentVM as PPCViewModel; + } } private IPPCModule _currentModule; @@ -67,10 +95,13 @@ namespace Tango.PPC.UI.Navigation /// Initializes a new instance of the class. /// /// The module loader. - public DefaultNavigationManager(IPPCModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider) + public DefaultNavigationManager(IPPCModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider, INotificationProvider notificationProvider) { + IsBackEnabled = true; + _awaitingVMResults = new List(); _navigationHistory = new Stack(); _moduleLoader = moduleLoader; + _notificationProvider = notificationProvider; NavigateToCommand = new RelayCommand(async (x) => await NavigateTo(x)); NavigateBackCommand = new RelayCommand(async () => await NavigateBack()); @@ -113,7 +144,19 @@ namespace Tango.PPC.UI.Navigation { LogManager.Log($"Navigating to: {view.ToString()}..."); - MainView.Instance.NavigationControl.NavigateTo(view.ToString()); + + var fromView = MainView.Instance.NavigationControl.SelectedElement; + FrameworkElement toView = null; + + toView = MainView.Instance.NavigationControl.NavigateTo(view.ToString(), (Action)(() => + { + CurrentVM = toView.DataContext as PPCViewModel; + NotifyOnNavigated(fromView.DataContext, toView.DataContext); + + })); + + NotifyOnBeforeNavigated(fromView.DataContext, toView.DataContext); + return Task.FromResult(true); } } @@ -173,88 +216,155 @@ namespace Tango.PPC.UI.Navigation /// Navigates to the specified module and view by full path (e.g Jobs.JobsView). /// /// The full path. - public async Task NavigateTo(String fullPath, bool pushToHistory = true) + public async Task NavigateTo(String fullPath, bool pushToHistory = true, Action onNavigating = null, Action onNavigated = null) { - String[] path = fullPath.Split('.'); - var module = _moduleLoader.UserModules.SingleOrDefault(x => x.GetType().Name == path[0] || x.Name == path[0]); + try + { + IsNavigating = true; - if (path.Length == 1 && path[0] == CurrentModule.Name) return true; + String[] path = fullPath.Split('.'); + var module = _moduleLoader.UserModules.SingleOrDefault(x => x.GetType().Name == path[0] || x.Name == path[0]); - LogManager.Log($"Navigating to: {fullPath}..."); + if (module == null) + { + await _notificationProvider.ShowError("The specified module was not loaded."); + IsNavigating = false; + return false; + } - var fromVM = _currentVM; + if (path.Length == 1 && path[0] == CurrentModule.Name) + { + IsNavigating = false; + return true; + } - if (_currentVM != null && _currentVM is INavigationBlocker) - { - if (_navigating_back) + LogManager.Log($"Navigating to: {fullPath}..."); + + var fromVM = CurrentVM; + + if (CurrentVM != null && CurrentVM is INavigationBlocker) { - if (!await (_currentVM as INavigationBlocker).OnNavigateBackRequest()) + if (_navigating_back) { - return false; + if (!await (CurrentVM as INavigationBlocker).OnNavigateBackRequest()) + { + IsNavigating = false; + return false; + } } - } - else - { - if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest()) + else { - return false; + if (!await (CurrentVM as INavigationBlocker).OnNavigateOutRequest()) + { + IsNavigating = false; + return false; + } } } - } - if (pushToHistory && _lastFullPath != null && !_preventHistory) - { - _navigationHistory.Push(_lastFullPath); - RaisePropertyChanged(nameof(CanNavigateBack)); - } - _lastFullPath = fullPath; - MainView.Instance.NavigationControl.NavigateTo(NavigationView.LayoutView.ToString()); - var navigationControl = LayoutView.Instance.NavigationControl; - CurrentModule = module; - var moduleView = navigationControl.NavigateTo(module.Name); + if (pushToHistory && _lastFullPath != null && !_preventHistory) + { + _navigationHistory.Push(_lastFullPath); + RaisePropertyChanged(nameof(CanNavigateBack)); + } - _currentVM = moduleView.DataContext; + _lastFullPath = fullPath; - if (path.Length > 1) - { - var moduleNavigation = moduleView.FindChildOffline(); + MainView.Instance.NavigationControl.NavigateTo(NavigationView.LayoutView.ToString()); + var navigationControl = LayoutView.Instance.NavigationControl; + CurrentModule = module; + var moduleView = navigationControl.NavigateTo(module.Name); + + CurrentVM = moduleView.DataContext as PPCViewModel; - if (moduleNavigation != null) + if (path.Length > 1) { - moduleNavigation.RegisterForLoadedOrNow(async (x, e) => + var moduleNavigation = moduleView.FindChildOffline(); + + if (moduleNavigation != null) { - foreach (var view in path.Skip(1)) + moduleNavigation.RegisterForLoadedOrNow(async (x, e) => { - await Task.Delay(100); - var v = moduleNavigation.NavigateTo(view); + var lastView = moduleNavigation.GetElement(path.Last()); + + if (lastView != null) + { + onNavigating?.Invoke(fromVM as PPCViewModel, lastView.DataContext as PPCViewModel); + } - if (v != null) + foreach (var view in path.Skip(1)) { - _currentVM = v.DataContext; + await Task.Delay(100); + + FrameworkElement v = null; - if (view != path.Last()) + v = moduleNavigation.NavigateTo(view, () => { - moduleNavigation = v.FindChildOffline(); + if (v != null) + { + NotifyOnNavigated(fromVM, v.DataContext); + onNavigated?.Invoke(fromVM as PPCViewModel, v.DataContext as PPCViewModel); + NotifyAwaitingVMResults(fromVM as PPCViewModel, v.DataContext as PPCViewModel); + } + }); + + NotifyOnBeforeNavigated(fromVM, v.DataContext); + + if (v != null) + { + CurrentVM = v.DataContext as PPCViewModel; + + if (view != path.Last()) + { + moduleNavigation = v.FindChildOffline(); + } + } + else + { + throw LogManager.Log(new ArgumentNullException("Could not navigate to " + fullPath)); } } - else - { - throw LogManager.Log(new ArgumentNullException("Could not navigate to " + fullPath)); - } - } + }); + } + else + { + onNavigating?.Invoke(fromVM as PPCViewModel, CurrentVM as PPCViewModel); + + NotifyOnBeforeNavigated(fromVM, CurrentVM); + + await Task.Delay(navigationControl.TransitionDuration.TimeSpan); + + NotifyOnNavigated(fromVM, CurrentVM); - NavigationCycleCompleted?.Invoke(fromVM, _currentVM); - }); + onNavigated?.Invoke(fromVM as PPCViewModel, CurrentVM as PPCViewModel); + NotifyAwaitingVMResults(fromVM as PPCViewModel, CurrentVM as PPCViewModel); + } } else { - NavigationCycleCompleted?.Invoke(fromVM, _currentVM); + NotifyOnBeforeNavigated(fromVM, CurrentVM); + + onNavigating?.Invoke(fromVM as PPCViewModel, CurrentVM as PPCViewModel); + + await Task.Delay(navigationControl.TransitionDuration.TimeSpan); + + NotifyOnNavigated(fromVM, CurrentVM); + + onNavigated?.Invoke(fromVM as PPCViewModel, CurrentVM as PPCViewModel); + NotifyAwaitingVMResults(fromVM as PPCViewModel, CurrentVM as PPCViewModel); } - } - return true; + return true; + } + catch (Exception ex) + { + IsNavigating = false; + LogManager.Log(ex, $"Error navigating to '{fullPath}'."); + await _notificationProvider.ShowError($"Error navigating to '{fullPath}'."); + return false; + } } /// @@ -267,46 +377,35 @@ namespace Tango.PPC.UI.Navigation /// The object. /// if set to true [push to history]. /// - public Task NavigateForResult(TObject obj, bool pushToHistory = true) + public async Task NavigateForResult(TObject obj, bool pushToHistory = true) where TModule : IPPCModule { TaskCompletionSource source = new TaskCompletionSource(); - var fromVM = _currentVM; - Object toVM = null; - - - Action handler = null; + var fromVM = CurrentVM; - handler = (from, to) => + await NavigateTo(typeof(TModule).Name + "." + typeof(TView).Name, pushToHistory, (from, to) => { - if (toVM == null) - { - toVM = to; - if (toVM is INavigationResultProvider) - { - (toVM as INavigationResultProvider).OnNavigationObjectReceived(obj); - } - } - else + _awaitingVMResults.Add(new AwaitingVMResult() { - if (to == fromVM && from == toVM) + FromVM = fromVM as PPCViewModel, + ToVM = to as PPCViewModel, + Action = () => { - if (from is INavigationResultProvider) + if (to is INavigationResultProvider) { - source.SetResult((from as INavigationResultProvider).GetNavigationResult()); + source.SetResult((to as INavigationResultProvider).GetNavigationResult()); } } + }); - NavigationCycleCompleted -= handler; + if (to is INavigationResultProvider) + { + (to as INavigationResultProvider).OnNavigationObjectReceived(obj); } - }; - - NavigationCycleCompleted += handler; + }); - NavigateTo(typeof(TView).Name, pushToHistory); - - return source.Task; + return await source.Task; } /// @@ -320,25 +419,13 @@ namespace Tango.PPC.UI.Navigation /// public Task NavigateWithObject(TPass obj, bool pushToHistory = true) where TModule : IPPCModule { - TaskCompletionSource source = new TaskCompletionSource(); - - Action handler = null; - - handler = (from, to) => + return NavigateTo(typeof(TModule).Name + "." + typeof(TView).Name, pushToHistory, (fromVM, toVM) => { - if (to is INavigationObjectReceiver) + if (toVM is INavigationObjectReceiver) { - (to as INavigationObjectReceiver).OnNavigatedToWithObject(obj); + (toVM as INavigationObjectReceiver).OnNavigatedToWithObject(obj); } - - NavigationCycleCompleted -= handler; - }; - - NavigationCycleCompleted += handler; - - NavigateTo(typeof(TView).Name, pushToHistory); - - return source.Task; + }); } private Task NavigateTo(Type moduleType, bool pushToHistory = true, params String[] viewPath) @@ -361,6 +448,30 @@ namespace Tango.PPC.UI.Navigation get { return _navigationHistory.Count > 0; } } + private bool _isBackEnabled; + /// + /// Gets a value indicating whether the back should be enabled. + /// + public bool IsBackEnabled + { + get { return _isBackEnabled; } + set { _isBackEnabled = value; RaisePropertyChangedAuto(); } + } + + private bool _isNavigating; + /// + /// Gets or sets a value indicating whether the navigation system is currently navigating. + /// + public bool IsNavigating + { + get { return _isNavigating; } + set + { + _isNavigating = value; + RaisePropertyChangedAuto(); + } + } + /// /// Navigates to the previous view if is true. /// @@ -370,24 +481,34 @@ namespace Tango.PPC.UI.Navigation _navigating_back = true; - String first = _navigationHistory.Pop(); - _preventHistory = true; - - - if (await NavigateTo(first)) + if (_navigationHistory.Count > 0) { - RaisePropertyChanged(nameof(CanNavigateBack)); - _preventHistory = false; - _navigating_back = false; - return true; + String first = _navigationHistory.Pop(); + _preventHistory = true; + + if (await NavigateTo(first)) + { + RaisePropertyChanged(nameof(CanNavigateBack)); + _preventHistory = false; + _navigating_back = false; + return true; + } + else + { + _navigationHistory.Push(first); + _preventHistory = false; + _navigating_back = false; + RaisePropertyChanged(nameof(CanNavigateBack)); + return false; + } } else { - _navigationHistory.Push(first); + await NavigateTo(NavigationView.HomeModule); + RaisePropertyChanged(nameof(CanNavigateBack)); _preventHistory = false; _navigating_back = false; - RaisePropertyChanged(nameof(CanNavigateBack)); - return false; + return true; } } @@ -420,5 +541,48 @@ namespace Tango.PPC.UI.Navigation RaisePropertyChanged(nameof(CanNavigateBack)); } + + private void NotifyOnBeforeNavigated(object fromVM, object toVM) + { + if (fromVM == toVM) return; + + if (fromVM is PPCViewModel) + { + (fromVM as PPCViewModel)?.OnBeforeNavigatedFrom(); + } + + if (toVM is PPCViewModel) + { + (toVM as PPCViewModel)?.OnBeforeNavigatedTo(); + } + } + + private void NotifyOnNavigated(object fromVM, object toVM) + { + IsNavigating = false; + + if (fromVM == toVM) return; + + if (fromVM is PPCViewModel) + { + (fromVM as PPCViewModel)?.OnNavigatedFrom(); + } + + if (toVM is PPCViewModel) + { + (toVM as PPCViewModel)?.OnNavigatedTo(); + (toVM as PPCViewModel)?.OnNavigatedTo(fromVM as PPCViewModel); + } + } + + private void NotifyAwaitingVMResults(PPCViewModel fromVM, PPCViewModel toVM) + { + var awaiter = _awaitingVMResults.SingleOrDefault(x => x.FromVM == toVM && x.ToVM == fromVM); + if (awaiter != null) + { + _awaitingVMResults.Remove(awaiter); + awaiter.Action(); + } + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/DefaultNotificationProvider.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/DefaultNotificationProvider.cs index 65337a892..e9de2538e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/DefaultNotificationProvider.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/DefaultNotificationProvider.cs @@ -17,6 +17,8 @@ using Tango.Touch.Controls; using Tango.SharedUI; using System.Reflection; using Tango.Core.DI; +using System.ComponentModel; +using System.Windows.Data; namespace Tango.PPC.UI.Notifications { @@ -46,6 +48,16 @@ namespace Tango.PPC.UI.Notifications /// public ObservableCollection NotificationItems { get; private set; } + /// + /// Gets the application bar items. + /// + public ObservableCollection AppBarItems { get; private set; } + + /// + /// Gets the notification items view. + /// + public ICollectionView NotificationItemsView { get; private set; } + /// /// Gets the collection of taskbar items. /// @@ -58,6 +70,10 @@ namespace Tango.PPC.UI.Notifications { NotificationsVisible = true; NotificationItems = new ObservableCollection(); + + AppBarItems = new ObservableCollection(); + CollectionViewSource.GetDefaultView(AppBarItems).SortDescriptions.Add(new SortDescription(nameof(AppBarItem.Priority), ListSortDirection.Ascending)); + TaskBarItems = new ObservableCollection(); _pendingMessageBoxes = new ConcurrentQueue>(); _pendingDialogs = new ConcurrentQueue>(); @@ -66,6 +82,9 @@ namespace Tango.PPC.UI.Notifications PopNotificationCommand = new RelayCommand((x) => PopNotification(x)); NotificationItems.EnableCrossThreadOperations(); + + NotificationItemsView = CollectionViewSource.GetDefaultView(NotificationItems); + NotificationItemsView.SortDescriptions.Add(new SortDescription(nameof(NotificationItem.Priority), ListSortDirection.Descending)); } private MessageBoxVM _currentMessageBox; @@ -322,29 +341,33 @@ namespace Tango.PPC.UI.Notifications /// public async Task ShowDialog(T datacontext, FrameworkElement view) where T : DialogViewVM { - view.DataContext = datacontext; - - TangoIOC.Default.Inject(datacontext); + TaskCompletionSource source = new TaskCompletionSource(); - view.Loaded += (_, __) => + InvokeUI(() => { view.DataContext = datacontext; - datacontext.OnShow(); - }; - TaskCompletionSource source = new TaskCompletionSource(); + TangoIOC.Default.Inject(datacontext); - datacontext.Accepted += () => { OnDialogClosed(); source.SetResult(datacontext); }; - datacontext.Canceled += () => { OnDialogClosed(); source.SetResult(datacontext); }; + view.Loaded += (_, __) => + { + view.DataContext = datacontext; + datacontext.OnShow(); + }; - if (CurrentDialog == null) - { - CurrentDialog = view; - } - else - { - _pendingDialogs.Enqueue(new PendingNotification(new DialogAndView(datacontext, view), source)); - } + datacontext.Accepted += () => { OnDialogClosed(); source.SetResult(datacontext); }; + datacontext.Canceled += () => { OnDialogClosed(); source.SetResult(datacontext); }; + + if (CurrentDialog == null) + { + CurrentDialog = view; + } + else + { + _pendingDialogs.Enqueue(new PendingNotification(new DialogAndView(datacontext, view), source)); + } + + }); var result = await source.Task; return result as T; @@ -376,23 +399,31 @@ namespace Tango.PPC.UI.Notifications /// public Task ShowDialog(T datacontext) where T : DialogViewVM { - var callingAssembly = datacontext.GetType().Assembly; - String viewName = datacontext.GetType().FullName.Replace("VM", ""); - var viewType = callingAssembly.GetType(viewName); + TaskCompletionSource source = new TaskCompletionSource(); - if (viewType == null) + InvokeUI(async () => { - throw new NullReferenceException("View type for " + datacontext.GetType().Name + " could not be found!"); - } + var callingAssembly = datacontext.GetType().Assembly; + String viewName = datacontext.GetType().FullName.Replace("VM", ""); + var viewType = callingAssembly.GetType(viewName); - var view = Activator.CreateInstance(viewType) as FrameworkElement; + if (viewType == null) + { + throw new NullReferenceException("View type for " + datacontext.GetType().Name + " could not be found!"); + } - if (view == null) - { - throw new NullReferenceException("The view " + viewType.ToString() + " is not of type framework element."); - } + var view = Activator.CreateInstance(viewType) as FrameworkElement; - return ShowDialog(datacontext, view); + if (view == null) + { + throw new NullReferenceException("The view " + viewType.ToString() + " is not of type framework element."); + } + + T result = await ShowDialog(datacontext, view); + source.SetResult(result); + }); + + return source.Task; } /// @@ -404,7 +435,15 @@ namespace Tango.PPC.UI.Notifications /// public Task ShowDialog() where T : DialogViewVM { - return ShowDialog(Activator.CreateInstance()); + TaskCompletionSource source = new TaskCompletionSource(); + + InvokeUI(async () => + { + var result = await ShowDialog(Activator.CreateInstance()); + source.SetResult(result); + }); + + return source.Task; } /// @@ -442,22 +481,12 @@ namespace Tango.PPC.UI.Notifications /// public bool IsInGlobalBusyState { get; private set; } - private AppBarItem _currentAppBarItem; - /// - /// Gets the current application bar item. - /// - public AppBarItem CurrentAppBarItem - { - get { return _currentAppBarItem; } - set { _currentAppBarItem = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasAppBarItem)); } - } - /// /// Gets a value indicating whether this instance has application bar item. /// - public bool HasAppBarItem + public bool HasAppBarItems { - get { return CurrentAppBarItem != null; } + get { return AppBarItems.Count > 0; } } /// @@ -468,8 +497,9 @@ namespace Tango.PPC.UI.Notifications public AppBarItem PushAppBarItem(AppBarItem appBarItem) { LogManager.Log($"Pushing AppBarItem '{appBarItem.GetType().Name}'."); - CurrentAppBarItem = appBarItem; + AppBarItems.Add(appBarItem); appBarItem.RemoveAction = () => PopAppBarItem(appBarItem); + RaisePropertyChanged(nameof(HasAppBarItems)); return appBarItem; } @@ -478,9 +508,9 @@ namespace Tango.PPC.UI.Notifications /// /// /// - public AppBarItem PushAppBarItem() where T : AppBarItem + public T PushAppBarItem() where T : AppBarItem { - return PushAppBarItem(Activator.CreateInstance()); + return PushAppBarItem(Activator.CreateInstance()) as T; } /// @@ -489,8 +519,12 @@ namespace Tango.PPC.UI.Notifications /// The application bar item. public void PopAppBarItem(AppBarItem appBarItem) { - LogManager.Log($"Popping out AppBarItem '{appBarItem.GetType().Name}'."); - CurrentAppBarItem = null; + InvokeUI(() => + { + LogManager.Log($"Popping out AppBarItem '{appBarItem.GetType().Name}'."); + AppBarItems.Remove(appBarItem); + RaisePropertyChanged(nameof(HasAppBarItems)); + }); } /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItem.cs new file mode 100644 index 000000000..9e336f276 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItem.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common.Notifications; + +namespace Tango.PPC.UI.Notifications.NotificationItems +{ + /// + /// Represents a simple text message notification item which can be inserted into the application notifications panel. + /// + /// + public class UpdateAvailableNotificationItem : NotificationItem + { + /// + /// Initializes a new instance of the class. + /// + public UpdateAvailableNotificationItem() + { + CanClose = true; + } + + private String _version; + /// + /// Gets or sets the message. + /// + public String Version + { + get { return _version; } + set { _version = value; RaisePropertyChangedAuto(); } + } + + private bool _isDatabaseUpdate; + /// + /// Gets or sets a value indicating whether this instance is database update. + /// + public bool IsDatabaseUpdate + { + get { return _isDatabaseUpdate; } + set { _isDatabaseUpdate = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the view type. + /// + public override Type ViewType + { + get { return typeof(UpdateAvailableNotificationItemView); } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml new file mode 100644 index 000000000..1d4dd6fc7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + Version + + is available! + Tap to start updating your system. + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml.cs new file mode 100644 index 000000000..791d40540 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Notifications.NotificationItems +{ + /// + /// Represents the view. + /// + /// + /// + public partial class UpdateAvailableNotificationItemView : UserControl + { + public UpdateAvailableNotificationItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs index c7351aa4a..83790a56f 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs @@ -32,6 +32,10 @@ using Tango.PPC.UI.Dialogs; using Tango.Core.Threading; using Tango.PPC.Common.Messages; using Tango.Core.ExtensionMethods; +using Tango.PPC.Common.Navigation; +using Tango.PPC.Common.Synchronization; +using Tango.Insights; +using System.Threading; namespace Tango.PPC.UI.PPCApplication { @@ -49,6 +53,7 @@ namespace Tango.PPC.UI.PPCApplication private IEventLogger _eventLogger; private IPPCModuleLoader _moduleLoader; private INotificationProvider _notificationProvider; + private IMachineDataSynchronizer _machineDataSynchronizer; private WatchDogServer _watchdogServer; private ObservablesContext _machineContext; private ActionTimer _screenLockTimer; @@ -58,6 +63,11 @@ namespace Tango.PPC.UI.PPCApplication /// public event EventHandler SystemRestartRequired; + /// + /// Occurs when the updater utility has failed to perform the last update. + /// + public event EventHandler UpdaterFailed; + /// /// Occurs when the application has started. /// @@ -93,10 +103,15 @@ namespace Tango.PPC.UI.PPCApplication /// public bool IsShuttingDown { get; private set; } + private bool _isInTechnicianMode; /// /// Gets a value indicating whether the application is in technician mode. /// - public bool IsInTechnicianMode { get; private set; } + public bool IsInTechnicianMode + { + get { return _isInTechnicianMode; } + set { _isInTechnicianMode = value; RaisePropertyChangedAuto(); } + } /// /// Gets the application version. @@ -125,6 +140,16 @@ namespace Tango.PPC.UI.PPCApplication /// public DateTime StartUpDate { get; private set; } + /// + /// Gets a value indicating whether an update has occurred before the application started. + /// + public bool IsAfterUpdate { get; private set; } + + /// + /// Gets a value indicating whether the updater utility has failed to perform the last update. + /// + public bool IsUpdateFailed { get; private set; } + private bool _isScreenLocked; /// /// Gets or sets a value indicating whether the screen is currently locked. @@ -135,16 +160,35 @@ namespace Tango.PPC.UI.PPCApplication set { _isScreenLocked = value; RaisePropertyChangedAuto(); } } + /// + /// Gets the firmware version. + /// + public Version FirmwareVersion + { + get + { + return Version.Parse(SettingsManager.Default.GetOrCreate().FirmwareVersion); + } + } + + /// + /// Gets or sets the application folder. + /// + public String StartPath { get; private set; } + /// /// Initializes a new instance of the class. /// - public DefaultPPCApplicationManager(IMachineProvider machineProvider, IDispatcherProvider dispatcherProvider, IEventLogger eventLogger, IPPCModuleLoader moduleLoader, INotificationProvider notificationProvider) + public DefaultPPCApplicationManager(IMachineProvider machineProvider, IDispatcherProvider dispatcherProvider, IEventLogger eventLogger, IPPCModuleLoader moduleLoader, INotificationProvider notificationProvider, IMachineDataSynchronizer machineDataSynchronizer) { + StartPath = AssemblyHelper.GetCurrentAssemblyFolder(); + _notificationProvider = notificationProvider; _machineProvider = machineProvider; _dispatcher = dispatcherProvider; _eventLogger = eventLogger; _moduleLoader = moduleLoader; + _machineDataSynchronizer = machineDataSynchronizer; if (!DesignMode) { @@ -210,11 +254,15 @@ namespace Tango.PPC.UI.PPCApplication { LogManager.Log("Application started with '-update_ok' startup arguments. The application has been successfully updated."); - if (settings.ApplicationState == ApplicationStates.PreSetup) + if (settings.ApplicationState == ApplicationStates.PreSetup || settings.ApplicationState == ApplicationStates.FactoryRestore) { isAfterSetup = true; LogManager.Log("System restart is required."); } + else + { + IsAfterUpdate = true; + } settings.ApplicationState = ApplicationStates.Ready; settings.Save(); @@ -226,13 +274,27 @@ namespace Tango.PPC.UI.PPCApplication } } + if (App.StartupArgs.Contains("-update_failed")) + { + LogManager.Log("Application started with '-update_failed' startup arguments. The updater utility has failed."); + + IsUpdateFailed = true; + + settings.ApplicationState = ApplicationStates.Ready; + settings.Save(); + UpdaterFailed?.Invoke(this, new EventArgs()); + return; + } + if (settings.ApplicationState == ApplicationStates.Ready) { LogManager.Log("Initializing ObservablesStaticCollections..."); ObservablesStaticCollections.Instance.Initialize(); LogManager.Log("Loading machine from database..."); _machineContext = ObservablesContext.CreateDefault(); - _machine = new MachineBuilder(_machineContext).SetFirst().WithVersion().WithSettings().WithOrganization().WithConfiguration().WithSpools().WithCats().Build(); + _machine = new MachineBuilder(_machineContext).SetFirst().WithVersion().WithOrganization().WithConfiguration().WithSpools().WithCats().Build(); + + } initialized = true; @@ -276,7 +338,6 @@ namespace Tango.PPC.UI.PPCApplication { LogManager.Log($"Raising {nameof(ApplicationStarted)} event..."); - _eventLogger.Log(EventTypes.APPLICATION_STARTED, "Application Started!"); ApplicationStarted?.Invoke(this, new EventArgs()); LogManager.Log("Invoking PPC view models OnApplicationStarted methods..."); @@ -290,6 +351,8 @@ namespace Tango.PPC.UI.PPCApplication } } + var internalModules = this.GetType().Assembly.GetTypes().Where(xx => typeof(PPCModuleBase).IsAssignableFrom(xx)).ToList(); + LogManager.Log("Waiting for IPPCModuleLoader instance injection..."); TangoIOC.Default.GetInstanceWhenAvailable((loader) => { @@ -304,12 +367,32 @@ namespace Tango.PPC.UI.PPCApplication { if (!Views.LayoutView.Instance.NavigationControl.Elements.ToList().Exists(m => m.GetType() == module.MainViewType)) { - LogManager.Log("Loading module view " + module.Name + "..."); - FrameworkElement view = Activator.CreateInstance(module.MainViewType) as FrameworkElement; - SharedUI.Controls.NavigationControl.SetNavigationName(view, module.Name); - Views.LayoutView.Instance.NavigationControl.Elements.Add(view); + try + { + LogManager.Log("Loading module view " + module.Name + "..."); + FrameworkElement view = Activator.CreateInstance(module.MainViewType) as FrameworkElement; + SharedUI.Controls.NavigationControl.SetNavigationName(view, module.Name); + Views.LayoutView.Instance.NavigationControl.Elements.Add(view); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error loading module view for module {module.Name}."); + } } } + + //Adding internal modules. + LogManager.Log("Loading internal modules..."); + foreach (var type in internalModules) + { + var module = Activator.CreateInstance(type) as IPPCModule; + LogManager.Log("Loading module view " + module.Name + "..."); + FrameworkElement view = Activator.CreateInstance(module.MainViewType) as FrameworkElement; + SharedUI.Controls.NavigationControl.SetNavigationName(view, module.Name); + Views.LayoutView.Instance.NavigationControl.Elements.Add(view); + _moduleLoader.AllModules.Add(module); + _moduleLoader.UserModules.Add(module); + } }); LogManager.Log($"{loader.UserModules.Count} modules loaded."); @@ -334,6 +417,9 @@ namespace Tango.PPC.UI.PPCApplication LogManager.Log("Initializing Machine Provider..."); _machineProvider.Init(_machine, _machineContext); + LogManager.Log("Starting Machine Data Synchronizer..."); + _machineDataSynchronizer.IsEnabled = true; + LogManager.Log("Applications initialization completed!"); LogManager.Log("Checking for un-notified PPC view models..."); @@ -350,6 +436,7 @@ namespace Tango.PPC.UI.PPCApplication _dispatcher.Invoke(() => { LogManager.Log($"Invoking {nameof(ApplicationReady)} event."); + _eventLogger.Log(EventTypes.APPLICATION_STARTED, "Application Started!"); ApplicationReady?.Invoke(this, new EventArgs()); LogManager.Log("Notifying view models about application ready..."); @@ -390,7 +477,7 @@ namespace Tango.PPC.UI.PPCApplication /// /// Shutdown the application. /// - public void ShutDown() + public async void ShutDown() { if (IsShuttingDown) return; @@ -408,13 +495,22 @@ namespace Tango.PPC.UI.PPCApplication } catch { } + try + { + await FinalizeApplication(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred on application shutdown finalization."); + } + Environment.Exit(0); } /// /// Restarts the application. /// - public void Restart() + public async void Restart() { if (IsShuttingDown) return; @@ -422,13 +518,28 @@ namespace Tango.PPC.UI.PPCApplication try { + _dispatcher.Invoke(() => + { + var nav = TangoIOC.Default.GetInstance(); + if (nav != null) + { + nav.NavigateTo(NavigationView.RestartingView); + } + }); + LogManager.Log("Restarting the application..."); + await Task.Delay(8000); + _watchdogServer.Dispose(); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { - vm.OnApplicationShuttingDown(); + try + { + vm.OnApplicationShuttingDown(); + } + catch { } } } catch { } @@ -442,6 +553,15 @@ namespace Tango.PPC.UI.PPCApplication } catch { } + try + { + await FinalizeApplication(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred on application shutdown finalization."); + } + Process.Start(Application.ResourceAssembly.Location); Environment.Exit(0); } @@ -449,25 +569,82 @@ namespace Tango.PPC.UI.PPCApplication /// /// Runs the updater utility and exits the application. /// - public void UpdateApplication(String updaterPath, String arguments) + public async void UpdateApplication(String updaterPath, String arguments) { if (IsShuttingDown) return; IsShuttingDown = true; + LogManager.Log("Restarting application for update..."); + try { - _watchdogServer.Dispose(); + LogManager.Log("Navigating to restart view..."); + _dispatcher.Invoke(() => + { + var nav = TangoIOC.Default.GetInstance(); + if (nav != null) + { + nav.NavigateTo(NavigationView.RestartingView); + } + }); + LogManager.Log("Waiting 2 seconds..."); + await Task.Delay(2000); + + try + { + LogManager.Log("Disposing watch dog..."); + _watchdogServer.Dispose(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disposing watch dog."); + } + + LogManager.Log("Raising OnApplicationShutDown for all view models..."); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { - vm.OnApplicationShuttingDown(); + try + { + vm.OnApplicationShuttingDown(); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error on {vm.GetType().Name}.OnApplicationShutDown()."); + } } } catch { } + try + { + LogManager.Log("Saving application settings..."); + SettingsManager.Default.GetOrCreate().PreviousApplicationVersion = Version.ToString(); + SettingsManager.Default.Save(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving application settings."); + } + + try + { + await FinalizeApplication(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred on application shutdown finalization."); + } + LogManager.Log($"Executing '{updaterPath}' with arguments '{arguments}'..."); - Process.Start(updaterPath, arguments); + + Process p = new Process(); + p.StartInfo.FileName = updaterPath; + p.StartInfo.Arguments = arguments; + p.StartInfo.LoadUserProfile = true; + p.StartInfo.UseShellExecute = true; + p.Start(); LogManager.Log("Terminating application..."); Environment.Exit(0); @@ -546,5 +723,48 @@ namespace Tango.PPC.UI.PPCApplication { IsScreenLocked = true; } + + public void SetWindowState(WindowState state) + { + InvokeUI(() => + { + MainWindow.Instance.WindowState = state; + }); + } + + private Task FinalizeApplication() + { + LogManager.Log("Finalizing application..."); + + return LimitedTimeTask.StartNew(() => + { + try + { + LogManager.Log("Flushing machine events..."); + _eventLogger.Log(EventTypes.APPLICATION_TERMINATED, "User Interface Terminated."); + _eventLogger.FlushAll(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error flushing machine events."); + } + + try + { + LogManager.Log("Disposing insights manager (max 40 seconds to complete)..."); + Stopwatch watch = new Stopwatch(); + watch.Start(); + var frame = InsightsFrame.CreateEmpty(DateTime.UtcNow); + InsightsManager.Default.InsertFrame(frame); + InsightsManager.Default.Dispose(); + watch.Stop(); + LogManager.Log($"Insights manager disposed after {(int)watch.Elapsed.TotalSeconds} seconds."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disposing insights manager."); + } + }, TimeSpan.FromSeconds(40)); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Printing/DefaultPrintingManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Printing/DefaultPrintingManager.cs index 56ec2fa7e..1f2895f26 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Printing/DefaultPrintingManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Printing/DefaultPrintingManager.cs @@ -259,7 +259,11 @@ namespace Tango.PPC.UI.Printing { throw new InvalidOperationException("Error starting job. Color is out of range."); } - if (job.Segments.SelectMany(x => x.BrushStops).Any(x => x.BrushColorSpace == ColorSpaces.Catalog && x.ColorCatalogsItem == null)) + if (job.Segments.SelectMany(x => x.BrushStops).Any(x => x.IsLiquidVolumesOutOfRange)) + { + throw new InvalidOperationException("Error starting job. Total ink volume is out of range."); + } + if (job.Segments.SelectMany(x => x.BrushStops).Any(x => x.BrushColorSpace == ColorSpaces.Catalog && x.ColorCatalogsItem == null && !x.IsTransparent && !x.IsWhite)) { throw new InvalidOperationException("Error starting job. Please select a catalog color."); } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs index 02099e659..0540cfa9b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs @@ -8,4 +8,4 @@ using System.Windows; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Tango PPC Application")] -[assembly: AssemblyVersion("1.0.50.0")] +[assembly: AssemblyVersion("1.2.9.0")] diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs new file mode 100644 index 000000000..1b8780f91 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.Core.Threading; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Common.RemoteActions; +using Tango.PPC.Common.Threading; +using Tango.PPC.Shared.RemoteActions; + +namespace Tango.PPC.UI.RemoteActions +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteActionsService : IRemoteActionsService, IExternalBridgeRequestHandler + { + [TangoInject] + private IDispatcherProvider DispatcherProvider { get; set; } + + public DefaultRemoteActionsService(IPPCExternalBridgeService externalBridge) + { + externalBridge.RegisterRequestHandler(this); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do nothing. + } + + [ExternalBridgeRequestHandlerMethod(typeof(SimulateApplicationExceptionRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnSimulateApplicationExceptionRequest(SimulateApplicationExceptionRequest request, String token, ExternalBridgeReceiver receiver) + { + await receiver.SendGenericResponse(new SimulateApplicationExceptionResponse(), token); + + Thread.Sleep(500); + + DispatcherProvider.Invoke(() => + { + if (request.CrashApplication) + { + App.ExceptionTrapper.Disable(); + throw new OutOfMemoryException("This is a simulated exception to cause the application to crash."); + } + else + { + throw new ApplicationException("This is a simulated exception to cause an unhandled application error."); + } + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Resources/Colors.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Resources/Colors.xaml index f0e872285..d6cd842d5 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Resources/Colors.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Resources/Colors.xaml @@ -13,4 +13,6 @@ + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj index c5045abf3..081d79f3e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj @@ -114,12 +114,23 @@ GlobalVersionInfo.cs + + + + PowerUpAppBarItemView.xaml + + + PowerOffAppBarItemView.xaml + WiFiAuthenticationView.xaml + + MachineStatusControl.xaml + @@ -129,6 +140,21 @@ InsufficientLiquidQuantityView.xaml + + SafetyLevelOperationsConfirmationView.xaml + + + + ThreadBreakView.xaml + + + + ThreadLoadingView.xaml + + + PowerUpView.xaml + + ScreenLockView.xaml @@ -138,21 +164,34 @@ + + + FirmwareUpgradeFromFileView.xaml + UpdateFromFileView.xaml + - + + + + + UpdateAvailableNotificationItemView.xaml + + + + @@ -161,13 +200,18 @@ + + ExternalBridgeView.xaml + + InternalModuleView.xaml + LayoutView.xaml @@ -177,6 +221,12 @@ LoadingErrorView.xaml + + PowerOffView.xaml + + + RestartingView.xaml + LoadingView.xaml @@ -198,15 +248,43 @@ RestartingSystemView.xaml + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + Designer MSBuild:Compile @@ -218,6 +296,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -234,6 +316,10 @@ MainWindow.xaml Code + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -250,6 +336,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -262,6 +352,14 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -327,18 +425,59 @@ - - - Tango.ColorLib_v1.dll - PreserveNewest - - - Tango.ColorLib_v2.dll - PreserveNewest - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + SettingsSingleFileGenerator @@ -373,6 +512,10 @@ {4399af76-db52-4cfb-8020-6f85bdb29fd5} Tango.Explorer + + {4A55C185-3F8D-41B0-8815-C15F6213A14A} + Tango.Insights + {4206ac58-3b57-4699-8835-90bf6db01a61} Tango.Integration @@ -421,6 +564,10 @@ {6aa425c9-ea6a-4b01-aaed-5ff122e8b663} Tango.WiFi + + {bc2753f8-c0f7-48f5-a85c-149ec7a2f8c7} + Tango.PPC.BackupRestore + {8146fa0a-0725-4a1a-82e6-696c58f33a2b} Tango.PPC.BugReporting @@ -437,6 +584,10 @@ {91b70e9b-66a7-4873-ae10-400e71cf404f} Tango.PPC.MachineSettings + + {011470ac-6bd6-4366-b5f2-c82c065d4a84} + Tango.PPC.Maintenance + {04febb02-f782-4b96-b47d-f6902afa43be} Tango.PPC.Storage @@ -449,6 +600,40 @@ {0be74eee-22cb-4dba-b896-793b9e1a3ac0} Tango.PPC.Common + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + + + + {E9528353-7D41-4AA8-BBAC-D65B7FE3A0D6} + Tango.ColorLib_v4 + false + Content + PreserveNewest + + + {A3A8ADA0-C150-4E30-A60D-11F291FDBF7A} + Tango.ColorLib_v3 + false + Content + PreserveNewest + + + {1A3FC7FB-403C-4B3D-B705-28FCE11317DD} + Tango.ColorLib_v2 + false + Content + PreserveNewest + + + {CF4C66B0-CD13-4D31-8133-339A01E7E6F2} + Tango.ColorLib_v1 + false + Content + PreserveNewest + + @@ -504,6 +689,7 @@ + @@ -560,6 +746,12 @@ RD /S /Q "$(TargetDir)nb-NO\" RD /S /Q "$(TargetDir)pt-BR\" RD /S /Q "$(TargetDir)roslyn\" +RD /S /Q "$(TargetDir)ProtoCompilers\" +RD /S /Q "$(TargetDir)Packages\ProtoCompilers\" +if $(ConfigurationName) == Release RD /S /Q "$(TargetDir)x86\" +if $(ConfigurationName) == Release RD /S /Q "$(TargetDir)x64\" + +if $(ConfigurationName) == Release RD /S /Q "$(TargetDir)lib\" copy /Y "$(SolutionDir)Referenced Assemblies\mscoree.dll" "$(TargetDir)" copy /Y "$(SolutionDir)Referenced Assemblies\msvcp140d.dll" "$(TargetDir)" @@ -568,12 +760,17 @@ copy /Y "$(SolutionDir)Referenced Assemblies\vcruntime140.dll" "$(TargetDir)" copy /Y "$(SolutionDir)Referenced Assemblies\vcruntime140d.dll" "$(TargetDir)" copy /Y "$(SolutionDir)Referenced Assemblies\Microsoft.WITDataStore32.dll" "$(TargetDir)" -del "$(TargetDir)firmware_package.tfp" +if $(ConfigurationName) == Release del "$(TargetDir)firmware_package.tfp" + +if $(ConfigurationName) == Release del *.xml + +if $(ConfigurationName) == Release del WebRtc.NET.pdb -if $(ConfigurationName) == Release del *.xml +if $(ConfigurationName) == Debug copy /Y "$(TargetDir)Packages" "$(TargetDir)" - copy /Y "$(ProjectDir)Manifests\$(ConfigurationName).xml" "$(ProjectDir)app.manifest" + copy /Y "$(ProjectDir)Manifests\$(ConfigurationName).xml" "$(ProjectDir)app.manifest" + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ThreadLoading/DefaultThreadLoadingService.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ThreadLoading/DefaultThreadLoadingService.cs new file mode 100644 index 000000000..a6479da63 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ThreadLoading/DefaultThreadLoadingService.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.Operation; +using Tango.PPC.Common.Connection; +using Tango.PPC.Common.Notifications; +using Tango.PPC.Common.Threading; +using Tango.PPC.Common.ThreadLoading; +using Tango.PPC.UI.Dialogs; + +namespace Tango.PPC.UI.ThreadLoading +{ + public class DefaultThreadLoadingService : IThreadLoadingService + { + private INotificationProvider _notificationsProvider; + private IMachineProvider _machineProvider; + private IDispatcherProvider _dispatcher; + private bool _dialogShown; + + public DefaultThreadLoadingService(INotificationProvider notificationsProvider, IMachineProvider machineProvider, IDispatcherProvider dispatcher) + { + _notificationsProvider = notificationsProvider; + _machineProvider = machineProvider; + _dispatcher = dispatcher; + _machineProvider.MachineOperator.ThreadLoadingStatusChanged += MachineOperator_ThreadLoadingStatusChanged; + } + + private void MachineOperator_ThreadLoadingStatusChanged(object sender, PMR.ThreadLoading.StartThreadLoadingResponse e) + { + if (!_dialogShown && e.State != PMR.ThreadLoading.ThreadLoadingState.None) + { + _dialogShown = true; + _dispatcher.Invoke(async () => + { + await _notificationsProvider.ShowDialog(new ThreadLoadingViewVM()); + _dialogShown = false; + }); + } + } + + public async void StartThreadLoadingWizard() + { + _dialogShown = true; + await _notificationsProvider.ShowDialog(new ThreadLoadingViewVM(true)); + _dialogShown = false; + } + + public async void StartThreadBreakWizard() + { + if (!_dialogShown) + { + _dialogShown = true; + var vm = await _notificationsProvider.ShowDialog(); + _dialogShown = false; + + if (vm.Result == ThreadBreakViewVM.ThreadBreakWizardResult.StartThreadLoading) + { + StartThreadLoadingWizard(); + } + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs index 67b5dc19b..222d3a1e8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs @@ -1,26 +1,41 @@ using System; +using System.Linq; using System.Windows; using Tango.Core.DI; using Tango.Integration.ExternalBridge; using Tango.Logging; using Tango.PPC.Common.Application; using Tango.PPC.Common.Authentication; +using Tango.PPC.Common.BackupRestore; using Tango.PPC.Common.Connection; using Tango.PPC.Common.Connectivity; +using Tango.PPC.Common.Console; +using Tango.PPC.Common.DataStore; using Tango.PPC.Common.Diagnostics; using Tango.PPC.Common.EventLogging; using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Common.FileSystem; using Tango.PPC.Common.HotSpot; +using Tango.PPC.Common.Insights; using Tango.PPC.Common.MachineSetup; using Tango.PPC.Common.MachineUpdate; using Tango.PPC.Common.Modules; using Tango.PPC.Common.Navigation; using Tango.PPC.Common.Notifications; using Tango.PPC.Common.OS; +using Tango.PPC.Common.Performance; using Tango.PPC.Common.Printing; +using Tango.PPC.Common.RemoteActions; using Tango.PPC.Common.RemoteAssistance; +using Tango.PPC.Common.RemoteDesktop; +using Tango.PPC.Common.RemoteJob; +using Tango.PPC.Common.SQL; using Tango.PPC.Common.Storage; +using Tango.PPC.Common.Synchronization; +using Tango.PPC.Common.SystemInfo; using Tango.PPC.Common.Threading; +using Tango.PPC.Common.ThreadLoading; +using Tango.PPC.Common.UpdatePackages; using Tango.PPC.Common.UWF; using Tango.PPC.Common.Web; using Tango.PPC.UI.Authentication; @@ -30,7 +45,9 @@ using Tango.PPC.UI.Navigation; using Tango.PPC.UI.Notifications; using Tango.PPC.UI.PPCApplication; using Tango.PPC.UI.Printing; +using Tango.PPC.UI.RemoteActions; using Tango.PPC.UI.Threading; +using Tango.PPC.UI.ThreadLoading; using Tango.PPC.UI.ViewModels; using Tango.PPC.UI.Views; using Tango.PPC.UI.ViewsContracts; @@ -71,8 +88,30 @@ namespace Tango.PPC.UI TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); + + if (App.StartupArgs != null && App.StartupArgs.Contains("-webDebug")) + { + TangoIOC.Default.Register(new PPCWebClient("http://localhost:1111", null)); + } + else + { + TangoIOC.Default.Register(new PPCWebClient()); + } - TangoIOC.Default.Register(new PPCWebClient()); TangoIOC.Default.Register(new DefaultDispatcherProvider(Application.Current.Dispatcher)); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -80,11 +119,14 @@ namespace Tango.PPC.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -93,8 +135,17 @@ namespace Tango.PPC.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); - - //TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -107,6 +158,9 @@ namespace Tango.PPC.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.GetInstance().ContentRendered += (_, __) => @@ -212,5 +266,29 @@ namespace Tango.PPC.UI return TangoIOC.Default.GetInstance(); } } + + public static RestartingViewVM RestartingViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static InternalModuleViewVM InternalModuleViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } + + public static PowerOffViewVM PowerOffViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs index f1127ebfe..f10e84d05 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs @@ -12,6 +12,7 @@ using Tango.PMR.Integration; using Tango.PPC.Common; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Common.Navigation; +using Tango.PPC.UI.Dialogs; namespace Tango.PPC.UI.ViewModels { @@ -24,6 +25,8 @@ namespace Tango.PPC.UI.ViewModels { private bool _disconnecting; + private const int KEEP_SAFETY_AUTHENTICATION_MINUTES = 5; + #region Properties private ExternalBridgeClientConnectedEventArgs _connection; @@ -79,7 +82,7 @@ namespace Tango.PPC.UI.ViewModels LogManager.Log("Disconnecting current external bridge session."); _disconnecting = true; InvalidateRelayCommands(); - ExternalBridgeService.DisconnectSession(); + ExternalBridgeService.DisconnectFullControlSession(); } #endregion @@ -103,7 +106,7 @@ namespace Tango.PPC.UI.ViewModels public override void OnApplicationStarted() { ExternalBridgeService.ConnectionRequest += ExternalBridgeService_ConnectionRequest; - ExternalBridgeService.ClientDisconnected += ExternalBridgeService_ClientDisconnected; + ExternalBridgeService.FullControlSessionDisconnected += ExternalBridgeService_FullControlSessionDisconnected; } #endregion @@ -111,11 +114,11 @@ namespace Tango.PPC.UI.ViewModels #region Event Handlers /// - /// Handles the event. + /// Handles the event. /// /// The sender. /// The instance containing the event data. - private void ExternalBridgeService_ClientDisconnected(object sender, EventArgs e) + private void ExternalBridgeService_FullControlSessionDisconnected(object sender, EventArgs e) { if (IsVisible) { @@ -133,13 +136,14 @@ namespace Tango.PPC.UI.ViewModels /// /// The sender. /// The instance containing the event data. - private void ExternalBridgeService_ConnectionRequest(object sender, ExternalBridgeClientConnectedEventArgs e) + private async void ExternalBridgeService_ConnectionRequest(object sender, ExternalBridgeClientConnectedEventArgs e) { LogManager.Log($"External bridge connection request received.\n{e.ToJsonString()}"); if (!e.Request.Intent.RequiresPassword() || e.Request.Password == Settings.ExternalBridgePassword) { - e.Confirmed = true; + e.ApplicationInformation.Version = ApplicationManager.Version.ToString(); + e.ApplicationInformation.StartupDate = ApplicationManager.StartUpDate.ToUniversalTime().ToString(); Connection = e; @@ -150,6 +154,41 @@ namespace Tango.PPC.UI.ViewModels LogManager.Log($"External bridge connection user has been identified as {User.Contact.FullName}"); } + if (e.Request.RequireSafetyLevelOperations) + { + DateTime lastAuthenticationTime; + bool bypassSafetyConfirmation = false; + + if (ExternalBridgeReceiver.LastSafetyLevelContactsTimes.TryGetValue(e.Request.UserName, out lastAuthenticationTime)) + { + if (DateTime.Now < lastAuthenticationTime.AddMinutes(KEEP_SAFETY_AUTHENTICATION_MINUTES)) + { + bypassSafetyConfirmation = true; + e.Confirm(); + } + } + + if (!bypassSafetyConfirmation) + { + SafetyLevelOperationsConfirmationViewVM vm = new SafetyLevelOperationsConfirmationViewVM(e); + await NotificationProvider.ShowDialog(vm); + + if (vm.DialogResult) + { + e.Confirm(); + } + else + { + e.Decline("Safety level connection refused by the remote user."); + return; + } + } + } + else + { + e.Confirm(); + } + if (e.Request.Intent == ExternalBridgeLoginIntent.FullControl) { LogManager.Log("Navigating to external bridge view..."); @@ -161,6 +200,7 @@ namespace Tango.PPC.UI.ViewModels } else { + e.Decline("Connection password did not match the machine external bridge password."); LogManager.Log("Connection password did not match the machine external bridge password."); } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/InternalModuleViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/InternalModuleViewVM.cs new file mode 100644 index 000000000..29e6417f4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/InternalModuleViewVM.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; + +namespace Tango.PPC.UI.ViewModels +{ + public class InternalModuleViewVM : PPCViewModel + { + public override void OnApplicationStarted() + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs index 9e8a9fe34..a2baec8b8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs @@ -3,13 +3,19 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; using System.Windows.Threading; +using Tango.Core; using Tango.Core.Commands; using Tango.Core.DI; using Tango.Integration.Operation; +using Tango.PMR.IFS; using Tango.PPC.Common; +using Tango.PPC.Common.Connection; using Tango.PPC.Common.Modules; using Tango.PPC.Common.Navigation; +using Tango.PPC.UI.Views; using Tango.PPC.UI.ViewsContracts; using Tango.SharedUI; @@ -22,6 +28,7 @@ namespace Tango.PPC.UI.ViewModels public class LayoutViewVM : PPCViewModel { private JobHandler _jobHandler; + private bool _resettingDevice; /// /// Gets or sets the module loader. @@ -29,6 +36,86 @@ namespace Tango.PPC.UI.ViewModels [TangoInject] public IPPCModuleLoader ModuleLoader { get; set; } + #region Classes + + public class CartridgeModel : ExtendedObject + { + private IMachineProvider _machineProvider; + + public CartridgeStatus Status { get; set; } + + public bool InProgress + { + get { return Status.State == CartridgeState.Filling || Status.State == CartridgeState.Emptying; } + } + + public String Message + { + get { return Status.Cartridge.Slot == PMR.Diagnostics.CartridgeSlot.Ink ? "Ink filling is in progress..." : "Waste emptying is in progress..."; } + } + + public Brush Brush + { + get + { + if (Status.Cartridge.Slot == PMR.Diagnostics.CartridgeSlot.Ink) + { + try + { + int index = Status.Cartridge.Index; + + var idsPack = _machineProvider.Machine.Configuration.NoneEmptyIdsPacks.FirstOrDefault(x => x.PackIndex == index); + + if (idsPack != null) + { + switch (idsPack.LiquidType.Type) + { + case BL.Enumerations.LiquidTypes.Cyan: + return Application.Current.Resources["TangoCyanInkBrush"] as Brush; + case BL.Enumerations.LiquidTypes.Magenta: + return Application.Current.Resources["TangoMagentaInkBrush"] as Brush; + case BL.Enumerations.LiquidTypes.Yellow: + return Application.Current.Resources["TangoYellowInkBrush"] as Brush; + case BL.Enumerations.LiquidTypes.Black: + return Application.Current.Resources["TangoBlackInkBrush"] as Brush; + case BL.Enumerations.LiquidTypes.Lubricant: + return Application.Current.Resources["TangoLubricantBrush"] as Brush; + case BL.Enumerations.LiquidTypes.Cleaner: + return Application.Current.Resources["TangoCleanerBrush"] as Brush; + case BL.Enumerations.LiquidTypes.TransparentInk: + return Application.Current.Resources["TangoTransparentInkBrush"] as Brush; + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating ink filling brush."); + } + + return Application.Current.Resources["TangoPrimaryAccentBrush"] as Brush; + } + else + { + return Application.Current.Resources["TangoWasteBrush"] as Brush; + } + } + } + + public CartridgeModel(IMachineProvider machineProvider) + { + _machineProvider = machineProvider; + Status = new CartridgeStatus(); + } + + public void Invalidate() + { + RaisePropertyChanged(nameof(InProgress)); + RaisePropertyChanged(nameof(Status)); + } + } + + #endregion + #region Properties private bool _isMenuOpened; @@ -72,6 +159,23 @@ namespace Tango.PPC.UI.ViewModels set { _isPowerOpened = value; RaisePropertyChangedAuto(); } } + private bool _isInkFillingOrWasteEmptying; + /// + /// Gets or sets a value indicating whether ink filling or waste emptying is active. + /// + public bool IsInkFillingOrWasteEmptying + { + get { return _isInkFillingOrWasteEmptying; } + set { _isInkFillingOrWasteEmptying = value; RaisePropertyChangedAuto(); } + } + + private List _cartridges; + public List Cartridges + { + get { return _cartridges; } + set { _cartridges = value; RaisePropertyChangedAuto(); } + } + #endregion #region Commands @@ -121,6 +225,21 @@ namespace Tango.PPC.UI.ViewModels /// public RelayCommand RestartApplicationCommand { get; set; } + /// + /// Gets or sets the power off command. + /// + public RelayCommand PowerOffCommand { get; set; } + + /// + /// Gets or sets the reset command. + /// + public RelayCommand ResetCommand { get; set; } + + /// + /// Gets or sets the stand by command. + /// + public RelayCommand StandByCommand { get; set; } + #endregion #region Constructors @@ -137,15 +256,13 @@ namespace Tango.PPC.UI.ViewModels StopPrintingCommand = new RelayCommand(StopPrinting); SignOutCommand = new RelayCommand(SignOut); - UpdateCommand = new RelayCommand(() => - { - NavigationManager.NavigateTo(NavigationView.MachineUpdateView); - TangoIOC.Default.GetInstance().CheckForUpdates(); - IsMenuOpened = false; - }); + UpdateCommand = new RelayCommand(UpdateMachine); PowerCommand = new RelayCommand(() => IsPowerOpened = true); RestartApplicationCommand = new RelayCommand(RestartApplication); + PowerOffCommand = new RelayCommand(PowerOffMachine, () => MachineProvider.MachineOperator.Status != MachineStatuses.Disconnected); + ResetCommand = new RelayCommand(ResetMachine, () => MachineProvider.MachineOperator.Status != MachineStatuses.Disconnected); + StandByCommand = new RelayCommand(StandBy, () => MachineProvider.MachineOperator.CanPrint); } #endregion @@ -239,6 +356,83 @@ namespace Tango.PPC.UI.ViewModels } } + /// + /// Powers off the machine. + /// + private async void PowerOffMachine() + { + IsMenuOpened = false; + + if (await NotificationProvider.ShowQuestion("Are you sure you wish to turn off the machine?")) + { + try + { + await MachineProvider.MachineOperator.PowerDown(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error triggering power down."); + await NotificationProvider.ShowError(ex.FlattenMessage()); + } + } + } + + /// + /// Resets the machine. + /// + private async void ResetMachine() + { + IsMenuOpened = false; + + if (!await NotificationProvider.ShowQuestion("Are you sure you want to reset the machine?")) return; + + try + { + _resettingDevice = true; + ResetCommand.RaiseCanExecuteChanged(); + await MachineProvider.MachineOperator.Reset(); + await NotificationProvider.ShowInfo("Machine was successfully restarted."); + } + catch (Exception ex) + { + await NotificationProvider.ShowError(ex.FlattenMessage()); + } + finally + { + _resettingDevice = false; + ResetCommand.RaiseCanExecuteChanged(); + } + } + + private async void StandBy() + { + IsMenuOpened = false; + + try + { + LogManager.Log("Executing stand-by command."); + await MachineProvider.MachineOperator.StandBy(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error switching to stand-by mode."); + await NotificationProvider.ShowError($"Error switching to stand-by mode.\n{ex.FlattenMessage()}"); + } + } + + private void UpdateMachine() + { + if (MachineProvider.MachineOperator.IsPrinting) + { + NotificationProvider.ShowInfo("Cannot perform a machine update while the machine is dyeing."); + return; + } + + NavigationManager.NavigateTo(NavigationView.MachineUpdateView); + TangoIOC.Default.GetInstance().CheckForUpdates(); + IsMenuOpened = false; + } + #endregion #region Override Methods @@ -250,6 +444,34 @@ namespace Tango.PPC.UI.ViewModels { base.OnApplicationStarted(); MachineProvider.MachineOperator.PrintingStarted += MachineOperator_PrintingStarted; + MachineProvider.MachineOperator.InkFillingStatusChanged += MachineOperator_InkFillingStatusChanged; + } + + private void MachineOperator_InkFillingStatusChanged(object sender, InkFillingStatusChangedEventArgs e) + { + if (Cartridges == null) + { + Cartridges = MachineProvider.MachineOperator.InkFillingStatus.CartridgesStatuses.Select(x => new CartridgeModel(MachineProvider) { Status = x }).ToList(); + } + else + { + foreach (var cartridgeStatus in e.Status.CartridgesStatuses) + { + var model = Cartridges.SingleOrDefault(x => x.Status == cartridgeStatus); + + if (model != null) + { + model.Status = cartridgeStatus; + } + } + } + + foreach (var cartridgeModel in Cartridges) + { + cartridgeModel.Invalidate(); + } + + IsInkFillingOrWasteEmptying = Cartridges.Any(x => x.Status.State == CartridgeState.Filling || x.Status.State == CartridgeState.Emptying); } /// @@ -260,6 +482,22 @@ namespace Tango.PPC.UI.ViewModels } + public override void OnApplicationReady() + { + base.OnApplicationReady(); + MachineProvider.MachineOperator.StatusChanged += MachineOperator_StatusChanged; + } + + private void MachineOperator_StatusChanged(object sender, MachineStatuses e) + { + InvokeUI(() => + { + PowerOffCommand.RaiseCanExecuteChanged(); + ResetCommand.RaiseCanExecuteChanged(); + StandByCommand.RaiseCanExecuteChanged(); + }); + } + #endregion #region Public Methods diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs index f926a0f4c..38dd569e1 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs @@ -74,37 +74,46 @@ namespace Tango.PPC.UI.ViewModels /// public async override void OnApplicationStarted() { - using (ObservablesContext db = ObservablesContext.CreateDefault()) - { - var machine = await db.Machines.FirstAsync(); + //We don't use authentication! - if (db.Users.Count() == 1 || machine.AutoLogin) - { - var user = await new UserBuilder(db).SetFirst().WithRolesAndPermissions().BuildAsync(); + //using (ObservablesContext db = ObservablesContext.CreateDefault()) + //{ + // var machine = await db.Machines.FirstAsync(); - if (!user.HasRole(Roles.PPCUser)) - { - var role = db.Roles.Single(x => x.Code == (int)Roles.PPCUser); - user.Roles.Add(role); - db.UsersRoles.Add(new BL.Entities.UsersRole() - { - User = user, - Role = role, - }); - await db.SaveChangesAsync(); - } + // if (db.Users.Count() == 1 || machine.AutoLogin) + // { + // var user = await new UserBuilder(db).SetFirst().WithRolesAndPermissions().BuildAsync(); - LogManager.Log($"Application started. Single user/Auto login detected ({user.Email}). Skipping LoginView..."); - await AuthenticationProvider.Login(user.Email, user.Password, false); - IsLoading = false; - } - else - { - LogManager.Log("Application started. Navigating to LoginView..."); - await NavigationManager.NavigateTo(NavigationView.LoginView); - IsLoading = false; - } - } + // if (!user.HasRole(Roles.PPCUser)) + // { + // var role = db.Roles.Single(x => x.Code == (int)Roles.PPCUser); + // user.Roles.Add(role); + // db.UsersRoles.Add(new BL.Entities.UsersRole() + // { + // User = user, + // Role = role, + // }); + // await db.SaveChangesAsync(); + // } + + // LogManager.Log($"Application started. Single user/Auto login detected ({user.Email}). Skipping LoginView..."); + // await AuthenticationProvider.Login(user.Email, user.Password, false); + // await Task.Delay(1000); + // IsLoading = false; + // } + // else + // { + // LogManager.Log("Application started. Navigating to LoginView..."); + // await NavigationManager.NavigateTo(NavigationView.LoginView); + // await Task.Delay(1000); + // IsLoading = false; + // } + //} + + LogManager.Log($"Application started with no authentication mode..."); + await AuthenticationProvider.Login(); + await Task.Delay(1000); + IsLoading = false; } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs index aa9689ef3..ec316989f 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs @@ -92,7 +92,13 @@ namespace Tango.PPC.UI.ViewModels await Task.Delay(500); - if (AuthenticationProvider.CurrentUser != null && AuthenticationProvider.CurrentUser.HasPermission(Permissions.RunPPC)) + if (!AuthenticationProvider.AuthenticationRequired) + { + LogManager.Log("Application is ready! Navigating to home module..."); + await NavigationManager.NavigateTo(NavigationView.HomeModule); + IsLoading = false; + } + else if (AuthenticationProvider.CurrentUser != null && AuthenticationProvider.CurrentUser.HasPermission(Permissions.RunPPC)) { LogManager.Log("Application is ready! Navigating to home module..."); await NavigationManager.NavigateTo(NavigationView.HomeModule); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs index aca9dbcf7..ae31a64a1 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs @@ -347,7 +347,10 @@ namespace Tango.PPC.UI.ViewModels try { - _ppcWebClient.Environment = DeploymentSlot; + if (!App.StartupArgs.Contains("-webDebug")) + { + _ppcWebClient.Environment = DeploymentSlot; + } await _operationSystemManager.ChangeTimeZone(SelectedTimeZone); _setup_result = await MachineSetupManager.Setup(SerialNumber); State = MachineSetupStates.Completed; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs index 01e67d3ce..5fe153ee9 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs @@ -1,22 +1,38 @@ using System; using System.Collections.Generic; +using System.Data.Entity; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; using Tango.Core.Commands; +using Tango.Core.ExtensionMethods; using Tango.Core.Helpers; +using Tango.Core.Threading; using Tango.Explorer; +using Tango.Integration.ExternalBridge; +using Tango.PMR.FirmwareUpgrade; using Tango.PPC.Common; +using Tango.PPC.Common.Application; +using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Common.MachineUpdate; +using Tango.PPC.Common.Navigation; +using Tango.PPC.Common.Notifications; +using Tango.PPC.Common.Publish; using Tango.PPC.Common.Web; +using Tango.PPC.Shared.RemoteUpgrade; using Tango.PPC.UI.Dialogs; +using Tango.PPC.UI.Notifications.NotificationItems; using Tango.PPC.UI.ViewsContracts; +using Tango.Transport; namespace Tango.PPC.UI.ViewModels { - public class MachineUpdateViewVM : PPCViewModel + public class MachineUpdateViewVM : PPCViewModel, IExternalBridgeRequestHandler { public enum MachineUpdateView { @@ -36,6 +52,7 @@ namespace Tango.PPC.UI.ViewModels private DbCompareResult _db_compare_result; private bool _isChecking; private CheckForUpdateResponse _checkUpdateResponse; + private UpdateAvailableNotificationItem _updateNotificationItem; #region Properties @@ -107,9 +124,10 @@ namespace Tango.PPC.UI.ViewModels #region Constructors - public MachineUpdateViewVM(IMachineUpdateManager machineUpdateManager) + public MachineUpdateViewVM(IMachineUpdateManager machineUpdateManager, IPPCExternalBridgeService externalBridge, IPPCApplicationManager applicationManager, INavigationManager navigationManager, INotificationProvider notificationProvider) { MachineUpdateManager = machineUpdateManager; + externalBridge.RegisterRequestHandler(this); CompleteCommand = new RelayCommand(CompleteUpdate); UpdateCommand = new RelayCommand(Update); @@ -125,6 +143,13 @@ namespace Tango.PPC.UI.ViewModels NavigationManager.NavigateTo(Common.Navigation.NavigationView.HomeModule); NavigateTo(MachineUpdateView.UpdateCheckView); }); + + machineUpdateManager.UpdateAvailable += MachineUpdateManager_UpdateAvailable; + + NavigationManager = navigationManager; + NotificationProvider = notificationProvider; + ApplicationManager = applicationManager; + ApplicationManager.UpdaterFailed += ApplicationManager_UpdaterFailed; } #endregion @@ -150,7 +175,28 @@ namespace Tango.PPC.UI.ViewModels return; } - var response = await MachineUpdateManager.CheckForUpdate(MachineProvider.Machine.SerialNumber); + var response = await MachineUpdateManager.CheckForUpdate(); + + try + { + if (response.UsedNotExistingRmlsGuids.Count > 0) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var arr = response.UsedNotExistingRmlsGuids.ToArray(); + var jobs = await db.Jobs.Where(x => arr.Contains(x.RmlGuid)).ToListAsync(); + FailedError = $"The following jobs must be removed or change thread type before the system can be updated:\n{String.Join("\n", jobs.Select(x => x.Name))}"; + _isChecking = false; + await NavigateTo(MachineUpdateView.UpdateFailedView); + return; + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error on used RML check procedure."); + } + _checkUpdateResponse = response; if (response.IsUpdateAvailable) @@ -158,9 +204,19 @@ namespace Tango.PPC.UI.ViewModels LatestVersion = response.Version; await NavigateTo(MachineUpdateView.UpdateAvailableView); } + else if (response.IsDatabaseUpdateAvailable) + { + IsDbUpdate = true; + _db_compare_result = new DbCompareResult() + { + RequiresUpdate = true, + UpdateDBResponse = response.UpdateDBResponse + }; + await NavigateTo(MachineUpdateView.UpdateAvailableView); + } else { - _db_compare_result = await MachineUpdateManager.UpdateDBCheck(MachineProvider.Machine.SerialNumber); + _db_compare_result = await MachineUpdateManager.UpdateDBCheck(); if (_db_compare_result.RequiresUpdate) { @@ -195,7 +251,7 @@ namespace Tango.PPC.UI.ViewModels try { - _update_result = await MachineUpdateManager.Update(MachineProvider.Machine.SerialNumber, _checkUpdateResponse.SetupFirmware, _checkUpdateResponse.SetupFPGA); + _update_result = await MachineUpdateManager.Update(_checkUpdateResponse.SetupFirmware, _checkUpdateResponse.SetupFPGA); LogManager.Log("Machine update completed."); await NavigateTo(MachineUpdateView.UpdateCompletedView); } @@ -213,7 +269,7 @@ namespace Tango.PPC.UI.ViewModels try { - await MachineUpdateManager.UpdateDB(_db_compare_result, MachineProvider.Machine.SerialNumber); + await MachineUpdateManager.UpdateDB(_db_compare_result); LogManager.Log("Database update completed."); await NavigateTo(MachineUpdateView.UpdateCompletedView); } @@ -234,15 +290,15 @@ namespace Tango.PPC.UI.ViewModels { LogManager.Log("Completing machine update..."); - if (!IsDbUpdate) + if (IsDbUpdate || !_update_result.RequiresBinariesUpdate) { - String updater_exe = Path.Combine(_update_result.UpdatePackagePath, "Tango.PPC.Updater.exe"); - ApplicationManager.UpdateApplication(updater_exe, PathHelper.GetStartupPath()); + LogManager.Log("Restarting Application..."); + ApplicationManager.Restart(); } else { - LogManager.Log("Restarting Application..."); - ApplicationManager.Restart(); + String updater_exe = Path.Combine(_update_result.UpdatePackagePath, "Tango.PPC.Updater.exe"); + ApplicationManager.UpdateApplication(updater_exe, PathHelper.GetStartupPath()); } } @@ -275,15 +331,100 @@ namespace Tango.PPC.UI.ViewModels base.OnApplicationReady(); StorageProvider.RegisterFileHandler(ExplorerFileDefinition.Update.Extension, HandleSoftwareUpdatePackageLoaded); + StorageProvider.RegisterFileHandler(ExplorerFileDefinition.Firmware.Extension, HandleFirmwareUpgradeLoaded); + + if (ApplicationManager.IsAfterUpdate) + { + RunPostUpdatePackages(); + } + else + { + MachineUpdateManager.EnableAutoCheckForUpdates = true; + } + } + + /// + /// Called when the navigation system has navigated to this VM view. + /// + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (_updateNotificationItem != null) + { + _updateNotificationItem.Close(); + _updateNotificationItem = null; + } + } + + #endregion + + #region Post Update Packages + + private async void RunPostUpdatePackages() + { + await Task.Delay(1000); + + LogManager.Log("Application was loaded after an update. Checking for required post-update packages..."); + + bool required = false; + + try + { + required = await MachineUpdateManager.PostUpdatePackagesRequired(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error checking for post-update packages."); + } + + if (required) + { + LogManager.Log("Post-update packages found and needs to be installed. Navigating to machine update and running post-update packages..."); + await NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + await NavigateTo(MachineUpdateView.UpdateProgressView); + try + { + var result = await MachineUpdateManager.RunPostUpdatePackages(); + + LogManager.Log("Post-update packages installed successfully."); + + await Task.Delay(2000); + + if (result.RestartRequired) + { + LogManager.Log("Restart required. Restarting..."); + ApplicationManager.Restart(); + } + else + { + await NavigationManager.NavigateTo(Common.Navigation.NavigationView.LayoutView); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred while running post-update packages."); + } + } + else + { + LogManager.Log("No post-update packages installation required."); + } } #endregion #region Handle USB Update - private async void HandleSoftwareUpdatePackageLoaded(ExplorerFileItem fileItem) + private async void HandleSoftwareUpdatePackageLoaded(List fileItems) { - UpdatePackageFile packageFile = null; + var fileItem = fileItems.FirstOrDefault(); + + if (fileItem == null) return; + + PublishInfo packageFile = null; + + LogManager.Log("TUP file loaded from storage..."); try { @@ -291,43 +432,394 @@ namespace Tango.PPC.UI.ViewModels } catch (Exception ex) { - LogManager.Log(ex, $"Error loading update package file from {fileItem.Path}."); + LogManager.Log(ex, $"Error loading publish info from {fileItem.Path}."); await NotificationProvider.ShowError("An error occurred while trying to load the selected software update package. Please make sure the package is valid."); return; } - if (ApplicationManager.Version <= packageFile.Version) + UpdateFromFileViewVM vm = new UpdateFromFileViewVM(); + vm.PublishInfo = packageFile; + + LogManager.Log($"TUP publish info:\n{packageFile.ToJson()}"); + + LogManager.Log("Displaying TUP update dialog..."); + + await NotificationProvider.ShowDialog(vm); + + if (vm.DialogResult) + { + await NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + await NavigateTo(MachineUpdateView.UpdateProgressView); + + LogManager.Log("Starting machine update from package..."); + + try + { + _update_result = await MachineUpdateManager.UpdateFromTUP(fileItem.Path, MachineProvider.Machine.SetupFirmware, MachineProvider.Machine.SetupFpga); + LogManager.Log("Machine update from package completed."); + await NavigateTo(MachineUpdateView.UpdateCompletedView); + } + catch (Exception ex) + { + LogManager.Log(ex, "Machine update from package failed."); + FailedError = ex.FlattenMessage(); + await NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + } + } + } + + private async void HandleFirmwareUpgradeLoaded(List fileItems) + { + var fileItem = fileItems.FirstOrDefault(); + + if (fileItem == null) return; + + LogManager.Log("TFP file loaded from storage..."); + + VersionPackageDescriptor packageInfo; + FirmwareUpgradeFromFileViewVM vm = new FirmwareUpgradeFromFileViewVM(); + + try + { + using (FileStream st = File.OpenRead(fileItem.Path)) + { + packageInfo = await MachineProvider.MachineOperator.GetFirmwarePackageInfo(st); + } + + packageInfo.Validate(); + + vm.Version = packageInfo.GetMcuVersion().ToString(); + } + catch (Exception ex) { - await NotificationProvider.ShowError($"The selected update package (v{packageFile.Version.ToString()}) contains an older software version."); + LogManager.Log(ex, $"Error loading package info from {fileItem.Path}."); + await NotificationProvider.ShowError($"An error occurred while trying to load the selected firmware upgrade package.\n{ex.FlattenMessage()}"); return; } - UpdateFromFileViewVM vm = new UpdateFromFileViewVM(); - vm.Version = packageFile.Version.ToString(); + + LogManager.Log($"TFP publish info:\n{packageInfo.ToJsonString()}"); + + LogManager.Log("Displaying TFP update dialog..."); await NotificationProvider.ShowDialog(vm); if (vm.DialogResult) { await NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); - await NavigateTo(MachineUpdateView.UpdateFromPackageView); + await NavigateTo(MachineUpdateView.UpdateProgressView); + + LogManager.Log("Starting firmware upgrade from package..."); + + try + { + await MachineUpdateManager.UpdateFromTFP(fileItem.Path); + LogManager.Log("Firmware upgrade from package completed."); + _update_result = new MachineUpdateResult() + { + RequiresBinariesUpdate = false, + }; + await NavigateTo(MachineUpdateView.UpdateCompletedView); + } + catch (Exception ex) + { + LogManager.Log(ex, "Firmware upgrade from package failed."); + FailedError = ex.FlattenMessage(); + await NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + } + } + } + + #endregion + + #region Auto Check For Update + + private void MachineUpdateManager_UpdateAvailable(object sender, CheckForUpdateResponse e) + { + if (!IsVisible && _updateNotificationItem == null) + { + LogManager.Log($"New {(e.IsDatabaseUpdateAvailable ? "database updates" : "application version")} detected ({e.Version}). Pushing notification..."); + + InvokeUI(() => + { + _updateNotificationItem = new UpdateAvailableNotificationItem(); + _updateNotificationItem.Version = Version.Parse(e.Version).ToString(3); + _updateNotificationItem.IsDatabaseUpdate = e.IsDatabaseUpdateAvailable && !e.IsUpdateAvailable; + _updateNotificationItem.Pressed += (_, __) => + { + if (MachineProvider.MachineOperator.IsPrinting) + { + NotificationProvider.ShowInfo("Cannot perform a machine update while the machine is dyeing."); + return; + } + + _updateNotificationItem = null; + + if (!IsVisible) + { + LogManager.Log("Update available notification pressed. Navigating to update view..."); + NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + CheckForUpdates(); + } + }; + _updateNotificationItem.Closed += (_, __) => + { + _updateNotificationItem = null; + }; + NotificationProvider.PushNotification(_updateNotificationItem); + }); + } + } + + #endregion + + #region Updater Failed + + private void ApplicationManager_UpdaterFailed(object sender, EventArgs e) + { + InvokeUI(async () => + { + try + { + await NavigationManager.NavigateTo(NavigationView.MachineUpdateView); + await NavigateTo(MachineUpdateView.UpdateProgressView); + await MachineUpdateManager.RestoreLastDatabaseBackup(); + await Task.Delay(5000); + ApplicationManager.Restart(); + } + catch (Exception ex) + { + await NotificationProvider.ShowError($"Could not restore the application to its previous state.\n{ex.FlattenMessage()}"); + ApplicationManager.Restart(); + } + }); + } + + #endregion + + #region External Bridge Handler + + [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteApplicationUpgradeRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStartRemoteApplicationUpgradeRequest(StartRemoteApplicationUpgradeRequest request, String token, ExternalBridgeReceiver receiver) + { + await receiver.SendGenericResponse(new StartRemoteApplicationUpgradeResponse(), token); + + bool stopReporting = false; + + try + { + ThreadFactory.StartNew(async () => + { + while (!stopReporting) + { + if (MachineUpdateManager.Status != null) + { + try + { + await receiver.SendGenericResponse(new StartRemoteApplicationUpgradeResponse() + { + Progress = new TangoProgress() + { + Message = MachineUpdateManager.Status.Message, + IsIndeterminate = MachineUpdateManager.Status.IsIntermediate, + Maximum = MachineUpdateManager.Status.Total, + Value = MachineUpdateManager.Status.Progress + }, + }, token, new TransportResponseConfig() { Priority = QueuePriority.Low }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending remote upgrade progress."); + } + } + + Thread.Sleep(500); + } + }); + + InvokeUI(() => + { + NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + NavigateTo(MachineUpdateView.UpdateProgressView); + }); LogManager.Log("Starting machine update from package..."); try { - _update_result = await MachineUpdateManager.UpdateFromTUP(fileItem.Path); + _update_result = await MachineUpdateManager.UpdateFromTUP(request.RemoteTupFilePath, request.SetupFirmware, request.SetupFPGA); LogManager.Log("Machine update from package completed."); - await NavigateTo(MachineUpdateView.UpdateCompletedView); + stopReporting = true; + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateCompletedView); + }); } catch (Exception ex) { LogManager.Log(ex, "Machine update from package failed."); - await NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + FailedError = ex.FlattenMessage(); + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + }); + + throw ex; + } + + await receiver.SendGenericResponse(new StartRemoteApplicationUpgradeResponse() + { + Progress = new TangoProgress("Completed", false, 100, 100), + }, token, new TransportResponseConfig() + { + Completed = true + }); + + try + { + File.Delete(request.RemoteTupFilePath); + } + catch { } + + await Task.Delay(2000); + + CompleteUpdate(); + } + catch (Exception ex) + { + stopReporting = true; + await receiver.SendErrorResponse(ex, token); + } + finally + { + stopReporting = true; + + try + { + File.Delete(request.RemoteTupFilePath); + } + catch { } + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(StartRemoteFirmwareUpgradeRequest), RequestHandlerLoggingMode.LogRequestName)] + public async Task OnStartRemoteFirmwareUpgradeRequest(StartRemoteFirmwareUpgradeRequest request, String token, ExternalBridgeReceiver receiver) + { + await receiver.SendGenericResponse(new StartRemoteFirmwareUpgradeResponse(), token); + + bool stopReporting = false; + + try + { + ThreadFactory.StartNew(async () => + { + while (!stopReporting) + { + if (MachineUpdateManager.Status != null) + { + try + { + await receiver.SendGenericResponse(new StartRemoteFirmwareUpgradeResponse() + { + Progress = new TangoProgress() + { + Message = MachineUpdateManager.Status.Message, + IsIndeterminate = MachineUpdateManager.Status.IsIntermediate, + Maximum = MachineUpdateManager.Status.Total, + Value = MachineUpdateManager.Status.Progress + } + }, token, new TransportResponseConfig() { Priority = QueuePriority.Low }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending remote upgrade progress."); + } + } + + Thread.Sleep(500); + } + }); + + InvokeUI(() => + { + NavigationManager.NavigateTo(Common.Navigation.NavigationView.MachineUpdateView); + NavigateTo(MachineUpdateView.UpdateProgressView); + }); + + LogManager.Log("Starting firmware upgrade from package..."); + + try + { + await MachineUpdateManager.UpdateFromTFP(request.RemoteTfpFilePath); + stopReporting = true; + LogManager.Log("Firmware upgrade from package completed."); + _update_result = new MachineUpdateResult() + { + RequiresBinariesUpdate = false, + }; + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateCompletedView); + }); + } + catch (Exception ex) + { + stopReporting = true; + + LogManager.Log(ex, "Firmware upgrade from package failed."); + FailedError = ex.FlattenMessage(); + + InvokeUI(() => + { + NavigateTo(MachineUpdateView.UpdateFailedFromPackageView); + }); + + throw ex; + } + + await receiver.SendGenericResponse(new StartRemoteFirmwareUpgradeResponse() + { + Progress = new TangoProgress("Completed", false, 100, 100), + }, token, new TransportResponseConfig() + { + Completed = true + }); + + try + { + File.Delete(request.RemoteTfpFilePath); } + catch { } + + await Task.Delay(2000); + + CompleteUpdate(); + } + catch (Exception ex) + { + stopReporting = true; + await receiver.SendErrorResponse(ex, token); + } + finally + { + stopReporting = true; + + try + { + File.Delete(request.RemoteTfpFilePath); + } + catch { } } } + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + //Do Nothing. + } + #endregion } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs index 01a47539e..05fb610c8 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs @@ -4,6 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Threading; +using Tango.BL; +using Tango.BL.Builders; +using Tango.BL.Entities; using Tango.Core.DI; using Tango.Integration.ExternalBridge; using Tango.Integration.Operation; @@ -17,6 +20,8 @@ using Tango.PPC.Common.Notifications; using Tango.PPC.Common.WatchDog; using Tango.PPC.UI.Dialogs; using Tango.SharedUI; +using System.Data.Entity; +using Tango.PPC.UI.AppBarItems; namespace Tango.PPC.UI.ViewModels { @@ -27,6 +32,10 @@ namespace Tango.PPC.UI.ViewModels public class MainViewVM : PPCViewModel { private DispatcherTimer _date_timer; + private bool _isPowerUpDialogShown; + private bool _isThreadLoadingShown; + private PowerUpAppBarItem _powerUpAppBar; + private bool _started; private DateTime _currentDateTime; /// @@ -58,8 +67,53 @@ namespace Tango.PPC.UI.ViewModels { base.OnApplicationReady(); MachineProvider.MachineOperator.CartridgeValidationRequestReceived += MachineOperator_CartridgeValidationRequestReceived; + MachineProvider.MachineOperator.FirmwareStarted += MachineOperator_FirmwareStarted; + MachineProvider.MachineOperator.ThreadLoadingStatusChanged += MachineOperator_ThreadLoadingStatusChanged; + MachineProvider.MachineOperator.ThreadLoadingConfirmationRequired += MachineOperator_ThreadLoadingConfirmationRequired; + + MachineProvider.MachineOperator.PowerUpStarted += MachineOperator_PowerUpStarted; + MachineProvider.MachineOperator.PowerUpProgress += MachineOperator_PowerUpProgress; + MachineProvider.MachineOperator.PowerUpEnded += MachineOperator_PowerUpEnded; + } + + #region Power Up + + private void MachineOperator_PowerUpEnded(object sender, EventArgs e) + { + _started = false; + _powerUpAppBar?.Close(); + _powerUpAppBar = null; + } + + private void MachineOperator_PowerUpProgress(object sender, PMR.Power.StartPowerUpResponse status) + { + if (_powerUpAppBar != null) + { + _powerUpAppBar.Status = status; + } + } + + private void MachineOperator_PowerUpStarted(object sender, PMR.Power.StartPowerUpResponse e) + { + _started = true; + + InvokeUI(() => + { + if (_powerUpAppBar != null) + { + _powerUpAppBar.Close(); + } + + if (_started) + { + _powerUpAppBar = NotificationProvider.PushAppBarItem(); + _powerUpAppBar.Priority = AppBarPriority.Low; + } + }); } + #endregion + #region Event Handlers /// @@ -92,6 +146,106 @@ namespace Tango.PPC.UI.ViewModels }); } + private async void MachineOperator_FirmwareStarted(object sender, EventArgs e) + { + if (_isPowerUpDialogShown) + { + LogManager.Log("Power up detected but power up dialog is already shown. Skipping..."); + return; + } + + LogManager.Log("Power up detected, showing power up screen..."); + + if (!Settings.DisplayPowerUpScreen) + { + LogManager.Log("Power up screen disabled. skipping..."); + return; + } + + PowerUpViewVM vm; + + try + { + LogManager.Log("Loading site rmls..."); + + List rmls = new List(); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + rmls = await new RmlsCollectionBuilder(db).SetAll().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).BuildListAsync(); + } + + var selectedRml = rmls.SingleOrDefault(x => x.Guid == Settings.LoadedRmlGuid); + + vm = new PowerUpViewVM(); + vm.Rmls = rmls; + vm.SelectedRml = selectedRml != null ? selectedRml : rmls.FirstOrDefault(); + vm.IsSelectedRml = selectedRml != null; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error initializing power up screen."); + return; + } + + InvokeUI(async () => + { + _isPowerUpDialogShown = true; + await NotificationProvider.ShowDialog(vm); + _isPowerUpDialogShown = false; + + await Task.Factory.StartNew(() => + { + LogManager.Log("Power up screen closed."); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + List processTables = new List(); + + if (vm.IsSelectedRml) + { + LogManager.Log($"Selected rml '{vm.SelectedRml.Name}'..."); + processTables = new RmlBuilder(db).Set(vm.SelectedRml.Guid).WithActiveParametersGroup().Build().GetActiveProcessGroup().ProcessParametersTables.ToList(); + } + else + { + LogManager.Log("Selected minimal temperature..."); + var rmlsToAvg = new RmlsCollectionBuilder(db).SetAll().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).WithActiveParametersGroup().Build(); + processTables = rmlsToAvg.Select(x => x.GetActiveProcessGroup()).SelectMany(x => x.ProcessParametersTables).ToList(); + } + + var processToLoad = processTables.OrderBy(x => x.GetAverageTemperature()).First(); + + LogManager.Log($"Selected process parameters:\nRML: {processToLoad.ProcessParametersTablesGroup.Rml.Name}\nGroup: {processToLoad.ProcessParametersTablesGroup.Name}\nProcess Table: {processToLoad.Name}"); + LogManager.Log("Uploading process parameters..."); + var r = MachineProvider.MachineOperator.UploadProcessParameters(processToLoad).Result; + + Settings.LoadedRmlGuid = vm.IsSelectedRml ? vm.SelectedRml.Guid : null; + Settings.Save(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred while trying to get and upload the proper process parameters after power screen closed."); + } + }); + }); + } + + private void MachineOperator_ThreadLoadingStatusChanged(object sender, PMR.ThreadLoading.StartThreadLoadingResponse e) + { + //if (e.State == PMR.ThreadLoading.ThreadLoadingState.Preparing) + //{ + // DisplayThreadLoading(); + //} + } + + private void MachineOperator_ThreadLoadingConfirmationRequired(object sender, ThreadLoadingConfirmationRequiredEventArgs e) + { +// DisplayThreadLoading(e); + } #endregion } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs new file mode 100644 index 000000000..e3ab7d111 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.Integration.Operation; +using Tango.PMR.Power; +using Tango.PPC.Common; +using Tango.PPC.UI.AppBarItems; +using Tango.PPC.UI.Views; + +namespace Tango.PPC.UI.ViewModels +{ + public class PowerOffViewVM : PPCViewModel + { + private PowerDownHandler _handler; + private PowerOffAppBarItem _appBarItem; + private int _abortTries; + + private StartPowerDownResponse _status; + public StartPowerDownResponse Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand AbortCommand { get; set; } + + public PowerOffViewVM() + { + _appBarItem = new PowerOffAppBarItem(); + _appBarItem.Pressed += (x, e) => + { + NavigationManager.NavigateTo(nameof(PowerOffView)); + }; + AbortCommand = new RelayCommand(AbortPowerOff); + } + + public override void OnApplicationStarted() + { + + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + MachineProvider.MachineOperator.PowerDownStarted += MachineOperator_PowerDownStarted; + } + + private void MachineOperator_PowerDownStarted(object sender, PowerDownStartedEventArgs e) + { + _abortTries = 0; + _handler = e.Handler; + + _handler.StatusChanged += OnStatusChanged; + _handler.Failed += OnFailed; + _handler.Completed += OnCompleted; + + InvokeUI(async () => + { + await NavigationManager.NavigateTo(nameof(PowerOffView)); + NotificationProvider.PushAppBarItem(_appBarItem); + }); + } + + private void OnStatusChanged(object sender, PowerDownStatusChangedEventArgs e) + { + Status = e.Status; + _appBarItem.Status = Status; + } + + private void OnCompleted(object sender, EventArgs e) + { + InvokeUI(async () => + { + if (IsVisible) + { + await NavigationManager.NavigateBack(); + } + + NotificationProvider.PopAppBarItem(_appBarItem); + }); + } + + private void OnFailed(object sender, Exception ex) + { + InvokeUI(async () => + { + await NotificationProvider.ShowError($"An error occurred while powering off the machine.\n{ex.FlattenMessage()}"); + + if (IsVisible) + { + await NavigationManager.NavigateBack(); + } + + NotificationProvider.PopAppBarItem(_appBarItem); + }); + } + + private async void AbortPowerOff() + { + try + { + NotificationProvider.SetGlobalBusyMessage("Aborting machine power off..."); + await _handler.Abort(); + await NavigationManager.NavigateBack(); + NotificationProvider.PopAppBarItem(_appBarItem); + } + catch (Exception ex) + { + _abortTries++; + LogManager.Log(ex, "Power down abort error."); + NotificationProvider.ReleaseGlobalBusyMessage(); + await NotificationProvider.ShowError($"An error occurred while trying to abort the power off sequence.\n{ex.FlattenMessage()}"); + + if (_abortTries > 2) + { + if (IsVisible) + { + await NavigationManager.NavigateBack(); + } + + NotificationProvider.PopAppBarItem(_appBarItem); + } + } + finally + { + NotificationProvider.ReleaseGlobalBusyMessage(); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/RestartingViewVM.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/RestartingViewVM.cs new file mode 100644 index 000000000..46111031b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/RestartingViewVM.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Common; + +namespace Tango.PPC.UI.ViewModels +{ + public class RestartingViewVM : PPCViewModel + { + public override void OnApplicationStarted() + { + + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + } + + public override void OnNavigatedFrom() + { + base.OnNavigatedFrom(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/EmergencyView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/EmergencyView.xaml index dfc70e602..f2b018bfa 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/EmergencyView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/EmergencyView.xaml @@ -9,12 +9,18 @@ xmlns:local="clr-namespace:Tango.PPC.UI.Views" mc:Ignorable="d" d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:EmergencyViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.EmergencyViewVM}"> - + - - - Emergency Switch Activated - Please release the emergency switch to exit this screen. + + + EMERGENCY PUSH BUTTON PRESSED + How to handle: + + 1. Verify that it is safe to restart the system. + 2. Release the emergency button. + 3. Press the power button to power up the system. + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml index d83128007..fddd15fe7 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml @@ -7,18 +7,23 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:Tango.PPC.UI.ViewModels" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:localControls="clr-namespace:Tango.PPC.UI.Controls" xmlns:local="clr-namespace:Tango.PPC.UI.Views" mc:Ignorable="d" d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:ExternalBridgeViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.ExternalBridgeViewVM}" Background="{StaticResource TangoPrimaryBackgroundBrush}"> - - - + + + + + + + + - - + @@ -302,8 +287,21 @@ - - + + + + + + + + + + + + + + + @@ -330,6 +328,35 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs index 883d3f893..b87f14b89 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs @@ -30,7 +30,7 @@ namespace Tango.PPC.UI.Views { public static LayoutView Instance { get; private set; } private LayoutViewVM _vm; - private DispatcherTimer _timer; + private System.Timers.Timer _timer; public LayoutView() { @@ -39,9 +39,9 @@ namespace Tango.PPC.UI.Views Loaded += (_, __) => _vm = DataContext as LayoutViewVM; techPressElement.RegisterForPreviewMouseOrTouchDown(OnMouseOrTouchDown); techPressElement.RegisterForPreviewMouseOrTouchUp(OnMouseOrTouchUp); - _timer = new DispatcherTimer(); - _timer.Interval = TimeSpan.FromSeconds(10); - _timer.Tick += _timer_Tick; + _timer = new System.Timers.Timer(); + _timer.Interval = TimeSpan.FromSeconds(10).TotalMilliseconds; + _timer.Elapsed += _timer_Elapsed; this.PreviewMouseUp += LayoutView_PreviewMouseUp; } @@ -51,10 +51,14 @@ namespace Tango.PPC.UI.Views _vm.ApplicationManager.ResetScreenLockTimer(); } - private void _timer_Tick(object sender, EventArgs e) + private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { _timer.Stop(); - _vm.ToggleTechnicianMode(); + + Dispatcher.BeginInvoke(new Action(() => + { + _vm.ToggleTechnicianMode(); + })); } private void OnMouseOrTouchDown(object sender, MouseOrTouchEventArgs e) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LoadingView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LoadingView.xaml index 79d9cd54b..a917695af 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LoadingView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LoadingView.xaml @@ -10,9 +10,9 @@ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" xmlns:local="clr-namespace:Tango.PPC.UI.Views" mc:Ignorable="d" - d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:LoadingViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.LoadingView}"> + d:DesignHeight="1280" d:DesignWidth="800" Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:LoadingViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.LoadingView}"> - + - - - + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineSetupView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineSetupView.xaml index 9437caac9..40b296d1e 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineSetupView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineSetupView.xaml @@ -25,7 +25,7 @@ - + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml index fba8a599d..beb09be0d 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml @@ -194,8 +194,9 @@ CLOSE - - An error occurred while trying to update the machine. + + Update Failed + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml.cs index f63899932..13a605774 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -37,7 +38,10 @@ namespace Tango.PPC.UI.Views navigationControl.NavigateTo(view.ToString(), () => { - source.SetResult(new object()); + if (!source.Task.IsCompleted) + { + source.SetResult(new object()); + } }); return source.Task; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MainView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MainView.xaml index 6d6d57526..2e36347a3 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MainView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MainView.xaml @@ -7,6 +7,7 @@ xmlns:commonControls="clr-namespace:Tango.PPC.Common.Controls;assembly=Tango.PPC.Common" xmlns:vm="clr-namespace:Tango.PPC.UI.ViewModels" xmlns:global="clr-namespace:Tango.PPC.UI" + xmlns:operations="clr-namespace:Tango.Integration.Operation;assembly=Tango.Integration" xmlns:local="clr-namespace:Tango.PPC.UI.Views" xmlns:notifications="clr-namespace:Tango.PPC.UI.Notifications" xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch" @@ -46,6 +47,21 @@ + + + + + + @@ -53,7 +69,7 @@ + + @@ -89,6 +144,7 @@ + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml new file mode 100644 index 000000000..22952a827 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml @@ -0,0 +1,20 @@ + + + + + Machine is turning Off + Do not unplug machine while turning off + ABORT + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs new file mode 100644 index 000000000..ead34ae12 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Views +{ + /// + /// Interaction logic for LoadingView.xaml + /// + public partial class PowerOffView : UserControl + { + public PowerOffView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingSystemView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingSystemView.xaml index 996b1788d..dd4d2f5d5 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingSystemView.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingSystemView.xaml @@ -10,17 +10,37 @@ mc:Ignorable="d" d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RestartingSystemViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestartingSystemViewVM}" Background="{StaticResource TangoPrimaryBackgroundBrush}"> - - - - - Setup completed. - - - - Restarting the system for the last time... - + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml new file mode 100644 index 000000000..41017f629 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + v + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs new file mode 100644 index 000000000..fabd7b47b --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.PPC.UI.Views +{ + /// + /// Interaction logic for LoadingView.xaml + /// + public partial class RestartingView : UserControl + { + public RestartingView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest index efc5f8179..d72e75011 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest @@ -16,7 +16,7 @@ Remove this element if your application requires this virtualization for backwards compatibility. --> - + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfp b/Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfp new file mode 100644 index 000000000..bc33e385a Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfp differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Updater/IdentityUtils.cs b/Software/Visual_Studio/PPC/Tango.PPC.Updater/IdentityUtils.cs new file mode 100644 index 000000000..3a43be6f9 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Updater/IdentityUtils.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Updater +{ + public static class IdentityUtils + { + [DllImport("advapi32.dll", SetLastError = true)] + static extern bool GetTokenInformation(IntPtr tokenHandle, TokenInformationClass tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength); + + /// + /// Passed to to specify what + /// information about the token to return. + /// + enum TokenInformationClass + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUiAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass + } + + /// + /// The elevation type for a user token. + /// + enum TokenElevationType + { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited + } + + public static bool IsElevated() + { + var identity = WindowsIdentity.GetCurrent(); + if (identity == null) throw new InvalidOperationException("Couldn't get the current user identity"); + var principal = new WindowsPrincipal(identity); + + // Check if this user has the Administrator role. If they do, return immediately. + // If UAC is on, and the process is not elevated, then this will actually return false. + //if (principal.IsInRole(WindowsBuiltInRole.Administrator)) return true; + + //// If we're not running in Vista onwards, we don't have to worry about checking for UAC. + //if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6) + //{ + // // Operating system does not support UAC; skipping elevation check. + // return false; + //} + + int tokenInfLength = Marshal.SizeOf(typeof(int)); + IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength); + + try + { + var token = identity.Token; + var result = GetTokenInformation(token, TokenInformationClass.TokenElevationType, tokenInformation, tokenInfLength, out tokenInfLength); + + if (!result) + { + var exception = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); + throw new InvalidOperationException("Couldn't get token information", exception); + } + + var elevationType = (TokenElevationType)Marshal.ReadInt32(tokenInformation); + + switch (elevationType) + { + case TokenElevationType.TokenElevationTypeDefault: + // TokenElevationTypeDefault - User is not using a split token, so they cannot elevate. + return false; + case TokenElevationType.TokenElevationTypeFull: + // TokenElevationTypeFull - User has a split token, and the process is running elevated. Assuming they're an administrator. + return true; + case TokenElevationType.TokenElevationTypeLimited: + // TokenElevationTypeLimited - User has a split token, but the process is not running elevated. Assuming they're an administrator. + return false; + default: + // Unknown token elevation type. + return false; + } + } + finally + { + if (tokenInformation != IntPtr.Zero) Marshal.FreeHGlobal(tokenInformation); + } + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.png b/Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.png new file mode 100644 index 000000000..26ccc3ecb Binary files /dev/null and b/Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.png differ diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml index a5e63477f..351ca0838 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml @@ -6,12 +6,43 @@ xmlns:local="clr-namespace:Tango.PPC.Updater" mc:Ignorable="d" WindowStyle="None" ResizeMode="NoResize" Width="800" Height="1280"> + + + + + + - + - + + + + + + + + + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml.cs index ae4f22420..8f521c85a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Security.Principal; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -26,16 +27,17 @@ namespace Tango.PPC.Updater private String _sourceFolder = AppDomain.CurrentDomain.BaseDirectory; private String _msProcessName = "Tango.PPC.UI"; private String _appPath; + private bool EMULATE_EXCEPTION = false; public MainWindow() { //Launch debugger.. - //#if DEBUG - // if (!Debugger.IsAttached) - // { - // Debugger.Launch(); - // } - //#endif +#if DEBUG + if (!Debugger.IsAttached) + { + Debugger.Launch(); + } +#endif InitializeComponent(); @@ -56,8 +58,16 @@ namespace Tango.PPC.Updater Width = touch_screen.Bounds.Width; Height = touch_screen.Bounds.Height; } + else + { + Top = 0; + Left = 0; + } ContentRendered += MainWindow_ContentRendered; + + btnRetry.Click += BtnRetry_Click; + btnAbort.Click += BtnAbort_Click; } private void MainWindow_ContentRendered(object sender, EventArgs e) @@ -67,9 +77,34 @@ namespace Tango.PPC.Updater private void Update() { + try + { + ShowProgress(); + + if (!IdentityUtils.IsElevated()) + { + ShowError("The updater utility is not running under elevated permissions and cannot perform.\nThe process will restart."); + var exeName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; + ProcessStartInfo startInfo = new ProcessStartInfo(exeName); + startInfo.Arguments = String.Join(" ", App.StartupArgs); + startInfo.Verb = "runas"; + Process.Start(startInfo); + Environment.Exit(0); + return; + } + } + catch { } + try { Init(); + + if (EMULATE_EXCEPTION) + { + EMULATE_EXCEPTION = false; + throw new InvalidOperationException("This is an emulated error."); + } + EnsureTangoIsDown(); RemoveOldDLLFiles(); ReplaceFiles(); @@ -78,16 +113,31 @@ namespace Tango.PPC.Updater DoEvents(); Thread.Sleep(1000); StartTango(true); + Exit(); } catch (Exception ex) { - ShowError($"Update failed.\n{ex.Message}"); - StartTango(false); + ShowFailed(ex); } - finally + } + + private void Exit() + { + try { - Environment.Exit(0); + foreach (var file in Directory.GetFiles(_sourceFolder, "*.*", SearchOption.AllDirectories)) + { + try + { + File.Delete(file); + } + catch { } + } } + catch { } + + + Environment.Exit(0); } private void Init() @@ -95,6 +145,11 @@ namespace Tango.PPC.Updater try { _appPath = String.Join(" ", App.StartupArgs); + + if (!_appPath.EndsWith("\\")) + { + _appPath += "\\"; + } } catch { @@ -118,12 +173,18 @@ namespace Tango.PPC.Updater { p.StartInfo.Arguments = "-update_ok"; } + else + { + p.StartInfo.Arguments = "-update_failed"; + } p.Start(); } private void ReplaceFiles() { + txtStatus.Text = "Updating files..."; + int maxProgress = Directory.GetFiles(_sourceFolder, "*.*", SearchOption.AllDirectories).Length; int progress = 0; @@ -143,7 +204,6 @@ namespace Tango.PPC.Updater { try { - txtStatus.Text = "Copying file " + Path.GetFileName(newPath); DoEvents(); File.Copy(newPath, newPath.Replace(_sourceFolder, _appPath), true); @@ -151,8 +211,6 @@ namespace Tango.PPC.Updater prog.Maximum = maxProgress; prog.Value = progress++; DoEvents(); - - Thread.Sleep(10); } catch (Exception ex) { @@ -185,37 +243,49 @@ namespace Tango.PPC.Updater { Process appProcess = null; - int tries = 0; - - do + for (int i = 0; i < 20; i++) { - appProcess = Process.GetProcessesByName(_msProcessName).FirstOrDefault(); - Process p = new Process(); - p.StartInfo.CreateNoWindow = true; - p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; - p.StartInfo.FileName = "wmic"; - p.StartInfo.Arguments = String.Format("process where name='{0}' delete", _msProcessName); + try + { + appProcess = Process.GetProcessesByName(_msProcessName).FirstOrDefault(); + } + catch + { + Thread.Sleep(1000); + continue; + } if (appProcess != null) { - tries++; - appProcess.Kill(); + try + { + appProcess.Kill(); + } + catch { } try { + Process p = new Process(); + p.StartInfo.CreateNoWindow = true; + p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + p.StartInfo.FileName = "wmic"; + p.StartInfo.Arguments = String.Format("process where name='{0}' delete", _msProcessName); p.Start(); } catch { } - - Thread.Sleep(1000); } - - if (tries > 10) + else { - throw new IOException("The main Tango process seems to in a frozen state. Please restart your computer and try again."); + break; } - } while (appProcess != null); + Thread.Sleep(1000); + } + + if (appProcess != null) + { + throw new IOException("The main Tango process seems to in a frozen state. Please restart your computer and try again."); + } } /// @@ -230,5 +300,49 @@ namespace Tango.PPC.Updater { MessageBox.Show(error, "Tango Update", MessageBoxButton.OK, MessageBoxImage.Error); } + + private bool ShowErrorRetry(String error) + { + var result = MessageBox.Show(error + "\n" + "Press yes to retry.", "Tango Update", MessageBoxButton.YesNo, MessageBoxImage.Error); + return result == MessageBoxResult.Yes; + } + + private void ShowProgress() + { + stackProgress.Visibility = Visibility.Visible; + stackFailed.Visibility = Visibility.Collapsed; + } + + private void ShowFailed(Exception ex) + { + try + { + using (EventLog eventLog = new EventLog("Application")) + { + eventLog.Source = "PPC Updater"; + eventLog.WriteEntry($"PPC Updater Failed\n{ex.ToString()}", EventLogEntryType.Error, 101, 1); + } + } + catch { } + + stackProgress.Visibility = Visibility.Collapsed; + stackFailed.Visibility = Visibility.Visible; + txtError.Text = ex.Message; + } + + private void BtnAbort_Click(object sender, RoutedEventArgs e) + { + ShowProgress(); + txtStatus.Text = "Update failed. Restoring previous application state..."; + DoEvents(); + Thread.Sleep(1000); + StartTango(false); + Exit(); + } + + private void BtnRetry_Click(object sender, RoutedEventArgs e) + { + Update(); + } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj index 3f232c4d2..8f8430102 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj @@ -67,6 +67,7 @@ App.xaml Code + MainWindow.xaml Code @@ -102,6 +103,9 @@ + + + diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Auth2.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Auth2.cs new file mode 100644 index 000000000..6ba278511 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Auth2.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Packages.Auth2 +{ + [PPCPackage(PackageType.Pre, "Applying Auth2 Patch", false)] + public class Auth2 : ExtendedObject, IPPCPackage + { + public Task Run(PackageContext context) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Starting Auth2 package procedure..."); + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + using (var transaction = db.Database.BeginTransaction()) + { + LogManager.Log("Setting all jobs users to null..."); + context.ReportProgress("Modifying jobs..."); + db.Database.ExecuteSqlCommand("ALTER TABLE JOBS ALTER COLUMN USER_GUID VARCHAR(36) NULL"); + db.Database.ExecuteSqlCommand("UPDATE JOBS SET USER_GUID = NULL"); + + Thread.Sleep(1000); + + LogManager.Log("Setting all job runs users to null..."); + context.ReportProgress("Modifying job runs..."); + db.Database.ExecuteSqlCommand("UPDATE JOB_RUNS SET USER_GUID = NULL"); + + Thread.Sleep(1000); + + LogManager.Log("Setting all events users to null..."); + context.ReportProgress("Modifying events..."); + db.Database.ExecuteSqlCommand("UPDATE MACHINES_EVENTS SET USER_GUID = NULL"); + + Thread.Sleep(1000); + + LogManager.Log("Removing all users..."); + context.ReportProgress("Modifying users..."); + db.Database.ExecuteSqlCommand("DELETE FROM USERS"); + + Thread.Sleep(1000); + + LogManager.Log("Removing redundant addresses..."); + context.ReportProgress("Modifying addresses..."); + db.Database.ExecuteSqlCommand(@" +DELETE ADDRESSES FROM ADDRESSES +FULL JOIN ORGANIZATIONS ON ORGANIZATIONS.ADDRESS_GUID = ADDRESSES.GUID +WHERE ORGANIZATIONS.ADDRESS_GUID IS NULL"); + + Thread.Sleep(1000); + + LogManager.Log("Removing redundant contacts..."); + context.ReportProgress("Modifying contacts..."); + db.Database.ExecuteSqlCommand(@" +DELETE CONTACTS FROM CONTACTS +FULL JOIN ORGANIZATIONS ON ORGANIZATIONS.CONTACT_GUID = CONTACTS.GUID +WHERE ORGANIZATIONS.CONTACT_GUID IS NULL"); + + Thread.Sleep(1000); + + LogManager.Log("Committing transaction..."); + context.ReportProgress("Committing transaction..."); + transaction.Commit(); + } + } + + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..998c2463e --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.Packages.Auth2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.Packages.Auth2")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ea4233f1-4b7b-4ccf-a6de-2d17612eba90")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Tango.PPC.Packages.Auth2.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Tango.PPC.Packages.Auth2.csproj new file mode 100644 index 000000000..bd91c2b60 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Tango.PPC.Packages.Auth2.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {EA4233F1-4B7B-4CCF-A6DE-2D17612EBA90} + Library + Properties + Tango.PPC.Packages.Auth2 + Tango.PPC.Packages.Auth2 + v4.6.1 + 512 + true + + + true + full + false + ..\..\..\Build\PPC\Debug\Packages\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\Packages\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll + False + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll + False + + + + + + + + + + + + + + + + + + {F441FEEE-322A-4943-B566-110E12FD3B72} + Tango.BL + False + + + {A34EE0F0-649D-41C8-8489-B6F1CC6924EE} + Tango.Core + False + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + False + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + False + + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/app.config b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/app.config new file mode 100644 index 000000000..4e9a59d89 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/app.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/packages.config b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/packages.config new file mode 100644 index 000000000..b3daf0d6c --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs new file mode 100644 index 000000000..a4ea5dc4f --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.Helpers; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; +using Tango.Transport.Web; + +namespace Tango.PPC.Packages.CefInstaller +{ + [PPCPackage(PackageType.Post, "Installing Web Browser", true)] + public class CefInstaller : ExtendedObject, IPPCPackage + { + public Task Run(PackageContext context) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Downloading cef binaries..."); + + var zipFile = TemporaryManager.CreateImaginaryFile(); + + try + { + using (AutoFileDownloader downloader = new AutoFileDownloader("https://tangostorage.blob.core.windows.net/resources/CefSharpOutput.zip", "https://tango.azureedge.net/resources/CefSharpOutput.zip", zipFile)) + { + downloader.Progress += (x, e) => + { + context.ReportProgress("Downloading cef binaries...", false, e.Current, e.Total); + }; + + downloader.Download().GetAwaiter().GetResult(); + } + + using (ZipArchive zip = ZipFile.OpenRead(zipFile)) + { + zip.ExtractToDirectory(context.ApplicationManager.StartPath, true); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error installing cef binaries."); + throw; + } + finally + { + zipFile.Delete(); + } + + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..9ddf67db3 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.Packages.CefInstaller")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.Packages.CefInstaller")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("df64460a-6617-4338-872a-dc43fd994c48")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj new file mode 100644 index 000000000..8e7ec8253 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {DF64460A-6617-4338-872A-DC43FD994C48} + Library + Properties + Tango.PPC.Packages.CefInstaller + Tango.PPC.Packages.CefInstaller + v4.6.1 + 512 + true + + + true + full + false + ..\..\..\Build\PPC\Debug\Packages\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\Packages\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {A34EE0F0-649D-41C8-8489-B6F1CC6924EE} + Tango.Core + False + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + False + + + {74e700b0-1156-4126-be40-ee450d3c3026} + Tango.Transport + False + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + False + + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/App.config b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/App.config new file mode 100644 index 000000000..9a2bcbea4 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/App.config @@ -0,0 +1,49 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/JobRunsStartTimePatch.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/JobRunsStartTimePatch.cs new file mode 100644 index 000000000..eb5aef8ef --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/JobRunsStartTimePatch.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Packages.JobRunsStartTimePatch +{ + [PPCPackage(PackageType.Pre, "JobRuns StartTime Patch", false)] + public class JobRunsStartTimePatch : ExtendedObject, IPPCPackage + { + public Task Run(PackageContext context) + { + return Task.Factory.StartNew(() => + { + try + { + LogManager.Log("Fixing corrupted job runs start time values..."); + + context.ReportProgress("Applying corrupted job runs start date patch..."); + + Thread.Sleep(5000); //Just so we can see something happened. + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + db.Database.ExecuteSqlCommand("UPDATE JOB_RUNS SET START_DATE = ACTUAL_START_DATE WHERE START_DATE = '0001-01-01 00:00:00.000';"); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred while trying to apply job runs start date patch."); + } + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5d8c8d19b --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.Packages.JobRunsStartTimePatch")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.Packages.JobRunsStartTimePatch")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("59643abc-df9a-497f-8a7c-4a131c7cf438")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Tango.PPC.Packages.JobRunsStartTimePatch.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Tango.PPC.Packages.JobRunsStartTimePatch.csproj new file mode 100644 index 000000000..81435b4ba --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Tango.PPC.Packages.JobRunsStartTimePatch.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {59643ABC-DF9A-497F-8A7C-4A131C7CF438} + Library + Properties + Tango.PPC.Packages.JobRunsStartTimePatch + Tango.PPC.Packages.JobRunsStartTimePatch + v4.6.1 + 512 + true + + + true + full + false + ..\..\..\Build\PPC\Debug\Packages\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\Packages\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll + False + + + ..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll + False + + + + + + + + + + + + + + + + + + {F441FEEE-322A-4943-B566-110E12FD3B72} + Tango.BL + False + + + {A34EE0F0-649D-41C8-8489-B6F1CC6924EE} + Tango.Core + False + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + False + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + False + + + {208C8BD8-72C6-4E3C-ACAA-351091A2ACC7} + Tango.PPC.Shared + False + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/packages.config b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/packages.config new file mode 100644 index 000000000..b3daf0d6c --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ce0d97e8c --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.Packages.SamplePostPackage")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.Packages.SamplePostPackage")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("da391b02-ae28-4ea1-a80f-d0f4c8029ffa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs new file mode 100644 index 000000000..f6fb2c935 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Packages.SamplePostPackage +{ + [PPCPackage(PackageType.Post, "Sample Post Package", false)] + public class SamplePostPackage : ExtendedObject, IPPCPackage + { + public Task Run(PackageContext context) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Hi from 'Sample Post Package'.. !!! ____________"); + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj new file mode 100644 index 000000000..d528c5c14 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {DA391B02-AE28-4EA1-A80F-D0F4C8029FFA} + Library + Properties + Tango.PPC.Packages.SamplePostPackage + Tango.PPC.Packages.SamplePostPackage + v4.6.1 + 512 + true + + + true + full + false + ..\..\..\Build\PPC\Debug\Packages\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\Packages\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} + Tango.Core + False + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + False + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + False + + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Properties/AssemblyInfo.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..24117be29 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.PPC.Packages.SamplePrePackage")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.PPC.Packages.SamplePrePackage")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2cd12594-3522-4658-a65f-190ee58b6afa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs new file mode 100644 index 000000000..1913d3f28 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.PPC.Common.UpdatePackages; +using Tango.PPC.Shared.Updates; + +namespace Tango.PPC.Packages.SamplePrePackage +{ + [PPCPackage(PackageType.Pre, "Sample Pre Package", false)] + public class SamplePrePackage : ExtendedObject, IPPCPackage + { + public Task Run(PackageContext context) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Hi from 'Sample Pre Package'.. !!! ____________"); + }); + } + } +} diff --git a/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj new file mode 100644 index 000000000..4437a05c4 --- /dev/null +++ b/Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {2CD12594-3522-4658-A65F-190EE58B6AFA} + Library + Properties + Tango.PPC.Packages.SamplePrePackage + Tango.PPC.Packages.SamplePrePackage + v4.6.1 + 512 + true + + + true + full + false + ..\..\..\Build\PPC\Debug\Packages\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\Build\PPC\Release\Packages\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {A34EE0F0-649D-41C8-8489-B6F1CC6924EE} + Tango.Core + False + + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + False + + + {0be74eee-22cb-4dba-b896-793b9e1a3ac0} + Tango.PPC.Common + False + + + {208c8bd8-72c6-4e3c-acaa-351091a2acc7} + Tango.PPC.Shared + False + + + + \ No newline at end of file -- cgit v1.3.1