aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/PPC
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy@twine-s.com>2020-12-30 15:11:34 +0000
committerRoy Ben Shabat <Roy@twine-s.com>2020-12-30 15:11:34 +0000
commitd33c19b3ac6803de4b5c8d475832efef131c1a45 (patch)
treeea725abc39def99a755b041c13cba1fe0d594ddc /Software/Visual_Studio/PPC
parent1bdcaa9f51303bbff682507f31fb3b4414692ca4 (diff)
downloadTango-d33c19b3ac6803de4b5c8d475832efef131c1a45.tar.gz
Tango-d33c19b3ac6803de4b5c8d475832efef131c1a45.zip
Revert "Hope it is fine"
Diffstat (limited to 'Software/Visual_Studio/PPC')
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/App.xaml11
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/BackupRestoreModule.cs84
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.pngbin0 -> 3044 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.pngbin0 -> 89496 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.pngbin0 -> 3252 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/AssemblyInfo.cs20
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.Designer.cs63
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.Designer.cs26
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Tango.PPC.BackupRestore.csproj246
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModelLocator.cs95
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupCompletedViewVM.cs20
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupErrorViewVM.cs37
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/BackupViewVM.cs163
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/MainViewVM.cs34
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreCompletedViewVM.cs51
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreErrorViewVM.cs38
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/RestoreViewVM.cs168
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/ViewModels/WelcomeViewVM.cs48
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml37
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupCompletedView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml39
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupErrorView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml38
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupProgressView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml99
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/BackupView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml39
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/MainView.xaml.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml37
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreCompletedView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml39
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreErrorView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml38
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreProgressView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml160
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/RestoreView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml72
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Views/WelcomeView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/app.config61
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/packages.config7
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/App.xaml11
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Attributes/BoundObjectAttribute.cs20
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BoundsObjects/KeyboardHandler.cs66
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/BrowserModule.cs101
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zipbin0 -> 143444091 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Helpers/BoundObjectsHelper.cs72
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.pngbin0 -> 2539 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Navigation/BrowserNavigationRequest.cs19
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/AssemblyInfo.cs20
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.Designer.cs63
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.Designer.cs26
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/RequestHandlers/ChromiumRequestHandler.cs114
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Scripts/keyboard.js21
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Tango.PPC.Browser.csproj199
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewContracts/IBrowserView.cs18
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModelLocator.cs32
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/ViewModels/BrowserViewVM.cs134
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml77
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/BrowserView.xaml.cs211
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml23
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Views/ErrorView.xaml.cs29
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/app.config90
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/packages.config11
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/BugReportingModule.cs2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/TFS/TeamFoundationServicePPCClient.cs73
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/Tango.PPC.BugReporting_txujxqrg_wpftmp.csproj235
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.BugReporting/ViewModelLocator.cs2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Converters/MachineEventToViewConverter.cs7
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml26
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/EventsViews/ThreadBreakView.xaml.cs49
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Resources/Styles.xaml4
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Tango.PPC.Events.csproj9
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/ViewModels/MainViewVM.cs32
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Views/MainView.xaml8
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppBarItems/JobProgressAppBarItemView.xaml5
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/AppButtons/StartPrintingButton.cs4
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobOutlineControl.cs319
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/JobSummeryViewer.xaml3
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Controls/RunningJobViewer.xaml3
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Converters/ColorSpaceToVisibilityConverter.cs12
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionView.xaml68
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/AdvancedColorCorrectionViewVM.cs2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/BasicColorCorrectionView.xaml9
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/CatalogSelectionView.xaml2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Dialogs/ImportJobView.xaml2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpgbin0 -> 27097 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpgbin0 -> 10743 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.pngbin0 -> 1171 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.pngbin0 -> 4127 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.pngbin0 -> 6743 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItem.cs32
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/NotificationItems/NewSynchronizardJobsNotificationItemView.xaml.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Tango.PPC.Jobs.csproj26
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobProgressViewVM.cs108
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobSummeryViewVM.cs37
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobViewVM.cs149
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/JobsViewVM.cs186
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/ViewModels/MainViewVM.cs66
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobProgressView.xaml138
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobSummeryView.xaml2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml321
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobView.xaml.cs16
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Views/JobsView.xaml14
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/MachineSettingsModule.cs2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/ViewModels/MainViewVM.cs229
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml186
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/App.xaml11
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/HomingMotorCommand.cs80
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseDyeingHeadCommand.cs31
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseLeftLeadingWheelsCommand.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseMotorCommand.cs158
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/OpenCloseRightLeadingWheelsCommand.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Commands/ResetThreadLoadingCommand.cs24
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Controls/StateTouchButton.cs109
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToBrushConverter.cs74
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/LiquidTypeToShortNameConverter.cs41
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/MidTankLevelToElementHeightConverter.cs34
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Converters/StringToFirstLetterConverter.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml66
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/CleanerDispensingViewVM.cs128
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml56
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Dialogs/HeadCleaningViewVM.cs150
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideBase.cs35
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/GuideStep.cs21
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/HandleWasteCartridgeGuide.cs43
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadInkCartridgeGuide.cs43
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/LoadNewThreadGuide.cs43
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceAirFilterGuide.cs43
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Guides/ReplaceThreadGuide.cs43
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Helpers/GuideHelper.cs33
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gifbin0 -> 4092741 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gifbin0 -> 4197318 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gifbin0 -> 3500573 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gifbin0 -> 13319358 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gifbin0 -> 3567850 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.pngbin0 -> 2174 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.pngbin0 -> 2266 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.pngbin0 -> 2228 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.pngbin0 -> 138220 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.pngbin0 -> 2269 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.pngbin0 -> 2175 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.pngbin0 -> 892 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.pngbin0 -> 1440 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.pngbin0 -> 1497 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.pngbin0 -> 2035 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.pngbin0 -> 1152 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.pngbin0 -> 3454 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.pngbin0 -> 4125 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.pngbin0 -> 3018 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.pngbin0 -> 2099 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.pngbin0 -> 44260 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.pngbin0 -> 2075 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.pngbin0 -> 19717 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.pngbin0 -> 194234 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.pngbin0 -> 686 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.pngbin0 -> 1663 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.pngbin0 -> 926 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.pngbin0 -> 928 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.pngbin0 -> 927 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.pngbin0 -> 7209 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceCommand.cs81
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/MaintenanceModule.cs84
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/MidTankLevelModel.cs35
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Models/OverallTemperatureModel.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/AssemblyInfo.cs20
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.Designer.cs63
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.Designer.cs26
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Resources/Guides.xaml60
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Tango.PPC.Maintenance.csproj320
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Themes/Generic.xaml9
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModelLocator.cs56
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/GeneralGuideViewVM.cs40
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MainViewVM.cs31
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/ViewModels/MaintenanceViewVM.cs324
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml55
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/GeneralGuideView.xaml.cs33
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml22
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MainView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml341
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Views/MaintenanceView.xaml.cs30
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/app.config61
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/packages.config11
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Models/StorageNavigationIntent.cs4
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/StorageModule.cs2
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/ViewModels/MainViewVM.cs60
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Storage/Views/MainView.xaml70
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml80
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/EmbeddedLogItemDetailsViewVM.cs21
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml74
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/SynchronizationDetailsViewVM.cs22
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml87
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Dialogs/UpdateDetailsViewVM.cs21
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.pngbin0 -> 2539 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.pngbin0 -> 2492 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.pngbin0 -> 4349 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.pngbin0 -> 1784 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.pngbin0 -> 4438 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.pngbin0 -> 1781 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.pngbin0 -> 4186 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.pngbin0 -> 3703 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.pngbin0 -> 4127 bytes
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Tango.PPC.Technician.csproj71
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModelLocator.cs36
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/CatalogViewVM.cs23
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/LoggingViewVM.cs125
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/MainViewVM.cs4
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/PackagesViewVM.cs44
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/RemoteConnectionsViewVM.cs64
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/SystemViewVM.cs87
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/ViewModels/UpdatesViewVM.cs107
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/CatalogView.xaml130
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/LoggingView.xaml178
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/MainView.xaml3
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml103
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/PackagesView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml88
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/RemoteConnectionsView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/SystemView.xaml313
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml160
-rw-r--r--Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Views/UpdatesView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Application/IPPCApplicationManager.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Authentication/IAuthenticationProvider.cs11
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupFile.cs81
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupMode.cs23
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreProgressEventArgs.cs36
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupRestoreStage.cs63
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/BackupSettings.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/DefaultBackupManager.cs604
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/IBackupManager.cs43
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreResult.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/BackupRestore/RestoreSettings.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/DefaultMachineProvider.cs136
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Connection/IMachineProvider.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Connectivity/IConnectivityProvider.cs7
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Console/DefaultConsoleEngineService.cs92
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Console/IConsoleEngineService.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.cs114
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/ImageGalleryControl.xaml101
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/DefaultDataStoreService.cs492
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/DataStore/IDataStoreService.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/DefaultEventLogger.cs61
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/EventLogging/IEventLogger.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs36
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs433
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperation.cs51
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs (renamed from Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs)7
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/IFileSystemService.cs20
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/KeyboardHelper.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Helpers/LogsHelper.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/IPPCService.cs36
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.pngbin0 -> 3454 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.pngbin0 -> 194234 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs154
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/IInsightsService.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs200
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs59
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs1451
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Models/FineTuneItem.cs2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/INavigationManager.cs17
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Navigation/NavigationView.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarItem.cs10
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/AppBarPriority.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/INotificationProvider.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItem.cs25
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItem.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Notifications/NotificationItems/MessageNotificationItemView.xaml14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/OS/DefaultOperationSystemManager.cs22
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/OS/IOperationSystemManager.cs11
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs190
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/PPCViewModel.cs50
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/DefaultPerformanceService.cs219
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Performance/IPerformanceService.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.Designer.cs22
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Properties/Resources.resx20
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs97
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishInfo.cs22
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PublishOptions.cs25
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteActions/IRemoteActionsService.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/DefaultRemoteAssistanceProvider.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteAssistance/IRemoteAssistanceProvider.cs4
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs584
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/IRemoteDesktopService.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/RemoteDesktopClient.cs20
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/DefaultRemoteJobService.cs177
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteJob/IRemoteJobService.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Colors.xaml11
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml10
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Styles.xaml65
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.pngbin0 -> 1005 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.pngbin0 -> 1316 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs59
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SafetyLevelOperations.csv3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/DefaultStorageProvider.cs23
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Storage/IStorageProvider.cs6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/DefaultMachineDataSynchronizer.cs662
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/IMachineDataSynchronizer.cs26
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationEndedEventArgs.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationState.cs23
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatus.cs47
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Synchronization/SynchronizationStatusChangedEventArgs.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/DefaultSystemInfoService.cs138
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SystemInfo/ISystemInfoService.cs17
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj141
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/ThreadLoading/IThreadLoadingService.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/AlternativeUnifiedWriteFilterManager.cs48
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/DefaultUnifiedWriteFilterManager.cs35
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UWF/IUnifiedWriteFilterManager.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/DefaultPackageRunner.cs362
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPPCPackage.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/IPackageRunner.cs18
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PPCPackageAttribute.cs26
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageContext.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageProgressEventArgs.cs17
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageRunnerResult.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackageStateChangedEventArgs.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/UpdatePackages/PackagesFile.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateRequest.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/CheckForUpdateResponse.cs10
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataRequest.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadMachineDataResponse.cs27
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateRequest.cs2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/DownloadUpdateResponse.cs6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LatestVersionResponse.cs1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/LoginRequest.cs1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupRequest.cs1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineSetupResponse.cs7
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedRequest.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/MachineUpdateCompletedResponse.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedRequest.cs27
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/NotifyMachineDataDownloadCompletedResponse.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClient.cs5
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/PPCWebClientBase.cs45
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/SynchronizationFailedEntity.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBRequest.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdateDBResponse.cs1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UpdatedEntity.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataRequest.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Web/UploadMachineDataResponse.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/packages.config1
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/App.config28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Program.cs107
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/Tango.PPC.DataSynchronizer.CLI.csproj75
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.DataSynchronizer.CLI/packages.config4
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindow.xaml19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/MainWindowVM.cs27
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.csproj6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Publisher.UI/Tango.PPC.Publisher.UI.json164
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/App.config6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Program.cs54
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.SchemaSynchronizer.CLI/Tango.PPC.SchemaSynchronizer.CLI.csproj63
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventRequest.cs20
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Events/PushEmulatedEventResponse.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationRequest.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/GetMachineInformationResponse.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Information/InformationPackage.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsDownloadCompletedResponse.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateRequest.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsMinDateResponse.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsRequest.cs25
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Insights/InsightsResponse.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobProgress.cs21
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobStage.cs18
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Jobs/RemoteJobUpdateResponse.cs22
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/GetLogFilesResponse.cs18
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFile.cs17
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Logs/RemoteLogFileType.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/PerformancePackage.cs25
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesRequest.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Performance/StartPerformanceUpdatesResponse.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/AssemblyInfo.cs23
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.Designer.cs62
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.Designer.cs30
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteActions/SimulateApplicationExceptionResponse.cs12
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeRequest.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteApplicationUpgradeResponse.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/RemoteUpgrade/StartRemoteFirmwareUpgradeResponse.cs24
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumn.cs52
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlColumnCollection.cs78
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlDataSet.cs188
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/RemoteSqlRow.cs153
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj148
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Themes/Generic.xaml6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/GetUpdatesAndPackagesResponse.cs22
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallation.cs26
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageInstallationState.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Updates/PackageType.cs14
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/App.config7
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs102
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml30
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItem.cs31
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml30
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerUpAppBarItemView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Authentication/DefaultAuthenticationProvider.cs18
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Connectivity/DefaultConnectivityProvider.cs44
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml49
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Controls/MachineStatusControl.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/FirmwareUpgradeFromFileViewVM.cs15
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml62
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/InsufficientLiquidQuantityView.xaml.cs6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml32
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpView.xaml.cs34
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/PowerUpViewVM.cs128
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml52
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/SafetyLevelOperationsConfirmationViewVM.cs82
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml225
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadBreakViewVM.cs245
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml170
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/ThreadLoadingViewVM.cs287
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileView.xaml21
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Dialogs/UpdateFromFileViewVM.cs8
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.pngbin0 -> 810 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.pngbin0 -> 586 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.pngbin0 -> 844 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.pngbin0 -> 1190 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.pngbin0 -> 1834 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpgbin0 -> 57998 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpgbin0 -> 58057 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpgbin0 -> 59306 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpgbin0 -> 55777 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPGbin0 -> 50823 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPGbin0 -> 36100 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPGbin0 -> 52652 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPGbin0 -> 62531 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpgbin0 -> 50823 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpgbin0 -> 36100 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpgbin0 -> 52652 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpgbin0 -> 62531 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpgbin0 -> 123123 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPGbin0 -> 47345 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpgbin0 -> 70545 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPGbin0 -> 50823 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPGbin0 -> 36100 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPGbin0 -> 85970 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPGbin0 -> 123123 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPGbin0 -> 67829 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpgbin0 -> 229536 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpgbin0 -> 94899 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpgbin0 -> 67243 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpgbin0 -> 39336 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpgbin0 -> 36100 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpgbin0 -> 45420 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpgbin0 -> 46782 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpgbin0 -> 49932 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.pngbin0 -> 3044 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.pngbin0 -> 89496 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.pngbin0 -> 3956 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gifbin0 -> 798338 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.pngbin0 -> 138220 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gifbin0 -> 397334 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gifbin0 -> 32040 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gifbin0 -> 380322 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.pngbin0 -> 3252 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gifbin0 -> 4092741 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.pngbin0 -> 7209 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.pngbin0 -> 529370 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.pngbin0 -> 2856 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/InternalModule.cs84
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/MainWindow.xaml.cs21
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs (renamed from Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs)8
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Navigation/DefaultNavigationManager.cs382
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/DefaultNotificationProvider.cs128
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItem.cs52
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml30
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Notifications/NotificationItems/UpdateAvailableNotificationItemView.xaml.cs30
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/PPCApplication/DefaultPPCApplicationManager.cs252
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Printing/DefaultPrintingManager.cs6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Properties/AssemblyInfo.cs2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/RemoteActions/DefaultRemoteActionsService.cs54
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Resources/Colors.xaml2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Tango.PPC.UI.csproj223
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ThreadLoading/DefaultThreadLoadingService.cs65
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs84
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/ExternalBridgeViewVM.cs52
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/InternalModuleViewVM.cs17
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LayoutViewVM.cs250
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoadingViewVM.cs65
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/LoginViewVM.cs8
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineSetupViewVM.cs5
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MachineUpdateViewVM.cs536
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/MainViewVM.cs154
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/PowerOffViewVM.cs134
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModels/RestartingViewVM.cs27
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/EmergencyView.xaml16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/ExternalBridgeView.xaml19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml18
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml131
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml.cs16
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LoadingView.xaml11
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineSetupView.xaml2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml5
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MachineUpdateView.xaml.cs6
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/MainView.xaml58
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml20
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/PowerOffView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingSystemView.xaml40
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml52
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/Views/RestartingView.xaml.cs28
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfpbin0 -> 270787 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Updater/IdentityUtils.cs118
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.pngbin0 -> 8947 bytes
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml35
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Updater/MainWindow.xaml.cs174
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Updater/Tango.PPC.Updater.csproj4
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Auth2.cs79
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/Tango.PPC.Packages.Auth2.csproj88
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/app.config39
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.Auth2/packages.config4
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/CefInstaller.cs58
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.CefInstaller/Tango.PPC.Packages.CefInstaller.csproj77
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/App.config49
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/JobRunsStartTimePatch.cs41
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/Tango.PPC.Packages.JobRunsStartTimePatch.csproj88
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.JobRunsStartTimePatch/packages.config4
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/SamplePostPackage.cs23
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePostPackage/Tango.PPC.Packages.SamplePostPackage.csproj70
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/SamplePrePackage.cs23
-rw-r--r--Software/Visual_Studio/PPC/UpdatePackages/Tango.PPC.Packages.SamplePrePackage/Tango.PPC.Packages.SamplePrePackage.csproj70
557 files changed, 26913 insertions, 1414 deletions
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 @@
+<Application x:Class="Tango.PPC.BackupRestore.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Resources/Merged.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+ </Application.Resources>
+</Application> \ 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
+{
+ /// <summary>
+ /// Represents a PPC <see cref="BackupRestoreModule"/>.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
+ [PPCModule(20)]
+ public class BackupRestoreModule : PPCModuleBase
+ {
+ /// <summary>
+ /// Gets the module name.
+ /// </summary>
+ public override string Name
+ {
+ get
+ {
+ return "Backup & Restore";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module description.
+ /// </summary>
+ public override string Description
+ {
+ get
+ {
+ return "Tango Backup/Restore Module";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module cover image.
+ /// </summary>
+ public override BitmapSource Image
+ {
+ get
+ {
+ return ResourceHelper.GetImageFromResources("Images/backup-big.png");
+ }
+ }
+
+ /// <summary>
+ /// Gets the module entry point view type.
+ /// </summary>
+ public override Type MainViewType
+ {
+ get
+ {
+ return typeof(MainView);
+ }
+ }
+
+ /// <summary>
+ /// Gets the permission required to see and load this module.
+ /// </summary>
+ public override Permissions Permission
+ {
+ get
+ {
+ return Permissions.RunPPC;
+ }
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-big.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/backup-restore.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.BackupRestore/Images/restore.png
Binary files 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.PPC.BackupRestore.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // 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() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [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;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+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 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{BC2753F8-C0F7-48F5-A85C-149EC7A2F8C7}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.PPC.BackupRestore</RootNamespace>
+ <AssemblyName>Tango.PPC.BackupRestore</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ </Reference>
+ <Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\RestoreCompletedView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\BackupCompletedView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\RestoreErrorView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\BackupErrorView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\RestoreProgressView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\BackupProgressView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\BackupView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\MainView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\RestoreView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\WelcomeView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="BackupRestoreModule.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="ViewModelLocator.cs" />
+ <Compile Include="ViewModels\RestoreCompletedViewVM.cs" />
+ <Compile Include="ViewModels\RestoreErrorViewVM.cs" />
+ <Compile Include="ViewModels\BackupViewVM.cs" />
+ <Compile Include="ViewModels\BackupCompletedViewVM.cs" />
+ <Compile Include="ViewModels\BackupErrorViewVM.cs" />
+ <Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="ViewModels\RestoreViewVM.cs" />
+ <Compile Include="ViewModels\WelcomeViewVM.cs" />
+ <Compile Include="Views\RestoreCompletedView.xaml.cs">
+ <DependentUpon>RestoreCompletedView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\BackupCompletedView.xaml.cs">
+ <DependentUpon>BackupCompletedView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\RestoreErrorView.xaml.cs">
+ <DependentUpon>RestoreErrorView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\BackupErrorView.xaml.cs">
+ <DependentUpon>BackupErrorView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\RestoreProgressView.xaml.cs">
+ <DependentUpon>RestoreProgressView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\BackupProgressView.xaml.cs">
+ <DependentUpon>BackupProgressView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\BackupView.xaml.cs">
+ <DependentUpon>BackupView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\MainView.xaml.cs">
+ <DependentUpon>MainView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\RestoreView.xaml.cs">
+ <DependentUpon>RestoreView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\WelcomeView.xaml.cs">
+ <DependentUpon>WelcomeView.xaml</DependentUpon>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.DragAndDrop\Tango.DragAndDrop.csproj">
+ <Project>{b112d89a-a106-41ae-a0c1-4abc84c477f5}</Project>
+ <Name>Tango.DragAndDrop</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Explorer\Tango.Explorer.csproj">
+ <Project>{4399AF76-DB52-4CFB-8020-6F85BDB29FD5}</Project>
+ <Name>Tango.Explorer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Settings\Tango.Settings.csproj">
+ <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project>
+ <Name>Tango.Settings</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Touch\Tango.Touch.csproj">
+ <Project>{fd86424c-6e84-491b-8df9-3d0f5c236a2a}</Project>
+ <Name>Tango.Touch</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Tango.PPC.Storage\Tango.PPC.Storage.csproj">
+ <Project>{04FEBB02-F782-4B96-B47D-F6902AFA43BE}</Project>
+ <Name>Tango.PPC.Storage</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\backup-big.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\backup-restore.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\restore.png" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ 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
+ {
+ /// <summary>
+ /// Initializes a new instance of the ViewModelLocator class.
+ /// </summary>
+ static ViewModelLocator()
+ {
+ TangoIOC.Default.Register<MainViewVM>();
+ TangoIOC.Default.Register<WelcomeViewVM>();
+ TangoIOC.Default.Register<BackupViewVM>();
+ TangoIOC.Default.Register<RestoreViewVM>();
+ TangoIOC.Default.Register<BackupErrorViewVM>();
+ TangoIOC.Default.Register<BackupCompletedViewVM>();
+ TangoIOC.Default.Register<RestoreErrorViewVM>();
+ TangoIOC.Default.Register<RestoreCompletedViewVM>();
+ }
+
+ /// <summary>
+ /// Gets the main view VM.
+ /// </summary>
+ public static MainViewVM MainViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<MainViewVM>();
+ }
+ }
+
+ public static WelcomeViewVM WelcomeViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<WelcomeViewVM>();
+ }
+ }
+
+ public static BackupViewVM BackupViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<BackupViewVM>();
+ }
+ }
+
+ public static RestoreViewVM RestoreViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<RestoreViewVM>();
+ }
+ }
+
+ public static BackupErrorViewVM BackupErrorViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<BackupErrorViewVM>();
+ }
+ }
+
+ public static BackupCompletedViewVM BackupCompletedViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<BackupCompletedViewVM>();
+ }
+ }
+
+ public static RestoreErrorViewVM RestoreErrorViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<RestoreErrorViewVM>();
+ }
+ }
+
+ public static RestoreCompletedViewVM RestoreCompletedViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<RestoreCompletedViewVM>();
+ }
+ }
+ }
+}
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<BackupErrorNavigationObject>
+ {
+ 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<BackupRestoreModule>(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<BackupRestoreModule>(nameof(BackupCompletedView), false);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "The backup operation failed.");
+
+ await NavigationManager.NavigateWithObject<BackupRestoreModule, BackupErrorView, BackupErrorNavigationObject>(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<StorageModule,
+ Storage.Views.MainView, ExplorerFileItem,
+ Storage.Models.StorageNavigationRequest>(
+ 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<BackupRestoreModule>(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<RestoreResult>
+ {
+ 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<RestoreErrorNavigationObject>
+ {
+ 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<BackupRestoreModule>(nameof(RestoreProgressView), false);
+
+ try
+ {
+ IsFree = false;
+ NavigationManager.IsBackEnabled = false;
+ var result = await BackupManager.Restore(_backupFileLocation, RestoreSettings);
+ await NavigationManager.NavigateWithObject<BackupRestoreModule, RestoreCompletedView, RestoreResult>(result, false);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "The restore operation failed.");
+
+ await NavigationManager.NavigateWithObject<BackupRestoreModule, RestoreErrorView, RestoreErrorNavigationObject>(new RestoreErrorNavigationObject()
+ {
+ Error = ex.FlattenMessage(),
+ }, false);
+
+ NavigationManager.IsBackEnabled = true;
+ }
+ finally
+ {
+ IsFree = true;
+ }
+ }
+
+ private async void BrowseForBackup()
+ {
+ _isBrowsing = true;
+
+ var result = await NavigationManager.
+ NavigateForResult<StorageModule,
+ Storage.Views.MainView, ExplorerFileItem,
+ Storage.Models.StorageNavigationRequest>(
+ 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<bool> 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<BackupRestoreModule>(nameof(BackupView));
+ });
+
+ NavigateToRestoreCommand = new RelayCommand(() =>
+ {
+ NavigationManager.NavigateTo<BackupRestoreModule>(nameof(RestoreView));
+ });
+ }
+
+ public override void OnApplicationStarted()
+ {
+
+ }
+
+ public override void OnNavigatedTo()
+ {
+ base.OnNavigatedTo();
+ NotificationProvider.NotificationsVisible = false;
+ }
+
+ public override Task<bool> 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.BackupCompletedView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BackupCompletedViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BackupCompletedViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoSuccessBrush}">Backup completed</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>The backup operation was completed successfully.</Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+
+ <Grid DockPanel.Dock="Bottom">
+
+ </Grid>
+
+ <Grid>
+
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.BackupErrorView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BackupErrorViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BackupErrorViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoErrorBrush}">Backup failed</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>The backup operation has failed due to the following reason.</Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+
+ <Grid DockPanel.Dock="Bottom">
+
+ </Grid>
+
+ <Grid>
+ <TextBlock Text="{Binding Error}" Margin="0 10 0 0" Height="Auto" TextWrapping="Wrap" Foreground="{StaticResource TangoGrayTextBrush}">
+
+ </TextBlock>
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.BackupProgressView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BackupViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BackupViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}">Backing up your system</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>This process may take several minutes, please wait.</Run>
+ </TextBlock>
+
+
+ </StackPanel>
+ </Grid>
+
+ <Grid>
+ <StackPanel VerticalAlignment="Center">
+ <TextBlock Text="{Binding CurrentBackupProgress.Stage,Converter={StaticResource EnumToDescriptionConverter},FallbackValue='Backing up data'}" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}"></TextBlock>
+ <touch:TouchProgressBar Margin="0 20" Height="10" IsIndeterminate="{Binding CurrentBackupProgress.IsIntermediate}" Maximum="{Binding CurrentBackupProgress.MaxProgress}" Value="{Binding CurrentBackupProgress.Progress,Mode=OneWay}" />
+ </StackPanel>
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.BackupView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BackupViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BackupViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Bottom">
+ <DockPanel>
+ <touch:TouchButton Command="{Binding BackupCommand}" HorizontalAlignment="Right" Height="80" Width="300" CornerRadius="40" Content="START"/>
+ </DockPanel>
+ </Grid>
+ <StackPanel IsEnabled="{Binding IsFree}">
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}">Backup your system</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>Please specify the location and settings of your backup and press 'START'.</Run>
+ </TextBlock>
+
+ <touch:TouchDropShadowBorder Padding="10" Margin="0 50 0 0">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Backup Mode</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0" TextElement.Foreground="{StaticResource TangoDarkForegroundBrush}" TextElement.FontSize="{StaticResource TangoTitleFontSize}">
+ <StackPanel.Resources>
+ <Style TargetType="touch:TouchCheckBox" BasedOn="{StaticResource {x:Type touch:TouchCheckBox}}">
+ <Setter Property="Margin" Value="0 0 0 10"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ </Style>
+
+ <Style x:Key="run" TargetType="Run">
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayTextBrush}"></Setter>
+ <Setter Property="FontSize" Value="{StaticResource TangoDefaultFontSize}"></Setter>
+ </Style>
+ </StackPanel.Resources>
+ <touch:TouchRadioButton IsChecked="{Binding IsBackupJobs,Mode=TwoWay}">
+ <touch:TouchRadioButton.Content>
+ <TextBlock>
+ <Run>Jobs</Run>
+ <Run Style="{StaticResource run}">(create a backup of all your jobs)</Run>
+ </TextBlock>
+ </touch:TouchRadioButton.Content>
+ </touch:TouchRadioButton>
+ <touch:TouchRadioButton IsChecked="{Binding IsBackupFull,Mode=TwoWay}" Margin="0 5 0 0">
+ <touch:TouchRadioButton.Content>
+ <TextBlock>
+ <Run>Full Backup</Run>
+ <Run Style="{StaticResource run}">(backup the entire state of the system)</Run>
+ </TextBlock>
+ </touch:TouchRadioButton.Content>
+ </touch:TouchRadioButton>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <touch:TouchDropShadowBorder Padding="10 10 10 20" Margin="0 10 0 0">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Location</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0">
+
+ <TextBlock>Please select the destination of your backup file</TextBlock>
+ <DockPanel Height="50" Margin="0 20 0 0">
+ <touch:TouchButton Command="{Binding BrowseBackupLocationCommand}" Margin="20 0 0 0" Width="150" DockPanel.Dock="Right" Foreground="{StaticResource TangoDarkForegroundBrush}" BorderBrush="{StaticResource TangoDarkForegroundBrush}" Style="{StaticResource TangoHollowButton}">SELECT</touch:TouchButton>
+ <touch:TouchTextBox Text="{Binding BackupLocation}" IsReadOnly="True" />
+ </DockPanel>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <touch:TouchDropShadowBorder Padding="10" Margin="0 10 0 0">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Name</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0">
+ <TextBlock>Please enter the name of your backup</TextBlock>
+ <touch:TouchTextBox Margin="0 20 0 0" Text="{Binding BackupName}" KeyboardContainer="{Binding RelativeSource={RelativeSource AncestorType=touch:TouchKeyboardContainer}}" />
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+ </StackPanel>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.MainView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
+
+ <touch:TouchKeyboardContainer Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <Grid DockPanel.Dock="Top">
+ <StackPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="0 20 0 0">
+ <Image Source="/Images/backup-restore.png" Stretch="Fill" Width="700" />
+ </StackPanel>
+ </Grid>
+
+ <controls:NavigationControl x:Name="navigationControl" TransitionType="Slide" TransitionDuration="00:00:0.2" KeepElementsAttached="True" Margin="0 20 0 0" SelectedIndex="0">
+
+ <local:WelcomeView/>
+ <local:BackupView/>
+ <local:RestoreView/>
+
+ <local:BackupProgressView/>
+ <local:RestoreProgressView/>
+
+ <local:BackupErrorView/>
+ <local:RestoreErrorView/>
+
+ <local:BackupCompletedView/>
+ <local:RestoreCompletedView/>
+ </controls:NavigationControl>
+ </DockPanel>
+ </touch:TouchKeyboardContainer>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.RestoreCompletedView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RestoreCompletedViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestoreCompletedViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoSuccessBrush}">System restored</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>Your system was successfully restored. The system needs to restart in order apply the changes.</Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+
+ <Grid DockPanel.Dock="Bottom">
+ <touch:TouchButton Command="{Binding RestartCommand}" HorizontalAlignment="Right" Height="80" Width="300" CornerRadius="40" Content="RESTART"/>
+ </Grid>
+
+ <Grid>
+
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.RestoreErrorView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RestoreErrorViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestoreErrorViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoErrorBrush}">Restore failed</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>The restore operation has failed due to the following reason.</Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+
+ <Grid DockPanel.Dock="Bottom">
+
+ </Grid>
+
+ <Grid>
+ <TextBlock Text="{Binding Error}" Margin="0 10 0 0" Height="Auto" TextWrapping="Wrap" Foreground="{StaticResource TangoGrayTextBrush}">
+
+ </TextBlock>
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.RestoreProgressView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RestoreViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestoreViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Top">
+ <StackPanel>
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}">Restoring your system</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>This process may take several minutes, please wait.</Run>
+ </TextBlock>
+
+
+ </StackPanel>
+ </Grid>
+
+ <Grid>
+ <StackPanel VerticalAlignment="Center">
+ <TextBlock Text="{Binding CurrentRestoreProgress.Stage,Converter={StaticResource EnumToDescriptionConverter},FallbackValue='Restoring data'}" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}"></TextBlock>
+ <touch:TouchProgressBar Margin="0 20" Height="10" IsIndeterminate="{Binding CurrentRestoreProgress.IsIntermediate}" Maximum="{Binding CurrentRestoreProgress.MaxProgress}" Value="{Binding CurrentRestoreProgress.Progress,Mode=OneWay}" />
+ </StackPanel>
+ </Grid>
+
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for BackupView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.RestoreView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="700" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RestoreViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestoreViewVM}">
+
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel Margin="30 0 30 30">
+ <Grid DockPanel.Dock="Bottom">
+ <DockPanel>
+ <touch:TouchButton Command="{Binding RestoreCommand}" HorizontalAlignment="Right" Height="80" Width="300" CornerRadius="40" Content="START"/>
+ </DockPanel>
+ </Grid>
+ <StackPanel IsEnabled="{Binding IsFree}">
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}">Restore your system</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>Please specify the location of your backup file and other options. Press 'START' when you are ready.</Run>
+ </TextBlock>
+
+ <touch:TouchDropShadowBorder Padding="10 10 10 20" Margin="0 50 0 0">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Location</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0">
+
+ <TextBlock>Please insert a storage device and select your backup file</TextBlock>
+ <DockPanel Height="50" Margin="0 20 0 0">
+ <touch:TouchButton Command="{Binding BrowseForBackupCommand}" Margin="20 0 0 0" Width="150" DockPanel.Dock="Right" Foreground="{StaticResource TangoDarkForegroundBrush}" BorderBrush="{StaticResource TangoDarkForegroundBrush}" Style="{StaticResource TangoHollowButton}">SELECT</touch:TouchButton>
+ <touch:TouchTextBox Text="{Binding BackupFileName}" IsReadOnly="True" />
+ </DockPanel>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <touch:TouchDropShadowBorder Padding="10 10 10 0" Margin="0 10 0 0" Visibility="{Binding BackupFile,Converter={StaticResource IsNullToVisibilityConverter}}">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Information</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0">
+
+ <StackPanel>
+ <controls:TableGrid RowHeight="20">
+ <TextBlock Text="Name:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.Name}"></TextBlock>
+
+ <TextBlock Text="Date:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.Date}"></TextBlock>
+
+ <TextBlock Text="Size:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupSize,Converter={StaticResource ByteArrayToFileSizeConverter}}"></TextBlock>
+
+ <TextBlock Text="Mode:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.Settings.Mode}"></TextBlock>
+ </controls:TableGrid>
+ </StackPanel>
+
+ <StackPanel Margin="0 -20 0 0">
+ <StackPanel.Style>
+ <Style TargetType="StackPanel">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding BackupFile.Settings.Mode}" Value="Jobs">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </StackPanel.Style>
+ <controls:TableGrid RowHeight="20">
+ <TextBlock Text="Jobs:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.JobFiles.Count}"></TextBlock>
+ </controls:TableGrid>
+ </StackPanel>
+
+ <StackPanel>
+ <StackPanel.Style>
+ <Style TargetType="StackPanel">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding BackupFile.Settings.Mode}" Value="Full">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </StackPanel.Style>
+ <controls:TableGrid RowHeight="20">
+ <TextBlock Text="Application Version:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.ApplicationVersion}"></TextBlock>
+
+ <TextBlock Text="Firmware Version:"></TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding BackupFile.FirmwareVersion}"></TextBlock>
+ </controls:TableGrid>
+ </StackPanel>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <touch:TouchDropShadowBorder Padding="10" Margin="0 10 0 0">
+ <touch:TouchDropShadowBorder.Style>
+ <Style TargetType="touch:TouchDropShadowBorder">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding BackupFile.Settings.Mode}" Value="Jobs">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchDropShadowBorder.Style>
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoPrimaryAccentBrush}">Options</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 20 0 0" TextElement.Foreground="{StaticResource TangoDarkForegroundBrush}" TextElement.FontSize="{StaticResource TangoTitleFontSize}">
+ <StackPanel.Resources>
+ <Style TargetType="touch:TouchCheckBox" BasedOn="{StaticResource {x:Type touch:TouchCheckBox}}">
+ <Setter Property="Margin" Value="0 0 0 10"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ </Style>
+
+ <Style x:Key="run" TargetType="Run">
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayTextBrush}"></Setter>
+ <Setter Property="FontSize" Value="{StaticResource TangoDefaultFontSize}"></Setter>
+ </Style>
+ </StackPanel.Resources>
+ <touch:TouchCheckBox IsChecked="{Binding RestoreSettings.OverwriteExistingJobs,Mode=TwoWay}">
+ <touch:TouchCheckBox.Content>
+ <TextBlock>
+ <Run>Overwrite existing jobs</Run>
+ <Run Style="{StaticResource run}">(existing jobs will change if there are conflicts)</Run>
+ </TextBlock>
+ </touch:TouchCheckBox.Content>
+ </touch:TouchCheckBox>
+ <touch:TouchCheckBox IsChecked="{Binding RestoreSettings.AllowDeleteJobs,Converter={StaticResource BooleanInverseConverter},Mode=TwoWay}">
+ <touch:TouchCheckBox.Content>
+ <TextBlock>
+ <Run>Do not remove existing jobs</Run>
+ <Run Style="{StaticResource run}">(existing jobs will not be deleted)</Run>
+ </TextBlock>
+ </touch:TouchCheckBox.Content>
+ </touch:TouchCheckBox>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+ </StackPanel>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for RestoreView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.BackupRestore.Views.WelcomeView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.BackupRestore.ViewModels"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:global="clr-namespace:Tango.PPC.BackupRestore"
+ xmlns:local="clr-namespace:Tango.PPC.BackupRestore.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:WelcomeViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.WelcomeViewVM}">
+
+ <UserControl.Resources>
+ <Style TargetType="touch:TouchButton" x:Key="ButtonMenu">
+ <Setter Property="Padding" Value="10"></Setter>
+ <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
+ <Setter Property="Height" Value="140"></Setter>
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="1"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="EnableDropShadow" Value="False"></Setter>
+ <Setter Property="CornerRadius" Value="5"></Setter>
+ <Setter Property="Margin" Value="0 0 0 20"></Setter>
+ <Setter Property="RippleBrush" Value="#4BB8B8B8"></Setter>
+ </Style>
+ </UserControl.Resources>
+
+ <Grid controls:NavigationControl.NavigationName="MainView">
+ <StackPanel HorizontalAlignment="Left" Margin="50 20 50 0">
+ <TextBlock TextWrapping="Wrap" FontSize="{StaticResource TangoDefaultFontSize}">
+ <Run FontSize="{StaticResource TangoTitleFontSize}">Welcome to the backup/restore wizard</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>This wizard allows you to create a complete backup of your current machine state including software, firmware, data and user settings.</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <LineBreak/>
+ <Run>For creating a complete backup of your system please press 'Backup'.</Run>
+ <LineBreak/>
+ <Run>In case you want to restore your system to a previous state, please press 'Restore'.</Run>
+ </TextBlock>
+ </StackPanel>
+
+ <StackPanel VerticalAlignment="Center" Margin="50 150 50 0">
+ <touch:TouchButton Style="{StaticResource ButtonMenu}" Command="{Binding NavigateToBackupCommand}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/backup-big.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Backup</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" Width="470" TextWrapping="Wrap">
+ Create a complete backup of your system state and save it to a storage device.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Style="{StaticResource ButtonMenu}" Command="{Binding NavigateToRestoreCommand}" CommandParameter="RestoreView">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/restore.png" Width="80" Height="65" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Restore</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Restore your system from a previously saved backup file.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for WelcomeView.xaml
+ /// </summary>
+ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <configSections>
+ <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
+ </configSections>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+ <entityFramework>
+ <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
+ <providers>
+ <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
+ </providers>
+ </entityFramework>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="EntityFramework" version="6.0.0" targetFramework="net46" />
+ <package id="Expression.Blend.Sdk" version="1.0.2" targetFramework="net46" />
+ <package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net46" />
+ <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" />
+</packages> \ 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 @@
+<Application x:Class="Tango.PPC.Browser.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Resources/Merged.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+ </Application.Resources>
+</Application> \ 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
+{
+ /// <summary>
+ /// Represents a PPC <see cref="BrowserModule"/>.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
+ [PPCModule(10)]
+ public class BrowserModule : PPCModuleBase
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BrowserModule"/> class.
+ /// </summary>
+ public BrowserModule()
+ {
+ IsVisibleInMenu = false;
+ }
+
+ /// <summary>
+ /// Gets the module name.
+ /// </summary>
+ public override string Name
+ {
+ get
+ {
+ return "Browser";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module description.
+ /// </summary>
+ public override string Description
+ {
+ get
+ {
+ return "Browser module";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module cover image.
+ /// </summary>
+ public override BitmapSource Image
+ {
+ get
+ {
+ return ResourceHelper.GetImageFromResources("Images/browser.png");
+ }
+ }
+
+ /// <summary>
+ /// Gets the module entry point view type.
+ /// </summary>
+ public override Type MainViewType
+ {
+ get
+ {
+ return IsCefAvailable() ? typeof(BrowserView) : typeof(ErrorView);
+ }
+ }
+
+ /// <summary>
+ /// Gets the permission required to see and load this module.
+ /// </summary>
+ public override Permissions Permission
+ {
+ get
+ {
+ return Permissions.RunPPC;
+ }
+ }
+
+ private bool IsCefAvailable()
+ {
+ return File.Exists(Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "x86", "CefSharp.Core.dll"));
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/CefSharpOutput.zip
Binary files 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<String> _scripts = new List<string>();
+
+ 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<BoundObjectAttribute>() != null))
+ {
+ var att = type.GetCustomAttribute<BoundObjectAttribute>();
+
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Browser/Images/browser.png
Binary files 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.PPC.Browser.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // 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() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [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;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+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 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ 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<String> 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.props" Condition="Exists('..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.props')" />
+ <Import Project="..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.props" Condition="Exists('..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.props')" />
+ <Import Project="..\..\..\packages\cef.redist.x86.75.1.14\build\cef.redist.x86.props" Condition="Exists('..\..\..\packages\cef.redist.x86.75.1.14\build\cef.redist.x86.props')" />
+ <Import Project="..\..\..\packages\cef.redist.x64.75.1.14\build\cef.redist.x64.props" Condition="Exists('..\..\..\packages\cef.redist.x64.75.1.14\build\cef.redist.x64.props')" />
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <CefSharpAnyCpuSupport>true</CefSharpAnyCpuSupport>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{F02EAA84-AD59-465B-99A2-4422C13BFB72}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.PPC.Browser</RootNamespace>
+ <AssemblyName>Tango.PPC.Browser</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <TargetFrameworkProfile />
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ </Reference>
+ <Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\BrowserView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\ErrorView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Attributes\BoundObjectAttribute.cs" />
+ <Compile Include="BoundsObjects\KeyboardHandler.cs" />
+ <Compile Include="BrowserModule.cs" />
+ <Compile Include="Helpers\BoundObjectsHelper.cs" />
+ <Compile Include="Navigation\BrowserNavigationRequest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="RequestHandlers\ChromiumRequestHandler.cs" />
+ <Compile Include="ViewContracts\IBrowserView.cs" />
+ <Compile Include="ViewModelLocator.cs" />
+ <Compile Include="ViewModels\BrowserViewVM.cs" />
+ <Compile Include="Views\BrowserView.xaml.cs">
+ <DependentUpon>BrowserView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\ErrorView.xaml.cs">
+ <DependentUpon>ErrorView.xaml</DependentUpon>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.config" />
+ <None Include="CefSharpOutput.zip" />
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.DragAndDrop\Tango.DragAndDrop.csproj">
+ <Project>{b112d89a-a106-41ae-a0c1-4abc84c477f5}</Project>
+ <Name>Tango.DragAndDrop</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Settings\Tango.Settings.csproj">
+ <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project>
+ <Name>Tango.Settings</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Touch\Tango.Touch.csproj">
+ <Project>{fd86424c-6e84-491b-8df9-3d0f5c236a2a}</Project>
+ <Name>Tango.Touch</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\browser.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Scripts\keyboard.js" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
+ </VisualStudio>
+ </ProjectExtensions>
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>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}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\..\..\packages\cef.redist.x64.75.1.14\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\cef.redist.x64.75.1.14\build\cef.redist.x64.props'))" />
+ <Error Condition="!Exists('..\..\..\packages\cef.redist.x86.75.1.14\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\cef.redist.x86.75.1.14\build\cef.redist.x86.props'))" />
+ <Error Condition="!Exists('..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.props'))" />
+ <Error Condition="!Exists('..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.targets'))" />
+ <Error Condition="!Exists('..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.props'))" />
+ <Error Condition="!Exists('..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.targets'))" />
+ </Target>
+ <Import Project="..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.targets" Condition="Exists('..\..\..\packages\CefSharp.Common.75.1.143\build\CefSharp.Common.targets')" />
+ <Import Project="..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.targets" Condition="Exists('..\..\..\packages\CefSharp.Wpf.75.1.143\build\CefSharp.Wpf.targets')" />
+</Project> \ 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<String> 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
+ {
+ /// <summary>
+ /// Initializes a new instance of the ViewModelLocator class.
+ /// </summary>
+ static ViewModelLocator()
+ {
+ TangoIOC.Default.Register<BrowserViewVM>();
+ }
+
+ /// <summary>
+ /// Gets the main view VM.
+ /// </summary>
+ public static BrowserViewVM BrowserViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<BrowserViewVM>();
+ }
+ }
+ }
+}
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
+{
+ /// <summary>
+ /// Represents the main view VM and entry point for <see cref="Synchronization.MyModule"/>.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.PPCViewModel" />
+ public class BrowserViewVM : PPCViewModel<IBrowserView>, INavigationObjectReceiver<BrowserNavigationRequest>
+ {
+ 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<bool> OnNavigateBackRequest()
+ {
+ if (View != null && View.CanGoBack())
+ {
+ View.GoBack();
+ return Task.FromResult(false);
+ }
+ else
+ {
+ return Task.FromResult(true);
+ }
+ }
+
+ /// <summary>
+ /// Called when the application has been started
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Browser.Views.BrowserView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.Browser.ViewModels"
+ xmlns:wpf="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
+ xmlns:experimental="clr-namespace:CefSharp.Wpf.Experimental;assembly=CefSharp.Wpf"
+ xmlns:global="clr-namespace:Tango.PPC.Browser"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:keyboard="clr-namespace:Tango.Touch.Keyboard;assembly=Tango.Touch"
+ xmlns:local="clr-namespace:Tango.PPC.Browser.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BrowserViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BrowserViewVM}" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <Grid>
+ <DockPanel>
+ <Border DockPanel.Dock="Top" Padding="10" BorderBrush="{StaticResource TangoGrayBrush}" BorderThickness="0 0 0 1" Visibility="{Binding DisplayAddressBar,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <DockPanel>
+ <touch:TouchButton x:Name="btnGo" Command="{Binding GoCommand}" DockPanel.Dock="Right" Padding="10" Width="150" CornerRadius="20" Margin="20 0 0 0">
+ <touch:TouchIcon Icon="ArrowRightBold" Height="20" />
+ </touch:TouchButton>
+ <Grid>
+ <Border Background="{StaticResource TangoMidBackgroundBrush}" Padding="2" BorderBrush="{StaticResource TangoLightBorderBrush}" BorderThickness="1" CornerRadius="20">
+ <TextBox x:Name="txtAddress" PreviewMouseDoubleClick="TxtAddress_PreviewMouseDoubleClick" GotFocus="TxtAddress_GotFocus" PreviewMouseUp="TxtAddress_MouseUp" LostFocus="TxtAddress_LostFocus" KeyDown="TxtAddress_KeyDown" VerticalContentAlignment="Center" Text="{Binding Address,UpdateSourceTrigger=PropertyChanged}" BorderThickness="0" FontSize="{StaticResource TangoDefaultFontSize}" Padding="5" Background="Transparent"></TextBox>
+ </Border>
+ <Border CornerRadius="20" IsHitTestVisible="False" Visibility="{Binding ElementName=Browser,Path=IsLoading,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <Border.Background>
+ <LinearGradientBrush>
+ <GradientStop Offset="0" Color="Transparent" />
+ <GradientStop Offset="0.5" Color="#7612D433" />
+ <GradientStop Offset="1" Color="Transparent" />
+ </LinearGradientBrush>
+ </Border.Background>
+ <Border.Style>
+ <Style TargetType="Border">
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=Browser,Path=IsLoading}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard Name="loadingStory">
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="Background.GradientStops[1].Offset" From="0" To="1" AutoReverse="True" RepeatBehavior="Forever" />
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <RemoveStoryboard BeginStoryboardName="loadingStory" />
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+ </Border>
+ </Grid>
+ </DockPanel>
+ </Border>
+
+ <Grid>
+ <experimental:ChromiumWebBrowserWithTouchSupport x:Name="Browser" />
+ <Grid Background="White" IsHitTestVisible="False" Visibility="Hidden" x:Name="gridError">
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <touch:TouchIcon Icon="Alert" Foreground="{StaticResource TangoGrayTextBrush}" Width="100" Height="100" />
+ <TextBlock HorizontalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" FontSize="40" Margin="0 20 0 0">Page Not Found</TextBlock>
+ <TextBlock Margin="0 10 0 0" Foreground="{StaticResource TangoGrayTextBrush}" HorizontalAlignment="Center" Width="600" TextAlignment="Center" TextWrapping="Wrap">
+ <Run>The page at '</Run><Run Text="{Binding ElementName=txtAddress,Path=Text,Mode=OneWay}"></Run><Run>'</Run>
+ <Run>could not be reached.</Run>
+ <LineBreak/>
+ <Run>Please check your internet connection.</Run>
+ <LineBreak/>
+ <LineBreak/>
+ <Run x:Name="runError" Text="Unspecified"></Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+ </Grid>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ public partial class BrowserView : UserControl, IBrowserView
+ {
+ public event EventHandler<string> 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<IBrowserView>(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 @@
+<UserControl x:Class="Tango.PPC.Browser.Views.ErrorView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:vm="clr-namespace:Tango.PPC.Browser.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.Browser"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:local="clr-namespace:Tango.PPC.Browser.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:BrowserViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.BrowserViewVM}" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <Grid>
+ <Grid Background="White" IsHitTestVisible="False">
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <touch:TouchIcon Icon="Alert" Foreground="{StaticResource TangoGrayTextBrush}" Width="100" Height="100" />
+ <TextBlock HorizontalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" FontSize="40" Margin="0 20 0 0">Browser Not Loaded</TextBlock>
+ <TextBlock Margin="0 10 0 0" Foreground="{StaticResource TangoGrayTextBrush}" HorizontalAlignment="Center" Width="600" TextAlignment="Center" TextWrapping="Wrap">
+ The browser module was not loaded properly or has caused some error.
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for ErrorView.xaml
+ /// </summary>
+ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <configSections>
+ <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </configSections>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <!--Required for cefCharp-->
+ <probing privatePath="x86"/>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+ <entityFramework>
+ <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
+ <providers>
+ <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+ </providers>
+ </entityFramework>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+ </startup>
+</configuration>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="cef.redist.x64" version="75.1.14" targetFramework="net461" />
+ <package id="cef.redist.x86" version="75.1.14" targetFramework="net461" />
+ <package id="CefSharp.Common" version="75.1.143" targetFramework="net461" />
+ <package id="CefSharp.Wpf" version="75.1.143" targetFramework="net461" />
+ <package id="EntityFramework" version="6.0.0" targetFramework="net46" />
+ <package id="Expression.Blend.Sdk" version="1.0.2" targetFramework="net46" />
+ <package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net46" />
+ <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" />
+</packages> \ 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 <see cref="BugReportingModule"/>.
/// </summary>
/// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
- [PPCModule(5)]
+ [PPCModule(6)]
public class BugReportingModule : PPCModuleBase
{
/// <summary>
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<PPCSettings>().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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{8146FA0A-0725-4A1A-82E6-696C58F33A2B}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.PPC.BugReporting</RootNamespace>
+ <AssemblyName>Tango.PPC.BugReporting</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="BugReportingModule.cs" />
+ <Compile Include="BugReportingSettings.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="TFS\SystemInformationModel.cs" />
+ <Compile Include="TFS\TeamFoundationServicePPCClient.cs" />
+ <Compile Include="ViewModelLocator.cs" />
+ <Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="Views\MainView.xaml.cs">
+ <DependentUpon>MainView.xaml</DependentUpon>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <EmbeddedResource Include="TFS\SystemInformationTemplate.cshtml" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.CodeGeneration\Tango.CodeGeneration.csproj">
+ <Project>{caedae94-11ed-473c-888a-268a6d38cd20}</Project>
+ <Name>Tango.CodeGeneration</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.DragAndDrop\Tango.DragAndDrop.csproj">
+ <Project>{b112d89a-a106-41ae-a0c1-4abc84c477f5}</Project>
+ <Name>Tango.DragAndDrop</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj">
+ <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
+ <Name>Tango.Integration</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Settings\Tango.Settings.csproj">
+ <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project>
+ <Name>Tango.Settings</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.TFS\Tango.TFS.csproj">
+ <Project>{998f8471-dc1b-41b6-9d96-354e1b4e7a32}</Project>
+ <Name>Tango.TFS</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Touch\Tango.Touch.csproj">
+ <Project>{fd86424c-6e84-491b-8df9-3d0f5c236a2a}</Project>
+ <Name>Tango.Touch</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Web\Tango.Web.csproj">
+ <Project>{5001990f-977b-48ff-b217-0236a5022ad8}</Project>
+ <Name>Tango.Web</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ </VisualStudio>
+ </ProjectExtensions>
+ <ItemGroup>
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Microsoft.CSharp.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationCore.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationFramework.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.ComponentModel.DataAnnotations.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Core.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.DataSetExtensions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Net.Http.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xaml.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.Linq.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.BL.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.CodeGeneration.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Core.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.DragAndDrop.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Integration.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Logging.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.PMR.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\PPC\Debug\Tango.PPC.Common.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Settings.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.SharedUI.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.TFS.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Touch.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Transport.dll" />
+ <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Web.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\WindowsBase.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.Concurrent.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.Annotations.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.EventBasedAsync.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Contracts.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Debug.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tools.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tracing.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Dynamic.Runtime.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Globalization.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.IO.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Expressions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Parallel.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Queryable.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.NetworkInformation.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Primitives.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Requests.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.WebHeaderCollection.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ObjectModel.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.ILGeneration.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.Lightweight.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Extensions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Primitives.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Resources.ResourceManager.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Extensions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Handles.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.WindowsRuntime.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Numerics.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Json.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Primitives.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Xml.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Security.Principal.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Duplex.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Http.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.NetTcp.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Primitives.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Security.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.Extensions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.RegularExpressions.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.Parallel.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Timer.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.ReaderWriter.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XDocument.dll" />
+ <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XmlSerializer.dll" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\PPC\Modules\Tango.PPC.BugReporting\obj\Debug\App.g.cs" />
+ <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\PPC\Modules\Tango.PPC.BugReporting\obj\Debug\Views\MainView.g.cs" />
+ </ItemGroup>
+</Project> \ 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
/// </summary>
static ViewModelLocator()
{
- TangoIOC.Default.Register<TeamFoundationServicePPCClient>(new TeamFoundationServicePPCClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa"));
+ TangoIOC.Default.Register<TeamFoundationServicePPCClient>(new TeamFoundationServicePPCClient("https://twinetfs.visualstudio.com", String.Empty, "pyulwgs7m3v7pizz3oxusypdkdfw43txggo5mjwu2ouyv2qwprhq"));
TangoIOC.Default.Register<MainViewVM>();
}
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 @@
+<UserControl x:Class="Tango.PPC.Events.EventsViews.ThreadBreakView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL"
+ xmlns:local="clr-namespace:Tango.PPC.Events.EventsViews"
+ mc:Ignorable="d"
+ d:DesignHeight="220" d:DesignWidth="750" d:DataContext="{d:DesignInstance Type=entities:MachinesEvent, IsDesignTimeCreatable=False}">
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <Image Stretch="None" Margin="20" DockPanel.Dock="Right" Source="../Images/machine_small.png" RenderOptions.BitmapScalingMode="Fant" />
+ <DockPanel Margin="35 20 20 20">
+ <TextBlock FontSize="{StaticResource TangoTitleFontSize}" FontWeight="SemiBold" DockPanel.Dock="Top" Text="{Binding EventType.Title,FallbackValue='Unknown Event'}"></TextBlock>
+
+ <StackPanel Margin="0 30 0 0">
+ <TextBlock TextWrapping="Wrap" FontWeight="SemiBold" Text="{Binding EventType.Description,FallbackValue='No Description'}"></TextBlock>
+ <Rectangle Margin="0 5 0 10" StrokeThickness="2" Stroke="{StaticResource TangoDividerBrush}" />
+
+ <touch:TouchButton x:Name="btnLoadThreadBreakWizard" Margin="0 10 0 0" Height="55" Style="{StaticResource TangoHollowButton}" Width="280" HorizontalAlignment="Left">LOAD THREAD BREAK WIZARD</touch:TouchButton>
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for ThreadBreakView.xaml
+ /// </summary>
+ 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<IThreadLoadingService>();
+
+ 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 @@
<Setter Property="Height" Value="68"></Setter>
<Setter Property="Margin" Value="5 0 5 5"></Setter>
<Setter Property="CornerRadius" Value="5"></Setter>
- <Setter Property="Effect">
+ <!--<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="5" ShadowDepth="1" Color="Silver" />
</Setter.Value>
- </Setter>
+ </Setter>-->
</Style>
<Style TargetType="{x:Type touch:LightTouchDataGridRow}">
diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Tango.PPC.Events.csproj b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Tango.PPC.Events.csproj
index e2133e585..e8d4683ee 100644
--- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Tango.PPC.Events.csproj
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Tango.PPC.Events.csproj
@@ -76,6 +76,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="EventsViews\ThreadBreakView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Resources\Styles.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -98,6 +102,9 @@
<Compile Include="EventsViews\JobEventView.xaml.cs">
<DependentUpon>JobEventView.xaml</DependentUpon>
</Compile>
+ <Compile Include="EventsViews\ThreadBreakView.xaml.cs">
+ <DependentUpon>ThreadBreakView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
@@ -180,7 +187,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
</VisualStudio>
</ProjectExtensions>
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/ViewModels/MainViewVM.cs b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/ViewModels/MainViewVM.cs
index d2a730cd7..a6e6b7a4e 100644
--- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/ViewModels/MainViewVM.cs
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/ViewModels/MainViewVM.cs
@@ -127,15 +127,31 @@ namespace Tango.PPC.Events.ViewModels
{
if (ev.NotificationTime != EventTypeNotificationTimes.None)
{
- CurrentEvents.Insert(0, ev);
+ if (!ev.EventType.Persistent)
+ {
+ CurrentEvents.Insert(0, ev);
+ }
+ else
+ {
+ HistoryEvents.Insert(0, ev);
+ }
var notificationItem = new MessageNotificationItem();
- notificationItem.CanClose = false;
+ notificationItem.CanClose = ev.EventType.Persistent;
notificationItem.Message = ev.EventType.Title;
notificationItem.ExpandedMessage = ev.EventType.Description;
notificationItem.Pressed += async (_, __) =>
{
- SelectedEventsSource = EventsSource.CURRENT;
+ if (!ev.EventType.Persistent)
+ {
+ SelectedEventsSource = EventsSource.CURRENT;
+ }
+ else
+ {
+ SelectedEventsSource = EventsSource.HISTORY;
+ notificationItem.Dispose();
+ }
+
SelectedEvent = ev;
await NavigationManager.NavigateTo<EventsModule>();
};
@@ -144,15 +160,23 @@ namespace Tango.PPC.Events.ViewModels
{
case EventTypeCategories.Info:
notificationItem.MessageType = MessageNotificationItem.MessageNotificationItemTypes.Info;
+ notificationItem.Priority = NotificationItem.NotificationPriority.Normal;
break;
case EventTypeCategories.Warning:
notificationItem.MessageType = MessageNotificationItem.MessageNotificationItemTypes.Warning;
+ notificationItem.Priority = NotificationItem.NotificationPriority.High;
break;
case EventTypeCategories.Error:
notificationItem.MessageType = MessageNotificationItem.MessageNotificationItemTypes.Error;
+ notificationItem.Priority = NotificationItem.NotificationPriority.VeryHigh;
break;
case EventTypeCategories.Critical:
notificationItem.MessageType = MessageNotificationItem.MessageNotificationItemTypes.Critical;
+ notificationItem.Priority = NotificationItem.NotificationPriority.Critical;
+ break;
+ case EventTypeCategories.Success:
+ notificationItem.MessageType = MessageNotificationItem.MessageNotificationItemTypes.Success;
+ notificationItem.Priority = NotificationItem.NotificationPriority.VeryHigh;
break;
}
@@ -171,7 +195,7 @@ namespace Tango.PPC.Events.ViewModels
{
InvokeUI(() =>
{
- if (ev.NotificationTime != EventTypeNotificationTimes.None)
+ if (ev.NotificationTime != EventTypeNotificationTimes.None && !ev.EventType.Persistent)
{
CurrentEvents.Remove(ev);
HistoryEvents.Insert(0, ev);
diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Views/MainView.xaml
index af42a5576..f0ae4b128 100644
--- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Views/MainView.xaml
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Events/Views/MainView.xaml
@@ -143,8 +143,8 @@
<touch:TouchIcon Width="32" Height="32" IsHitTestVisible="False">
<touch:TouchIcon.Style>
<Style TargetType="touch:TouchIcon">
- <Setter Property="Icon" Value="CheckCircleOutline"/>
- <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"/>
+ <Setter Property="Icon" Value="Information"/>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Category,Mode=OneWay}" Value="Warning">
<Setter Property="Icon" Value="AlertCircleOutline"/>
@@ -158,6 +158,10 @@
<Setter Property="Icon" Value="Alert"/>
<Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"/>
</DataTrigger>
+ <DataTrigger Binding="{Binding Category,Mode=OneWay}" Value="Success">
+ <Setter Property="Icon" Value="CheckCircleOutline"/>
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"/>
+ </DataTrigger>
</Style.Triggers>
</Style>
</touch:TouchIcon.Style>
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}">
<Grid>
<touch:TouchButton Style="{StaticResource TangoFlatButton}" Command="{Binding PressedCommand}" Padding="0">
<StackPanel VerticalAlignment="Center">
- <TextBlock Text="{Binding MachineProvider.MachineOperator.RunningJob.Name,FallbackValue='Job Name'}" FontSize="{StaticResource TangoTitleFontSize}"></TextBlock>
+ <TextBlock Text="{Binding MachineProvider.MachineOperator.RunningJob.Name,FallbackValue='Job Name'}" FontSize="{StaticResource TangoTitleFontSize}" TextTrimming="CharacterEllipsis"></TextBlock>
<ProgressBar Maximum="{Binding MachineProvider.MachineOperator.RunningJobStatus.TotalProgressMinusSettingUp}" Value="{Binding MachineProvider.MachineOperator.RunningJobStatus.ProgressMinusSettingUp}" Margin="0 10 0 5" Background="{StaticResource TangoGrayBrush}" Height="5" Foreground="{StaticResource TangoPrimaryAccentBrush}" BorderThickness="0" />
<DockPanel LastChildFill="False">
<TextBlock DockPanel.Dock="Left">
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<ScrollViewer>();
+ _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<Tuple<String, String>> 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<string, string>(x.Name, x.GetValue(value).ToString()));
+ }
+ else
+ {
+ return null;
+ }
+ }
+ #endregion render
+
+ #region drawing
+ protected void DrawNameValueText(DrawingContext drawingContext, Tuple<string, string> 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 @@
</RectangleGeometry.Rect>
</RectangleGeometry>
</Border.Clip>
+ <Border.Background>
+ <ImageBrush ImageSource="../Images/JobView/transparent_small.jpg" Stretch="None" TileMode="Tile" AlignmentX="Left" ViewportUnits="Absolute" Viewport="0,0,94,30" />
+ </Border.Background>
<Grid>
<ItemsControl ClipToBounds="False" ItemsSource="{Binding EffectiveSegments,IsAsync=True}">
<ItemsControl.ItemsPanel>
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 @@
</ItemsControl>
<Border Grid.Row="1" x:Name="brush_border" ClipToBounds="False" CornerRadius="10" Margin="0 5 0 0">
+ <Border.Background>
+ <ImageBrush ImageSource="../Images/JobView/transparent_small.jpg" Stretch="None" TileMode="Tile" AlignmentX="Left" ViewportUnits="Absolute" Viewport="0,0,94,30" />
+ </Border.Background>
<Border.Clip>
<RectangleGeometry RadiusX="10" RadiusY="10">
<RectangleGeometry.Rect>
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 @@
</Grid.RowDefinitions>
<Grid>
- <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoMessageBoxTitleFontSize}" Foreground="{StaticResource TangoErrorBrush}">Color is out of range</TextBlock>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoMessageBoxTitleFontSize}">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Color is out of range"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsOutOfGamut}" Value="False">
+ <Setter Property="Text" Value="Closest Alternatives"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="Margin" Value="20 0 0 0"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
<touch:TouchIconButton Command="{Binding CloseCommand}" HorizontalAlignment="Right" Icon="Close" CornerRadius="50" RippleBrush="{StaticResource TangoRippleDarkBrush}" Foreground="{StaticResource TangoDarkForegroundBrush}" Padding="22" />
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Center">
- <Image Source="../Images/JobView/error.png" Stretch="None" />
+ <Image Source="../Images/JobView/error.png" Stretch="None" Visibility="{Binding IsOutOfGamut,Converter={StaticResource BooleanToVisibilityConverter}}" />
<Ellipse Width="60" Height="60" Margin="20 0 0 0" Fill="{Binding InvalidBrushStop.Brush}" />
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Margin="20 0 0 0">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding InvalidBrushStop.BrushColorSpace}" Value="RGB">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
<Run Text="{Binding InvalidBrushStop.Red}"></Run><Run>,</Run>
<Run Text="{Binding InvalidBrushStop.Green}"></Run><Run>,</Run>
<Run Text="{Binding InvalidBrushStop.Blue}"></Run>
</TextBlock>
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Margin="20 0 0 0">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding InvalidBrushStop.BrushColorSpace}" Value="LAB">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ <Run Text="{Binding InvalidBrushStop.L,StringFormat=0.00}"></Run><Run>,</Run>
+ <Run Text="{Binding InvalidBrushStop.A,StringFormat=0.00}"></Run><Run>,</Run>
+ <Run Text="{Binding InvalidBrushStop.B,StringFormat=0.00}"></Run>
+ </TextBlock>
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Margin="20 0 0 0" Text="{Binding InvalidBrushStop.LiquidVolumesOrderedPigmentedString,Mode=OneWay}">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding InvalidBrushStop.BrushColorSpace}" Value="Volume">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
</StackPanel>
<DockPanel Grid.Row="2" Margin="0 0 0 0">
- <TextBlock DockPanel.Dock="Top" Margin="40 0 0 0">Please select the best alternative</TextBlock>
+ <TextBlock DockPanel.Dock="Top" Margin="40 0 0 0">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Please select the best alternative"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsOutOfGamut}" Value="False">
+ <Setter Property="Text" Value="Please select an alternative"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
<hive:HexList Width="330" Height="460" Margin="0 20 0 0" RowCount="6" ColumnCount="5" ItemsSource="{Binding Suggestions}" SelectedItem="{Binding SelectedSuggestion,Mode=TwoWay}">
<hive:HexList.ItemContainerStyle>
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
/// <seealso cref="Tango.PPC.Jobs.Dialogs.BasicColorCorrectionViewVM" />
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 @@
</StackPanel>
<DockPanel Grid.Row="2" Margin="0 0 0 0">
- <TextBlock DockPanel.Dock="Top" Margin="40 0 0 0">Please select an alternative</TextBlock>
+ <TextBlock DockPanel.Dock="Top" Margin="40 0 0 0">Please use the closest alternative</TextBlock>
<touch:TouchListBox SelectionMode="Single" Style="{StaticResource TangoNoRippleListBox}" ItemsSource="{Binding Suggestions}" SelectedItem="{Binding SelectedSuggestion,Mode=TwoWay}" Margin="0 20 0 0">
<touch:TouchListBox.ItemContainerStyle>
@@ -81,7 +81,7 @@
</Setter>
<Setter Property="Effect">
<Setter.Value>
- <DropShadowEffect Color="{StaticResource TangoDarkForegroundColor}" ShadowDepth="0" BlurRadius="10" Opacity="0" />
+ <DropShadowEffect Color="{StaticResource TangoGrayColor}" ShadowDepth="0" BlurRadius="10" Opacity="0" />
</Setter.Value>
</Setter>
<Style.Triggers>
@@ -147,7 +147,10 @@
<DockPanel Grid.Row="3" Margin="40 10 20 0" LastChildFill="False">
<touch:TouchButton Command="{Binding MoreOptionsCommand}" VerticalAlignment="Top" Style="{StaticResource TangoLinkButton}" DockPanel.Dock="Left" Foreground="{StaticResource TangoPrimaryAccentBrush}">
- More Options
+ <StackPanel Orientation="Horizontal">
+ <Image Source="../Images/color-picker.png" Stretch="None" VerticalAlignment="Center" />
+ <TextBlock Margin="5 0 0 0" VerticalAlignment="Center">More Options</TextBlock>
+ </StackPanel>
</touch:TouchButton>
<touch:TouchButton Command="{Binding OKCommand}" CornerRadius="25" Style="{StaticResource TangoHollowButton}" DockPanel.Dock="Right" Width="170" Height="50" VerticalAlignment="Bottom">
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 @@
<DataTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<Image Stretch="Fill" Width="32" Height="32" RenderOptions.BitmapScalingMode="Fant" Source="../Images/NewJob/twine.png"></Image>
- <TextBlock HorizontalAlignment="Center" Margin="0 10 0 0" Text="{Binding Name}"></TextBlock>
+ <TextBlock HorizontalAlignment="Center" Margin="0 10 0 0" TextAlignment="Center" Text="{Binding Name}" TextWrapping="Wrap" TextTrimming="CharacterEllipsis"></TextBlock>
</StackPanel>
</DataTemplate>
</touch:TouchStaticListBox.ItemTemplate>
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 @@
<TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoHeaderFontSize}">IMPORT JOB</TextBlock>
<TextBlock Margin="20 10" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">A job file has been selected from the storage device. press 'IMPORT' to add the job to your job list.</TextBlock>
- <touch:TouchCheckBox IsChecked="{Binding ImportAndEdit}" Margin="40 50 0 0">Edit this job after import</touch:TouchCheckBox>
+ <touch:TouchCheckBox IsChecked="{Binding ImportAndEdit}" Margin="40 50 0 0" Visibility="Collapsed">Edit this job after import</touch:TouchCheckBox>
</StackPanel>
</DockPanel>
</Grid>
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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/JobView/transparent_small.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/color-picker.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Jobs/Images/sync_job.png
Binary files 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
+{
+ /// <summary>
+ /// Represents a simple text message notification item which can be inserted into the application notifications panel.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.Notifications.NotificationItem" />
+ public class NewSynchronizardJobsNotificationItem : NotificationItem
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UpdateAvailableNotificationItem"/> class.
+ /// </summary>
+ public NewSynchronizardJobsNotificationItem()
+ {
+ CanClose = true;
+ }
+
+ /// <summary>
+ /// Gets or sets the view type.
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Jobs.NotificationItems.NewSynchronizardJobsNotificationItemView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Jobs.NotificationItems"
+ xmlns:common="clr-namespace:Tango.PPC.Common.Converters"
+ mc:Ignorable="d"
+ x:Name="MessageNotificationItemControl"
+ d:DesignHeight="60" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:NewSynchronizardJobsNotificationItem, IsDesignTimeCreatable=False}" MinHeight="90" Height="90" MaxHeight="150" Background="White">
+
+ <UserControl.Resources>
+ <BitmapImage x:Key="icon" UriSource="../Images/sync_job.png" />
+ </UserControl.Resources>
+
+ <Grid>
+ <Border BorderThickness="0 0 0 2" BorderBrush="{StaticResource TangoPrimaryAccentBrush}" Padding="15">
+ <DockPanel>
+ <Image Source="{StaticResource icon}" MaxHeight="50" />
+
+ <Grid>
+ <TextBlock Margin="20 0 0 0" VerticalAlignment="Center">
+ New job definitions were synchronized with your machine. Tap to refresh your job list.
+ </TextBlock>
+ </Grid>
+ </DockPanel>
+ </Border>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Represents the <see cref="UpdateAvailableNotificationItemView"/> view.
+ /// </summary>
+ /// <seealso cref="System.Windows.Controls.UserControl" />
+ /// <seealso cref="System.Windows.Markup.IComponentConnector" />
+ 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 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="NotificationItems\NewSynchronizardJobsNotificationItemView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Resources\Styles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -163,6 +167,7 @@
</Compile>
<Compile Include="AppButtons\StartPrintingButton.cs" />
<Compile Include="AppButtons\StopPrintingButton.cs" />
+ <Compile Include="Controls\JobOutlineControl.cs" />
<Compile Include="Controls\RunningJobViewer.xaml.cs">
<DependentUpon>RunningJobViewer.xaml</DependentUpon>
</Compile>
@@ -227,6 +232,10 @@
<Compile Include="NavigationObjects\JobNavigationObject.cs" />
<Compile Include="NavigationObjects\JobSummeryNavigationObject.cs" />
<Compile Include="NavigationObjects\TwineCatalogNavigationObject.cs" />
+ <Compile Include="NotificationItems\NewSynchronizardJobsNotificationItem.cs" />
+ <Compile Include="NotificationItems\NewSynchronizardJobsNotificationItemView.xaml.cs">
+ <DependentUpon>NewSynchronizardJobsNotificationItemView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
@@ -482,10 +491,25 @@
<Resource Include="Images\small-cards-view - blue.png" />
<Resource Include="Images\small-cards-view.png" />
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\color-picker.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\sync.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\JobView\transparent.jpg" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\JobView\transparent_small.jpg" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\sync_job.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
</VisualStudio>
</ProjectExtensions>
</Project> \ 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;
+ /// <summary>
+ /// Gets or sets a value indicating whether to display the job outline.
+ /// </summary>
+ public bool IsDisplayJobOutline
+ {
+ get { return _isDisplayJobOutline; }
+ set { _isDisplayJobOutline = value; RaisePropertyChangedAuto(); }
+ }
+
+ private JobTicket _jobOutlineTicket;
+ /// <summary>
+ /// Gets or sets the job outline ticket.
+ /// </summary>
+ public JobTicket JobOutlineTicket
+ {
+ get { return _jobOutlineTicket; }
+ set { _jobOutlineTicket = value; RaisePropertyChangedAuto(); }
+ }
+
#endregion
#region Commands
@@ -59,6 +81,16 @@ namespace Tango.PPC.Jobs.ViewModels
/// </value>
public RelayCommand GoToJobCommand { get; set; }
+ /// <summary>
+ /// Gets or sets the display job outline command.
+ /// </summary>
+ public RelayCommand DisplayJobOutlineCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the hide job outline command.
+ /// </summary>
+ 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<JobsView>();
}
+ #endregion
+
#region Override Methods
/// <summary>
@@ -94,41 +135,32 @@ namespace Tango.PPC.Jobs.ViewModels
}
/// <summary>
- /// Called when the navigation system has navigated from this VM view.
- /// </summary>
- public override void OnNavigatedFrom()
- {
- base.OnNavigatedFrom();
-
- if (MachineProvider.MachineOperator.IsPrinting && _handler != null && !_handler.IsCanceled)
- {
- NotificationProvider.PushAppBarItem<JobProgressAppBarItem>().Pressed += (_, __) =>
- {
- NotificationProvider.CurrentAppBarItem.Close();
- NavigationManager.NavigateTo<JobsModule>(nameof(JobProgressView));
- };
- }
- }
-
- /// <summary>
/// Called when the navigation system has navigated to this VM view.
/// </summary>
public override void OnNavigatedTo()
{
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();
+ }
+ }
+
/// <summary>
/// Handles the PrintingStarted event of the MachineOperator.
/// </summary>
@@ -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;
}
/// <summary>
@@ -172,12 +206,18 @@ namespace Tango.PPC.Jobs.ViewModels
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
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;
+ }
}
/// <summary>
@@ -193,6 +233,16 @@ namespace Tango.PPC.Jobs.ViewModels
});
}
+ /// <summary>
+ /// Handles the CanCancelChanged event of the JobHandler control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
+ private void 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;
/// <summary>
@@ -59,7 +60,6 @@ namespace Tango.PPC.Jobs.ViewModels
set { _estimatedDuration = value; RaisePropertyChangedAuto(); }
}
-
/// <summary>
/// Gets or sets the dye command.
/// </summary>
@@ -96,12 +96,20 @@ namespace Tango.PPC.Jobs.ViewModels
/// </summary>
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<JobsModule>(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();
+ }
}
/// <summary>
@@ -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<FineTuneItem>(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
/// </summary>
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<JobsModule>(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;
+ }
}
/// <summary>
@@ -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();
}
/// <summary>
@@ -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<ColorConversionSuggestion> suggestions = null;
- vm = await NotificationProvider.ShowDialog<BasicColorCorrectionViewVM>(new BasicColorCorrectionViewVM()
+ if (brushStop.IsOutOfGamut)
{
- InvalidBrushStop = brushStop,
- Suggestions = conversionOutput.CreateTrippletSuggestions(),
- });
+ vm = await NotificationProvider.ShowDialog<BasicColorCorrectionViewVM>(new BasicColorCorrectionViewVM()
+ {
+ InvalidBrushStop = brushStop,
+ Suggestions = new List<ColorConversionSuggestion>() { 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<AdvancedColorCorrectionViewVM>(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();
+ }
}
/// <summary>
@@ -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
/// <summary>
/// Synchronizes the fine tune items to brush stops.
/// </summary>
- 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();
+ }
}
/// <summary>
@@ -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();
+ }
}
/// <summary>
/// Resets the fine tuning.
/// </summary>
- 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);
}
/// <summary>
@@ -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<IJobsView>
{
private ObservablesContext _db; //Holds the db context for the job list.
- private ObservableCollection<ColorCatalog> _catalogs; //Holds the available color catalogs.
+ private ObservableCollection<ColorCatalog> _catalogs; //Holds the available color catalogs for the site.
+ private ObservableCollection<Rml> _rmls; //Holds the available RML for the site.
+ private List<ColorSpace> _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<JobsModule, JobSummeryView, JobSummeryNavigationObject>(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<JobTypes>().ToList(),
- machine.SupportedColorSpaces.Count > 0 ? machine.SupportedColorSpaces : Enum.GetValues(typeof(ColorSpaces)).Cast<ColorSpaces>().Where(x => x.IsUserSpace() || (ApplicationManager.IsInTechnicianMode && x == ColorSpaces.Volume)).ToList()
+ Settings.SupportedJobTypes.Count > 0 ? Settings.SupportedJobTypes : Enum.GetValues(typeof(JobTypes)).Cast<JobTypes>().ToList(),
+ Settings.SupportedColorSpaces.Count > 0 ? Settings.SupportedColorSpaces : Enum.GetValues(typeof(ColorSpaces)).Cast<ColorSpaces>().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<JobCreationViewVM>(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<StorageModule,
Storage.Views.MainView, ExplorerFileItem,
- Storage.Models.StorageNavigationRequest>(
- 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<ExplorerFileItem> jobFiles)
{
var vm = await NotificationProvider.ShowDialog<ImportJobViewVM>();
@@ -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<ExplorerFileItem> 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<ExplorerFileItem> 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<NewSynchronizardJobsNotificationItem>();
+ 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;
/// <summary>
/// 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<JobProgressAppBarItem>();
+ _appBarItem.Pressed += (_, __) =>
+ {
+ _appBarItem?.Close();
+ NavigationManager.NavigateTo<JobsModule>(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
/// <param name="e">The <see cref="Integration.Operation.PrintingFailedEventArgs"/> instance containing the event data.</param>
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<JobsModule, JobView, Job>(e.Job);
NavigationManager.ClearHistoryExcept<JobsView>();
- }));
+ }, NotificationItem.NotificationPriority.VeryHigh));
}
/// <summary>
@@ -119,7 +155,7 @@ namespace Tango.PPC.Jobs.ViewModels
{
NavigationManager.NavigateWithObject<JobsModule, JobView, JobNavigationObject>(new JobNavigationObject() { Job = e.Job });
NavigationManager.ClearHistoryExcept<JobsView>();
- }));
+ }, 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 @@
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 100 0 0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
- <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Text="{Binding Job.Name,FallbackValue='Job Name'}"></TextBlock>
+ <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Text="{Binding Job.Name,FallbackValue='Job Name'}" TextWrapping="Wrap" MaxWidth="700"></TextBlock>
<TextBlock FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}" VerticalAlignment="Center" Margin="10 0 0 0" Visibility="{Binding Job.Designation,Converter={StaticResource EnumToVisibilityConverter},ConverterParameter='SampleDye'}">(Sample)</TextBlock>
<TextBlock FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}" VerticalAlignment="Center" Margin="10 0 0 0" Visibility="{Binding Job.Designation,Converter={StaticResource EnumToVisibilityConverter},ConverterParameter='FineTuning'}">(Fine Tuning)</TextBlock>
</StackPanel>
@@ -38,6 +38,8 @@
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RunningJobStatus.IsCompleted}" Value="True">
+ <Setter Property="Maximum" Value="100"></Setter>
+ <Setter Property="Value" Value="99.9999999"></Setter>
<Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RunningJobStatus.IsCanceled}" Value="True">
@@ -98,7 +100,7 @@
<StackPanel Height="90" Visibility="{Binding RunningJobStatus.IsSettingUp,Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Image Source="../Images/JobProgressView/drop.png" Stretch="None" />
- <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Getting ready...</TextBlock>
+ <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Getting Ready...</TextBlock>
</StackPanel>
</StackPanel>
@@ -117,8 +119,8 @@
</Grid>
<Grid Margin="0 150 0 0">
- <StackPanel>
- <Canvas Height="80" Margin="5 0">
+ <StackPanel MaxWidth="600">
+ <Canvas Height="80" Margin="0">
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
@@ -138,64 +140,58 @@
</Style.Triggers>
</Style>
</StackPanel.Style>
- <StackPanel Margin="-50 0 0 0">
- <ContentControl>
- <ContentControl.Style>
- <Style TargetType="ContentControl">
- <Setter Property="Content">
- <Setter.Value>
- <StackPanel>
- <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
- <TextBlock.Style>
- <Style TargetType="TextBlock">
- <Setter Property="Text" Value="now dyeing"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding RunningJobStatus.IsSettingUp}" Value="True">
- <Setter Property="Text" Value="getting ready"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </TextBlock.Style>
- </TextBlock>
- <touch:TouchIcon Margin="0 8 0 0" HorizontalAlignment="Center" Icon="Water" Angle="180" Foreground="{StaticResource TangoPrimaryAccentBrush}" Width="40" Height="40" />
- </StackPanel>
- </Setter.Value>
- </Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding RunningJobStatus.IsCanceled}" Value="True">
- <Setter Property="Content">
- <Setter.Value>
- <StackPanel>
- <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">job canceled</TextBlock>
- <touch:TouchIcon Margin="0 8 0 0" HorizontalAlignment="Center" Icon="Alert" Foreground="{StaticResource TangoWarningBrush}" Width="40" Height="40" />
- </StackPanel>
- </Setter.Value>
- </Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding RunningJobStatus.IsFailed}" Value="True">
- <Setter Property="Content">
- <Setter.Value>
- <StackPanel>
- <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">job failed</TextBlock>
- <touch:TouchIcon Margin="0 8 0 0" HorizontalAlignment="Center" Icon="AlertOctagon" Foreground="{StaticResource TangoErrorBrush}" Width="40" Height="40" />
- </StackPanel>
- </Setter.Value>
- </Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding RunningJobStatus.IsCompleted}" Value="True">
- <Setter Property="Content">
- <Setter.Value>
- <StackPanel>
- <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">job completed</TextBlock>
- <touch:TouchIcon Margin="0 8 0 0" HorizontalAlignment="Center" Icon="Check" Foreground="{StaticResource TangoSuccessBrush}" Width="40" Height="40" />
- </StackPanel>
- </Setter.Value>
- </Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </ContentControl.Style>
- </ContentControl>
+ <StackPanel Margin="-20 20 0 0">
+ <StackPanel>
+ <Canvas HorizontalAlignment="Center">
+ <TextBlock Margin="0 -25 0 0" Canvas.Left="{Binding RelativeSource={RelativeSource Mode=Self},Path=ActualWidth,Converter={StaticResource MathOperatorConverter},ConverterParameter='*-0.5'}" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Now Dyeing"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsSettingUp}" Value="True">
+ <Setter Property="Text" Value="Getting Ready"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsCanceled}" Value="True">
+ <Setter Property="Text" Value="Job Canceled"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsFailed}" Value="True">
+ <Setter Property="Text" Value="Job Failed"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsCompleted}" Value="True">
+ <Setter Property="Text" Value="Job Completed"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
+ </Canvas>
+ <touch:TouchIcon Margin="0 8 0 0" HorizontalAlignment="Center" Width="40" Height="40">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon" BasedOn="{StaticResource {x:Type touch:TouchIcon}}">
+ <Setter Property="Angle" Value="180"></Setter>
+ <Setter Property="Icon" Value="Water"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsCanceled}" Value="True">
+ <Setter Property="Angle" Value="0"></Setter>
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsFailed}" Value="True">
+ <Setter Property="Angle" Value="0"></Setter>
+ <Setter Property="Icon" Value="AlertOctagon"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RunningJobStatus.IsCompleted}" Value="True">
+ <Setter Property="Angle" Value="0"></Setter>
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </StackPanel>
</StackPanel>
</StackPanel>
</Canvas>
@@ -214,5 +210,23 @@
Go to job
</touch:TouchButton>
</StackPanel>
+
+ <touch:TouchButton Visibility="{Binding ApplicationManager.IsInTechnicianMode,Converter={StaticResource BooleanToVisibilityConverter}}" VerticalAlignment="Bottom" Margin="0 100 0 0" Command="{Binding DisplayJobOutlineCommand}" Style="{StaticResource TangoLinkButton}" Height="60" FontSize="{StaticResource TangoTitleFontSize}">
+ Display Job Outline
+ </touch:TouchButton>
+
+ <Grid Visibility="{Binding IsDisplayJobOutline,Converter={StaticResource BooleanToVisibilityConverter}}" Background="{StaticResource TangoPrimaryBackgroundBrush}" Opacity="0.8"/>
+
+ <Grid Margin="0 -10 0 0" Visibility="{Binding IsDisplayJobOutline,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <Grid>
+ <touch:TouchScrollViewer BorderThickness="0" Padding="10" Margin="0 0 0 100">
+ <global:JobOutlineControl BorderThickness="0" Margin="20" DataContext="{Binding JobOutlineTicket}" HorizontalAlignment="Left" />
+ </touch:TouchScrollViewer>
+ </Grid>
+
+ <touch:TouchButton Background="{StaticResource TangoPrimaryBackgroundBrush}" VerticalAlignment="Bottom" Margin="0 100 0 0" Command="{Binding HideJobOutlineCommand}" Style="{StaticResource TangoLinkButton}" Height="60" FontSize="{StaticResource TangoTitleFontSize}">
+ Hide Job Outline
+ </touch:TouchButton>
+ </Grid>
</Grid>
</UserControl>
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 @@
<RowDefinition Height="300*"/>
</Grid.RowDefinitions>
- <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Text="{Binding Job.Name}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
+ <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Text="{Binding Job.Name}" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap"></TextBlock>
<Grid Grid.Row="1" Width="360" Height="360">
<touch:TouchBusyIndicator Opacity="0.6" IsIndeterminate="False" Foreground="{StaticResource TangoGrayBrush}" StrokeThickness="10" Minimum="0" Maximum="100" Value="99.999" Width="Auto" Height="Auto">
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 @@
<BitmapImage x:Key="Image_Out_Of_Gamut" UriSource="../Images/JobView/error.png" />
<BitmapImage x:Key="Image_Replace_Color" UriSource="../Images/JobView/replace-color.png" />
<BitmapImage x:Key="Image_Color_Picker" UriSource="../Images/JobView/color-picker.png" />
+ <BitmapImage x:Key="Image_Transparent" UriSource="../Images/JobView/transparent.jpg" />
+ <BitmapImage x:Key="Image_TransparentSmall" UriSource="../Images/JobView/transparent_small.jpg" />
<Style TargetType="FrameworkElement" x:Key="Level1Container">
@@ -111,9 +113,24 @@
<StackPanel>
<StackPanel Orientation="Horizontal">
<Border Width="48" Height="48" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource TangoGrayBrush}">
- <Border.Background>
- <SolidColorBrush Color="{Binding Color,IsAsync=True}"></SolidColorBrush>
- </Border.Background>
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="Background">
+ <Setter.Value>
+ <SolidColorBrush Color="{Binding Color,IsAsync=True}" />
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsTransparent,IsAsync=True}" Value="True" >
+ <Setter Property="Background">
+ <Setter.Value>
+ <ImageBrush ImageSource="{StaticResource Image_TransparentSmall}" Stretch="None" />
+ </Setter.Value>
+ </Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
</Border>
<TextBlock Margin="30 0 0 0" FontSize="{StaticResource TangoTitleFontSize}">
@@ -147,6 +164,17 @@
<DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="Volume">
<Setter Property="ContentTemplate" Value="{StaticResource Volume_Template}" />
</DataTrigger>
+ <DataTrigger Binding="{Binding IsTransparent,IsAsync=True}" Value="True">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
+ <Grid Height="40">
+ <TextBlock VerticalAlignment="Bottom" Foreground="{StaticResource TangoGrayBrush}">Transparent</TextBlock>
+ </Grid>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ </DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
@@ -172,7 +200,10 @@
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0 0 -130 0" HorizontalAlignment="Right" VerticalAlignment="Top">
- <touch:TouchImageButton Command="{Binding ElementName=view,Path=DataContext.ReplaceBrushStopCommand,IsAsync=True}" CommandParameter="{Binding}" Visibility="{Binding IsOutOfGamut,Converter={StaticResource BooleanToVisibilityConverter},IsAsync=True}" Width="50" Height="50" Padding="10" Image="{StaticResource Image_Replace_Color}" CornerRadius="30"></touch:TouchImageButton>
+ <StackPanel Orientation="Horizontal" Visibility="{Binding ElementName=toggleEdit,Path=IsChecked,IsAsync=True,Converter={StaticResource BooleanToVisibilityInverseConverter}}">
+ <!--<touch:TouchToggleIconButton Padding="15" Width="60" Height="60" CornerRadius="30" Icon="EyeOutline" CheckedIcon="EyeOffOutline" Foreground="{StaticResource TangoGrayBrush}" CheckedForeground="{StaticResource TangoGrayBrush}" IsChecked="{Binding IsTransparent,IsAsync=True}"></touch:TouchToggleIconButton>-->
+ <touch:TouchImageButton Command="{Binding ElementName=view,Path=DataContext.ReplaceBrushStopCommand,IsAsync=True}" CommandParameter="{Binding}" Visibility="{Binding ColorSpace,Converter={StaticResource ColorSpaceToVisibilityConverter},IsAsync=True}" Width="50" Height="50" Padding="10" Image="{StaticResource Image_Replace_Color}" CornerRadius="30"></touch:TouchImageButton>
+ </StackPanel>
<touch:TouchIconButton Margin="0 0 50 0" Visibility="{Binding ElementName=toggleEdit,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding ElementName=view,Path=DataContext.RemoveBrushStopCommand,IsAsync=True}" CommandParameter="{Binding}" EnableDropShadow="False" Icon="TrashAltRegular" Padding="12" Foreground="{StaticResource TangoPrimaryAccentBrush}" Width="50" Height="50" RippleBrush="{StaticResource TangoRippleDarkBrush}" CornerRadius="30" />
</StackPanel>
</Grid>
@@ -214,7 +245,11 @@
</Style.Triggers>
</Style>
</DockPanel.Style>
- <Border DockPanel.Dock="Left" Background="{Binding SegmentBrush}" BorderThickness="0 0 1 0" BorderBrush="{StaticResource TangoLightBorderBrush}">
+
+ <Border DockPanel.Dock="Left" BorderThickness="0 0 1 0" BorderBrush="{StaticResource TangoLightBorderBrush}">
+ <Border.Background>
+ <ImageBrush ImageSource="{StaticResource Image_Transparent}" Stretch="None" />
+ </Border.Background>
<Border.Style>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="8 0 0 8"></Setter>
@@ -233,6 +268,26 @@
</Style.Triggers>
</Style>
</Border.Style>
+ <Border Background="{Binding SegmentBrush}">
+ <Border.Style>
+ <Style TargetType="Border">
+ <Setter Property="CornerRadius" Value="8 0 0 8"></Setter>
+ <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight,IsAsync=True}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=toggle_small_list,Path=IsChecked,IsAsync=True}" Value="True">
+ <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight,Converter={StaticResource MathOperatorConverter},ConverterParameter='*2',IsAsync=True}"></Setter>
+ </DataTrigger>
+ <MultiDataTrigger>
+ <MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="True"></Condition>
+ <Condition Binding="{Binding ElementName=toggle_large_list,Path=IsChecked,IsAsync=True}" Value="True"></Condition>
+ </MultiDataTrigger.Conditions>
+ <Setter Property="CornerRadius" Value="8 0 0 0"></Setter>
+ </MultiDataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Style>
+ </Border>
</Border>
<Grid>
@@ -247,77 +302,90 @@
</TextBlock>
</StackPanel>
- <StackPanel Margin="0 30 0 0" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="300" Visibility="{Binding ElementName=toggle_large_list,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter},IsAsync=True}">
- <DockPanel LastChildFill="False">
- <DockPanel.Style>
- <Style TargetType="DockPanel">
- <Setter Property="Visibility" Value="Visible"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="True">
- <Setter Property="Visibility" Value="Collapsed"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </DockPanel.Style>
- <TextBlock VerticalAlignment="Bottom" DockPanel.Dock="Left" Text="Color code:"></TextBlock>
+ <Grid>
+ <StackPanel Margin="0 30 0 0" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="300" Visibility="{Binding ElementName=toggle_large_list,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter},IsAsync=True}">
+ <DockPanel LastChildFill="False">
+ <DockPanel.Style>
+ <Style TargetType="DockPanel">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="True">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </DockPanel.Style>
+ <TextBlock VerticalAlignment="Bottom" DockPanel.Dock="Left" Text="Color code:"></TextBlock>
- <Grid DockPanel.Dock="Right" DataContext="{Binding BrushStops[0],IsAsync=True}">
- <StackPanel>
- <ContentControl Focusable="False" FocusVisualStyle="{x:Null}" d:DataContext="{d:DesignInstance Type=entities:BrushStop, IsDesignTimeCreatable=False}" Content="{Binding}" Width="180">
- <ContentControl.Style>
- <Style TargetType="ContentControl">
- <Setter Property="ContentTemplate">
- <Setter.Value>
- <DataTemplate>
+ <Grid DockPanel.Dock="Right" DataContext="{Binding BrushStops[0],IsAsync=True}">
+ <StackPanel>
+ <ContentControl Focusable="False" FocusVisualStyle="{x:Null}" d:DataContext="{d:DesignInstance Type=entities:BrushStop, IsDesignTimeCreatable=False}" Content="{Binding}" Width="180">
+ <ContentControl.Style>
+ <Style TargetType="ContentControl">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
- </DataTemplate>
- </Setter.Value>
- </Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="RGB">
- <Setter Property="ContentTemplate" Value="{StaticResource RGB_Template}" />
- </DataTrigger>
- <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="CMYK">
- <Setter Property="ContentTemplate" Value="{StaticResource CMYK_Template}" />
- </DataTrigger>
- <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="LAB">
- <Setter Property="ContentTemplate" Value="{StaticResource LAB_Template}" />
- </DataTrigger>
- <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="Catalog">
- <Setter Property="ContentTemplate" Value="{StaticResource CATALOG_Template}" />
- </DataTrigger>
- <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="Volume">
- <Setter Property="ContentTemplate" Value="{StaticResource Volume_Template}" />
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </ContentControl.Style>
- </ContentControl>
- </StackPanel>
- </Grid>
- </DockPanel>
- <Canvas>
- <Canvas.Style>
- <Style TargetType="Canvas">
- <Setter Property="Visibility" Value="Collapsed"></Setter>
- <Style.Triggers>
- <MultiDataTrigger>
- <MultiDataTrigger.Conditions>
- <Condition Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="False" />
- <Condition Binding="{Binding BrushStops[0].IsOutOfGamut,IsAsync=True}" Value="True" />
- </MultiDataTrigger.Conditions>
- <Setter Property="Visibility" Value="Visible"></Setter>
- </MultiDataTrigger>
- </Style.Triggers>
- </Style>
- </Canvas.Style>
- <TextBlock Canvas.Top="2" Foreground="{StaticResource TangoErrorBrush}" FontSize="{StaticResource TangoSmallFontSize}" Text="Color is out of gamut. Modify color or select an alternative."></TextBlock>
- </Canvas>
- <DockPanel LastChildFill="False" Margin="0 20 0 0">
- <TextBlock VerticalAlignment="Bottom" DockPanel.Dock="Left" Text="Length (m):"></TextBlock>
- <touch:TouchNumericTextBox Width="180" DockPanel.Dock="Right" Value="{Binding Length}" StringFormat="0.0" AutoCalculateJogStep="False" HasDecimalPoint="True" Minimum="1" Maximum="100000" KeyboardContainer="{Binding ElementName=Container}" />
- </DockPanel>
- </StackPanel>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="RGB">
+ <Setter Property="ContentTemplate" Value="{StaticResource RGB_Template}" />
+ </DataTrigger>
+ <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="CMYK">
+ <Setter Property="ContentTemplate" Value="{StaticResource CMYK_Template}" />
+ </DataTrigger>
+ <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="LAB">
+ <Setter Property="ContentTemplate" Value="{StaticResource LAB_Template}" />
+ </DataTrigger>
+ <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="Catalog">
+ <Setter Property="ContentTemplate" Value="{StaticResource CATALOG_Template}" />
+ </DataTrigger>
+ <DataTrigger Binding="{Binding ElementName=view,Path=DataContext.Job.ColorSpace.Name,IsAsync=True}" Value="Volume">
+ <Setter Property="ContentTemplate" Value="{StaticResource Volume_Template}" />
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsTransparent,IsAsync=True}" Value="True">
+ <Setter Property="ContentTemplate">
+ <Setter.Value>
+ <DataTemplate>
+ <Grid Height="40">
+ <TextBlock VerticalAlignment="Bottom" Foreground="{StaticResource TangoGrayBrush}">Transparent</TextBlock>
+ </Grid>
+ </DataTemplate>
+ </Setter.Value>
+ </Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </ContentControl.Style>
+ </ContentControl>
+ </StackPanel>
+ </Grid>
+ </DockPanel>
+ <Canvas>
+ <Canvas.Style>
+ <Style TargetType="Canvas">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <MultiDataTrigger>
+ <MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="False" />
+ <Condition Binding="{Binding BrushStops[0].IsOutOfGamut,IsAsync=True}" Value="True" />
+ </MultiDataTrigger.Conditions>
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </MultiDataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Canvas.Style>
+ <TextBlock Canvas.Top="2" Foreground="{StaticResource TangoErrorBrush}" FontSize="{StaticResource TangoSmallFontSize}" Text="Color is out of gamut. Modify color or select an alternative."></TextBlock>
+ </Canvas>
+ <DockPanel LastChildFill="False" Margin="0 20 0 0">
+ <TextBlock VerticalAlignment="Bottom" DockPanel.Dock="Left" Text="Length (m):"></TextBlock>
+ <touch:TouchNumericTextBox Width="180" DockPanel.Dock="Right" Value="{Binding Length}" StringFormat="0.0" AutoCalculateJogStep="False" HasDecimalPoint="True" Minimum="1" Maximum="100000" KeyboardContainer="{Binding ElementName=Container}" />
+ </DockPanel>
+ </StackPanel>
+ </Grid>
</DockPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0 10 10 0">
@@ -334,23 +402,27 @@
</TextBlock.Style>
</TextBlock>
- <touch:TouchImageButton Command="{Binding ElementName=view,Path=DataContext.ReplaceBrushStopCommand}" CommandParameter="{Binding BrushStops[0]}" Width="50" Height="50" Padding="10" Image="{StaticResource Image_Replace_Color}" CornerRadius="30">
- <touch:TouchImageButton.Style>
- <Style TargetType="{x:Type touch:TouchImageButton}" BasedOn="{StaticResource {x:Type touch:TouchImageButton}}">
+ <StackPanel Orientation="Horizontal">
+ <StackPanel.Style>
+ <Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding ElementName=toggleEdit,Path=IsChecked,IsAsync=True}" Value="False" />
<Condition Binding="{Binding ElementName=toggle_large_list,Path=IsChecked,IsAsync=True}" Value="True" />
<Condition Binding="{Binding Converter={StaticResource IsSegmentGradientConverter},IsAsync=True}" Value="False" />
- <Condition Binding="{Binding BrushStops[0].IsOutOfGamut,IsAsync=True}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Visible"></Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
- </touch:TouchImageButton.Style>
- </touch:TouchImageButton>
+ </StackPanel.Style>
+
+ <!--<touch:TouchToggleIconButton Padding="15" Width="60" Height="60" CornerRadius="30" Icon="EyeOutline" CheckedIcon="EyeOffOutline" Foreground="{StaticResource TangoGrayBrush}" CheckedForeground="{StaticResource TangoGrayBrush}" IsChecked="{Binding BrushStops[0].IsTransparent,IsAsync=True}"></touch:TouchToggleIconButton>-->
+
+ <touch:TouchImageButton Visibility="{Binding BrushStops[0].ColorSpace,Converter={StaticResource ColorSpaceToVisibilityConverter},IsAsync=True}" Command="{Binding ElementName=view,Path=DataContext.ReplaceBrushStopCommand}" CommandParameter="{Binding BrushStops[0]}" Width="50" Height="50" Padding="10" Image="{StaticResource Image_Replace_Color}" CornerRadius="30"></touch:TouchImageButton>
+ </StackPanel>
<StackPanel Visibility="{Binding ElementName=toggleEdit,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter},IsAsync=True}" Orientation="Horizontal">
@@ -454,9 +526,9 @@
<touch:TouchComboBox ItemsSource="{Binding Rmls}" SelectedItem="{Binding Job.Rml}" DisplayMemberPath="Name" Title="Select Thread" />
<TextBlock>Comment:</TextBlock>
- <TextBox Margin="20 0 0 -42" Text="{Binding Job.Description}" FocusVisualStyle="{x:Null}" BorderBrush="{StaticResource TangoDividerBrush}" Foreground="{StaticResource TangoDarkForegroundBrush}" AcceptsReturn="True" TextWrapping="Wrap" Height="60" Padding="5" keyboard:KeyboardView.Container="{Binding ElementName=Container}" keyboard:KeyboardView.Mode="AlphaNumeric">
+ <touch:TouchMultiLineTextBox Margin="20 0 0 -42" Text="{Binding Job.Description}" Height="60" keyboard:KeyboardView.Container="{Binding ElementName=Container}">
- </TextBox>
+ </touch:TouchMultiLineTextBox>
</controls:TableGrid>
<Grid HorizontalAlignment="Center" Margin="0 20 0 0" TextElement.Foreground="{StaticResource TangoGrayTextBrush}">
@@ -559,7 +631,6 @@
<touch:TouchToggleImageButton x:Name="toggleEdit" UncheckedImage="../Images/pencil-gray.png"
CheckedImage="../Images/pencil-blue.png"
DockPanel.Dock="Right"
- IsChecked="{Binding IsSelected}"
Padding="8" CornerRadius="30" Width="40" Height="40">
</touch:TouchToggleImageButton>
<!--<touch:TouchToggleIconButton x:Name="toggleEdit" DockPanel.Dock="Right" Icon="Pencil" CheckedIcon="Pencil" Padding="8" CornerRadius="20" />-->
@@ -647,63 +718,61 @@
</touch:TouchDropShadowBorder>
</touch:TouchVirtualizedContentControl>
- <touch:TouchVirtualizedContentControl Margin="0 20 0 0" >
- <touch:TouchDropShadowBorder Padding="0 0 0 50">
- <StackPanel>
- <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
- <Image Source="../Images/JobView/job-summary.png" Width="39" />
- <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Job Summary</TextBlock>
- </StackPanel>
+ <touch:TouchDropShadowBorder Padding="0 20 0 50" Margin="0 0 0 15">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <Image Source="../Images/JobView/job-summary.png" Width="39" />
+ <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Job Summary</TextBlock>
+ </StackPanel>
- <StackPanel Style="{StaticResource Level2ContainerExtraMargin}">
- <Grid>
- <localControls:JobSummeryViewer DataContext="{Binding Job,IsAsync=True}" Height="40"/>
- </Grid>
+ <StackPanel Style="{StaticResource Level2ContainerExtraMargin}">
+ <Grid>
+ <localControls:JobSummeryViewer DataContext="{Binding Job,IsAsync=True}" Height="40"/>
+ </Grid>
- <DockPanel Margin="0 30 0 0" LastChildFill="False">
+ <DockPanel Margin="0 30 0 0" LastChildFill="False">
- <StackPanel Orientation="Horizontal" DockPanel.Dock="Left" VerticalAlignment="Center">
- <TextBlock>
+ <StackPanel Orientation="Horizontal" DockPanel.Dock="Left" VerticalAlignment="Center">
+ <TextBlock>
<Run Text="Job length (m):"></Run>
<Run Text="{Binding Job.Length,Mode=OneWay}"></Run>
- </TextBlock>
- <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
- <TextBlock.Style>
- <Style TargetType="TextBlock">
- <Setter Property="Visibility" Value="Collapsed"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding Job.LengthPercentageFactor,Converter={StaticResource GreaterThanToBooleanConverter},ConverterParameter=0}" Value="True">
- <Setter Property="Visibility" Value="Visible"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </TextBlock.Style>
+ </TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Job.LengthPercentageFactor,Converter={StaticResource GreaterThanToBooleanConverter},ConverterParameter=0}" Value="True">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
<Run>(</Run><Run Text="{Binding Job.Length,Mode=OneWay}"></Run><Run>+</Run><Run Text="{Binding Job.LengthPercentageFactor,Mode=OneWay}"></Run><Run>%</Run><Run>)</Run>
- </TextBlock>
- </StackPanel>
+ </TextBlock>
+ </StackPanel>
- <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0 -20 5 0">
- <TextBlock Margin="0 3 0 0" Foreground="{StaticResource TangoGrayTextBrush}" VerticalAlignment="Bottom">
+ <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0 -20 5 0">
+ <TextBlock Margin="0 3 0 0" Foreground="{StaticResource TangoGrayTextBrush}" VerticalAlignment="Bottom">
<Run Text="Factor: +"></Run>
- </TextBlock>
+ </TextBlock>
- <touch:TouchNumericTextBox Foreground="{StaticResource TangoGrayTextBrush}" Margin="5 0 0 0" Width="50" HorizontalContentAlignment="Center" Maximum="100" Minimum="0" Value="{Binding Job.LengthPercentageFactor}" KeyboardContainer="{Binding ElementName=Container}" StringFormat="0" FocusSelectionMode="SelectAll" />
+ <touch:TouchNumericTextBox Foreground="{StaticResource TangoGrayTextBrush}" Margin="5 0 0 0" Width="50" HorizontalContentAlignment="Center" Maximum="100" Minimum="0" Value="{Binding Job.LengthPercentageFactor}" KeyboardContainer="{Binding ElementName=Container}" StringFormat="0" FocusSelectionMode="SelectAll" />
- <TextBlock VerticalAlignment="Bottom" Foreground="{StaticResource TangoGrayTextBrush}">%</TextBlock>
+ <TextBlock VerticalAlignment="Bottom" Foreground="{StaticResource TangoGrayTextBrush}">%</TextBlock>
- <Image Margin="10 0 0 0" Source="../Images/JobView/settings.png" VerticalAlignment="Bottom" />
- </StackPanel>
- </DockPanel>
- </StackPanel>
+ <Image Margin="10 0 0 0" Source="../Images/JobView/settings.png" VerticalAlignment="Bottom" />
+ </StackPanel>
+ </DockPanel>
</StackPanel>
- </touch:TouchDropShadowBorder>
- </touch:TouchVirtualizedContentControl>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
- <StackPanel HorizontalAlignment="Center" Margin="20 40 0 40" Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <StackPanel Visibility="Collapsed" HorizontalAlignment="Center" Margin="20 40 0 40" Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
<TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Additional Tools</TextBlock>
</StackPanel>
- <touch:TouchVirtualizedContentControl>
+ <!--<touch:TouchVirtualizedContentControl>
<touch:TouchExpander x:Name="expander_sample_dye" Margin="0 0 0 0" Padding="20 15">
<touch:TouchExpander.Header>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0 0 20 0">
@@ -871,7 +940,7 @@
</touch:TouchVirtualizedContentControl>
<touch:TouchVirtualizedContentControl>
- <touch:TouchExpander x:Name="expander_fine_tuning" Margin="0 20 0 120" Padding="20 15" IsExpanded="{Binding IsFineTuneExpanded,Mode=TwoWay}" Visibility="{Binding Job.ColorSpace,Converter={StaticResource ColorSpaceToVisibilityConverter}}">
+ <touch:TouchExpander x:Name="expander_fine_tuning" Margin="0 20 0 120" Padding="20 15" IsExpanded="{Binding IsFineTuneExpanded,Mode=TwoWay}" Visibility="{Binding Job.ColorSpace,Converter={StaticResource ColorSpaceToVisibilityConverter},ConverterParameter='RGB,LAB'}">
<touch:TouchExpander.Header>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0 0 20 0">
<Image Source="../Images/JobView/color-fine-tuning.png" Width="39" />
@@ -1102,7 +1171,7 @@
</ContentControl>
</StackPanel>
</touch:TouchExpander>
- </touch:TouchVirtualizedContentControl>
+ </touch:TouchVirtualizedContentControl>-->
</StackPanel>
</StackPanel>
</touch:LightTouchScrollViewer>
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 @@
<touch:LightTouchDataGridColumn Width="1*" Header="Name" SortMember="Name" HorizontalContentAlignment="Left">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding Name,IsAsync=True}"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding Name,Converter={StaticResource StringEllipsisConverter},ConverterParameter='40'}"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
<touch:LightTouchDataGridColumn Width="117" Header="Length (m)" SortMember="Length">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding Length,StringFormat=0.0,IsAsync=True}"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding Length,StringFormat=0.0}"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
@@ -235,7 +235,7 @@
<touch:LightTouchDataGridColumn Width="100" Header="Updated" SortMember="LastUpdated">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateConverter},IsAsync=True}"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateConverter}}"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
@@ -314,21 +314,21 @@
<touch:LightTouchDataGridColumn Width="100" Header="Status" SortMember="JobStatus" HorizontalContentAlignment="Left">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding JobStatus,Converter={StaticResource EnumToDescriptionConverter},IsAsync=True}" HorizontalAlignment="Left" VerticalAlignment="Center"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding JobStatus,Converter={StaticResource EnumToDescriptionConverter}}" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
<touch:LightTouchDataGridColumn Width="1*" Header="Name" SortMember="Name" HorizontalContentAlignment="Left">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding Name,IsAsync=True}" HorizontalAlignment="Left" VerticalAlignment="Center"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding Name,Converter={StaticResource StringEllipsisConverter},ConverterParameter='40'}" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
<touch:LightTouchDataGridColumn Width="117" Header="Length (m)" SortMember="Length">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding Length,StringFormat=0.0,IsAsync=True}"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding Length,StringFormat=0.0}"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
@@ -342,7 +342,7 @@
<touch:LightTouchDataGridColumn Width="100" Header="Updated" SortMember="LastUpdated">
<touch:LightTouchDataGridColumn.CellTemplate>
<DataTemplate>
- <controls:FastTextBlock IsHitTestVisible="False" Text="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateConverter},IsAsync=True}"></controls:FastTextBlock>
+ <TextBlock IsHitTestVisible="False" Text="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateConverter}}"></TextBlock>
</DataTemplate>
</touch:LightTouchDataGridColumn.CellTemplate>
</touch:LightTouchDataGridColumn>
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 <see cref="MachineSettingsModule"/>.
/// </summary>
/// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
- [PPCModule(2)]
+ [PPCModule(4)]
public class MachineSettingsModule : PPCModuleBase
{
/// <summary>
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
/// <seealso cref="Tango.PPC.Common.PPCViewModel" />
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<Rml> _rmls;
+ public ObservableCollection<Rml> 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<TimeZoneInfo> _timeZones;
+ /// <summary>
+ /// Gets or sets the available time zones.
+ /// </summary>
+ public List<TimeZoneInfo> TimeZones
+ {
+ get { return _timeZones; }
+ set { _timeZones = value; RaisePropertyChangedAuto(); }
+ }
+
+ private TimeZoneInfo _selectedTimeZone;
+ /// <summary>
+ /// Gets or sets the selected time zone.
+ /// </summary>
+ 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
/// </summary>
public RelayCommand DiscardCommand { get; set; }
+ /// <summary>
+ /// Gets or sets the synchronize command.
+ /// </summary>
+ 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
/// </summary>
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<JobTypes>(Enum.GetValues(typeof(JobTypes)).Cast<JobTypes>().ToObservableCollection(), Machine.SupportedJobTypes.ToObservableCollection());
- SelectedColorSpaces = new SelectedObjectCollection<ColorSpaces>(Enum.GetValues(typeof(ColorSpaces)).Cast<ColorSpaces>().Where(x => x.IsUserSpace()).ToObservableCollection(), Machine.SupportedColorSpaces.ToObservableCollection());
+ SelectedJobTypes = new SelectedObjectCollection<JobTypes>(Enum.GetValues(typeof(JobTypes)).Cast<JobTypes>().ToObservableCollection(), Settings.SupportedJobTypes.ToObservableCollection());
+ SelectedColorSpaces = new SelectedObjectCollection<ColorSpaces>(Enum.GetValues(typeof(ColorSpaces)).Cast<ColorSpaces>().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}">
- <Grid Background="{StaticResource TangoMidBackgroundBrush}">
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}" IsEnabled="{Binding IsFree}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
@@ -83,7 +87,7 @@
</touch:TouchExpander>
<!--JOBS-->
- <touch:TouchExpander Margin="0 20 0 0" Header="JOBS" IsExpanded="True" FontSize="{StaticResource TangoExpanderHeaderFontSize}">
+ <touch:TouchExpander Margin="0 20 0 0" Header="Jobs" IsExpanded="True" FontSize="{StaticResource TangoExpanderHeaderFontSize}">
<StackPanel>
<controls:TableGrid Margin="10" RowHeight="70" MakeFirstColumnVerticalAlignmentBottom="False" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
<TextBlock VerticalAlignment="Center">Supported Job Types</TextBlock>
@@ -136,14 +140,14 @@
</ItemsControl.ItemTemplate>
</ItemsControl>
- <TextBlock VerticalAlignment="Bottom">Default Thread Type</TextBlock>
- <touch:TouchComboBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" ItemsSource="{Binding Adapter.Rmls}" SelectedItem="{Binding Machine.DefaultRml}" DisplayMemberPath="Name" ValuePath="Guid"></touch:TouchComboBox>
+ <TextBlock VerticalAlignment="Bottom">Default Thread</TextBlock>
+ <touch:TouchComboBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" ItemsSource="{Binding Rmls}" SelectedItem="{Binding DefaultRML}" DisplayMemberPath="Name"></touch:TouchComboBox>
- <!--<TextBlock VerticalAlignment="Bottom">Default Spool</TextBlock>
- <touch:TouchComboBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" ItemsSource="{Binding Adapter.SpoolTypes}" SelectedItem="{Binding Machine.DefaultSpoolType}" DisplayMemberPath="Name"></touch:TouchComboBox>-->
+ <TextBlock VerticalAlignment="Bottom">Default Spool</TextBlock>
+ <touch:TouchComboBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" ItemsSource="{Binding Adapter.SpoolTypes}" SelectedItem="{Binding DefaultSpoolType}" DisplayMemberPath="Name"></touch:TouchComboBox>
<TextBlock VerticalAlignment="Bottom">Default Segment Length</TextBlock>
- <touch:TouchNumericTextBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" Minimum="1" Maximum="1000" Value="{Binding Machine.DefaultSegmentLength}" HasDecimalPoint="True" KeyboardContainer="{Binding ElementName=Container}"></touch:TouchNumericTextBox>
+ <touch:TouchNumericTextBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="200" Minimum="1" Maximum="1000" Value="{Binding Settings.DefaultSegmentLength}" HasDecimalPoint="True" KeyboardContainer="{Binding ElementName=Container}"></touch:TouchNumericTextBox>
</controls:TableGrid>
@@ -195,6 +199,172 @@
</DockPanel>
</StackPanel>
</touch:TouchExpander>
+
+ <!--SYNCHRONIZATION-->
+ <touch:TouchExpander Margin="0 20 0 0" Header="Cloud Synchronization" IsExpanded="True" FontSize="{StaticResource TangoExpanderHeaderFontSize}">
+ <StackPanel Margin="10 30 10 10">
+
+ <DockPanel TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <StackPanel>
+ <TextBlock VerticalAlignment="Center">Auto Update Check</TextBlock>
+ <DockPanel Margin="0 5 0 0">
+ <touch:TouchIcon VerticalAlignment="Top" Icon="InformationOutline" Foreground="{StaticResource TangoGrayTextBrush}"></touch:TouchIcon>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ Automatically check for software and database updates.
+ </TextBlock>
+ </DockPanel>
+ </StackPanel>
+ <touch:TouchToggleSlider Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90" IsChecked="{Binding AutoCheckForUpdates}"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 40 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <StackPanel>
+ <TextBlock VerticalAlignment="Center">Synchronize Jobs</TextBlock>
+ <DockPanel Margin="0 5 0 0">
+ <touch:TouchIcon VerticalAlignment="Top" Icon="InformationOutline" Foreground="{StaticResource TangoGrayTextBrush}"></touch:TouchIcon>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ Synchronize your jobs with twine's cloud services.
+ </TextBlock>
+ </DockPanel>
+ </StackPanel>
+ <touch:TouchToggleSlider Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90" IsChecked="{Binding SynchronizeJobs}"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 40 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <StackPanel>
+ <TextBlock VerticalAlignment="Center">Synchronize Diagnostics Data</TextBlock>
+ <DockPanel Margin="0 5 0 0">
+ <touch:TouchIcon VerticalAlignment="Top" Icon="InformationOutline" Foreground="{StaticResource TangoGrayTextBrush}"></touch:TouchIcon>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ Help us improve your experience using this system.
+ </TextBlock>
+ </DockPanel>
+ </StackPanel>
+ <touch:TouchToggleSlider Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90" IsChecked="{Binding SynchronizeDiagnostics}"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 40 0 0">
+ <touch:TouchIcon VerticalAlignment="Top" Icon="InformationOutline" Foreground="{StaticResource TangoGrayTextBrush}"></touch:TouchIcon>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ Once enabled, synchronization occurs automatically in the background. you can choose to synchronize right now.
+ </TextBlock>
+ </DockPanel>
+ <touch:TouchButton Command="{Binding SynchronizeCommand}" IsEnabled="{Binding MachineDataSynchronizer.IsEnabled}" HorizontalAlignment="Left" Margin="25 10 0 0" Style="{StaticResource TangoHollowButton}" FontSize="{StaticResource TangoDefaultFontSize}" Padding="15 10" CornerRadius="22">Synchronize Now</touch:TouchButton>
+ </StackPanel>
+ </touch:TouchExpander>
+
+ <!--DATE & TIME-->
+ <touch:TouchExpander Margin="0 20 0 0" Header="Date &amp; Time" IsExpanded="True" FontSize="{StaticResource TangoExpanderHeaderFontSize}" Visibility="{Binding ApplicationManager.IsInTechnicianMode,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <StackPanel Margin="10 30 10 10">
+
+ <DockPanel TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <StackPanel>
+ <TextBlock VerticalAlignment="Center">Time Zone</TextBlock>
+ <touch:TouchComboBox Margin="0 10 0 0" ItemsSource="{Binding TimeZones}" SelectedItem="{Binding SelectedTimeZone,Mode=TwoWay}">
+
+ </touch:TouchComboBox>
+ </StackPanel>
+ </DockPanel>
+ </StackPanel>
+ </touch:TouchExpander>
+
+ <!--TECHNICIAN-->
+ <touch:TouchExpander Visibility="{Binding ApplicationManager.IsInTechnicianMode,Converter={StaticResource BooleanToVisibilityConverter}}" Margin="0 20 0 0" Header="Advanced" IsExpanded="True" FontSize="{StaticResource TangoExpanderHeaderFontSize}">
+ <StackPanel Margin="10 30 10 10">
+
+ <DockPanel TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Embedded COM Port</TextBlock>
+ <touch:TouchTextBox KeyboardContainer="{Binding ElementName=Container}" Text="{Binding Settings.EmbeddedComPort}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Emergency COM Port</TextBlock>
+ <touch:TouchTextBox KeyboardContainer="{Binding ElementName=Container}" Text="{Binding Settings.EmergencyComPort}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable Emergency Screen</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableEmergencyNotifications}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable Embedded Debug Logs</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableEmbeddedDebugLogs}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable Automatic Thread Loading Support</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableAutomaticThreadLoading}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Display PowerUp Screen</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.DisplayPowerUpScreen}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable Job Liquid Quantity Validation</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableJobLiquidQuantityValidation}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Always Start in Technician Mode</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableTechnicianModeByDefault}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable External Bridge SignalR</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.EnableExternalBridgeSignalR}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Auto Update Check Interval Minutes</TextBlock>
+ <touch:TouchNumericTextBox Minimum="1" Maximum="120" KeyboardContainer="{Binding ElementName=Container}" Value="{Binding Settings.AutoUpdateCheckInterval,Converter={StaticResource TimeSpanToMinutesConverter}}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchNumericTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Bypass Internet Connectivity Checks</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.BypassInternetConnectivityCheck}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Gradient Resolution CM</TextBlock>
+ <touch:TouchNumericTextBox Minimum="10" Maximum="500" KeyboardContainer="{Binding ElementName=Container}" Value="{Binding Settings.GradientGenerationResolution}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchNumericTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable Insights</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding Settings.InsightsEnabled}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Insights Sampling Interval (sec)</TextBlock>
+ <touch:TouchNumericTextBox Minimum="1" Maximum="300" KeyboardContainer="{Binding ElementName=Container}" Value="{Binding Settings.InsightsSamplingInterval,Converter={StaticResource TimeSpanToSecondsConverter}}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchNumericTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Insights Storage Cleanup Interval (min)</TextBlock>
+ <touch:TouchNumericTextBox Minimum="1" Maximum="120" KeyboardContainer="{Binding ElementName=Container}" Value="{Binding Settings.InsightsStorageCleanupInterval,Converter={StaticResource TimeSpanToMinutesConverter}}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchNumericTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Insights Max Storage Duration (days)</TextBlock>
+ <touch:TouchNumericTextBox Minimum="1" Maximum="120" KeyboardContainer="{Binding ElementName=Container}" Value="{Binding Settings.InsightsMaxStorageDuration,Converter={StaticResource TimeSpanToDaysConverter}}" Margin="0 0 100 0" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="90"></touch:TouchNumericTextBox>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0" TextElement.FontSize="{StaticResource TangoDefaultFontSize}">
+ <TextBlock VerticalAlignment="Center">Enable UWF (Disk Protection)</TextBlock>
+ <touch:TouchToggleSlider IsChecked="{Binding EnableUWF}" Margin="0 0 100 0" DockPanel.Dock="Right" Style="{StaticResource TangoToggleButtonGrayAccent}" HorizontalAlignment="Right" Width="90"></touch:TouchToggleSlider>
+ </DockPanel>
+
+ <DockPanel Margin="0 20 0 0">
+ <touch:TouchIcon VerticalAlignment="Top" Icon="InformationOutline" Foreground="{StaticResource TangoGrayTextBrush}"></touch:TouchIcon>
+ <TextBlock Margin="10 0 0 0" VerticalAlignment="Top" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ Please restart the application for advanced settings to take effect.
+ </TextBlock>
+ </DockPanel>
+ </StackPanel>
+ </touch:TouchExpander>
</StackPanel>
</touch:LightTouchScrollViewer>
</Grid>
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 @@
+<Application x:Class="Tango.PPC.Maintenance.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <Application.Resources>
+ <ResourceDictionary>
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Resources/Merged.xaml" />
+ </ResourceDictionary.MergedDictionaries>
+ </ResourceDictionary>
+ </Application.Resources>
+</Application> \ 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<object>
+ {
+ 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<OpenCloseMotorCommand.MotorState>
+ {
+ 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<Object> States
+ {
+ get { return (ObservableCollection<Object>)GetValue(StatesProperty); }
+ set { SetValue(StatesProperty, value); }
+ }
+ public static readonly DependencyProperty StatesProperty =
+ DependencyProperty.Register("States", typeof(ObservableCollection<Object>), 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<object>();
+ }
+
+ 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<ButtonState>().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 @@
+<UserControl x:Class="Tango.PPC.Maintenance.Dialogs.CleanerDispensingView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Maintenance.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="600" Height="950" d:DataContext="{d:DesignInstance Type=local:CleanerDispensingViewVM, IsDesignTimeCreatable=False}">
+ <Grid>
+ <StackPanel Margin="0 50 0 0" HorizontalAlignment="Center">
+ <Image Source="../Images/head_cleaning.png" RenderOptions.BitmapScalingMode="Fant" Stretch="Uniform" Height="120"></Image>
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Margin="0 30 0 0">Dispense Cleaning Liquid</TextBlock>
+
+
+ <DockPanel Margin="20 40" HorizontalAlignment="Center">
+ <touch:TouchIcon Icon="Alert" Foreground="{StaticResource TangoErrorBrush}" />
+ <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Foreground="{StaticResource TangoErrorBrush}">Please put on safety glasses</TextBlock>
+ </DockPanel>
+
+ <Label Margin="20 10" HorizontalAlignment="Center">
+ <Label.Style>
+ <Style TargetType="Label">
+ <Setter Property="Content">
+ <Setter.Value>
+ <TextBlock LineHeight="30" TextWrapping="Wrap">
+ <Run>1. Pull the thread aside and clean with Q tip when the liquid is dispensed.</Run>
+ <LineBreak/>
+ <Run>2. Dispense again if the liquid isn't enough for cleaning.</Run>
+ <LineBreak/>
+ <Run>3. When cleaning is completed, return the thread back to the V-Groove and press the 'Close Dyeing Head Lid' button to close the head lid</Run>
+ </TextBlock>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding MachineProvider.Machine.MachineHeadType}" Value="Arc">
+ <Setter Property="Content">
+ <Setter.Value>
+ <TextBlock LineHeight="30" TextWrapping="Wrap">
+ <Run>1. Open the dyeing head lid, pull the thread aside and clean with Q tip when the liquid is dispensed.</Run>
+ <LineBreak/>
+ <Run>2. Dispense again if the liquid isn't enough for cleaning.</Run>
+ <LineBreak/>
+ <Run>3. When cleaning is completed, return the thread back to the V-Groove and install the head lid back.</Run>
+ </TextBlock>
+ </Setter.Value>
+ </Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Label.Style>
+ </Label>
+
+ <Grid>
+ <touch:TouchButton Command="{Binding StartCommand}" Margin="0 100 0 0" Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Center" Padding="80 15" CornerRadius="25">START</touch:TouchButton>
+ </Grid>
+
+ <StackPanel Margin="40 150 40 40">
+ <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Status}"></TextBlock>
+ <touch:TouchProgressBar Margin="0 5 0 0" VerticalAlignment="Bottom" Height="10" Minimum="0" Maximum="100" Value="0" IsIndeterminate="{Binding IsStarted}">
+
+ </touch:TouchProgressBar>
+ </StackPanel>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerUpView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Maintenance.Dialogs.HeadCleaningView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Maintenance.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="600" Height="800" d:DataContext="{d:DesignInstance Type=local:HeadCleaningViewVM, IsDesignTimeCreatable=False}">
+ <Grid>
+ <StackPanel Margin="0 50 0 0" HorizontalAlignment="Center">
+ <Image Source="../Images/head_cleaning.png" RenderOptions.BitmapScalingMode="Fant" Stretch="Uniform" Height="120"></Image>
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Margin="0 30 0 0">Head Cleaning</TextBlock>
+
+ <TextBlock Margin="20 10" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Press 'START' to start the head cleaning sequence"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsStarted}" Value="True">
+ <Setter Property="Text" Value="Head cleaning in progress"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsAborting}" Value="True">
+ <Setter Property="Text" Value="Aborting head cleaning"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsCompleted}" Value="True">
+ <Setter Property="Text" Value="Head cleaning completed"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
+
+ <Grid>
+ <touch:TouchButton Visibility="{Binding IsStarted,Converter={StaticResource BooleanToVisibilityInverseConverter}}" Command="{Binding StartCommand}" Margin="0 100 0 0" Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Center" Padding="80 15" CornerRadius="25">START</touch:TouchButton>
+ <touch:TouchButton Visibility="{Binding IsStarted,Converter={StaticResource BooleanToVisibilityConverter}}" IsEnabled="{Binding IsAborting,Converter={StaticResource BooleanInverseConverter}}" Command="{Binding AbortCommand}" Margin="0 100 0 0" Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Center" Padding="80 15" CornerRadius="25">ABORT</touch:TouchButton>
+ </Grid>
+
+ <StackPanel Margin="40">
+ <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Status.Status}"></TextBlock>
+ <touch:TouchProgressBar Margin="0 20 0 0" VerticalAlignment="Bottom" Width="500" Height="10" Minimum="0" Maximum="{Binding Status.Total}" Value="{Binding Status.Progress}">
+ <touch:TouchProgressBar.Style>
+ <Style TargetType="touch:TouchProgressBar" BasedOn="{StaticResource {x:Type touch:TouchProgressBar}}">
+ <Setter Property="IsIndeterminate" Value="False"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Status.Progress}" Value="0">
+ <Setter Property="IsIndeterminate" Value="True"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchProgressBar.Style>
+ </touch:TouchProgressBar>
+ </StackPanel>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerUpView.xaml
+ /// </summary>
+ 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<GuideStep> Steps { get; }
+
+ protected virtual List<GuideStep> GetStepsFromResource(String key)
+ {
+ List<GuideStep> list = new List<GuideStep>();
+
+ 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<GuideStep> _steps;
+ public override List<GuideStep> 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<GuideStep> _steps;
+ public override List<GuideStep> 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<GuideStep> _steps;
+ public override List<GuideStep> 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<GuideStep> _steps;
+ public override List<GuideStep> 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<GuideStep> _steps;
+ public override List<GuideStep> 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<GuideBase> CreateAllGuides()
+ {
+ var resource = new ResourceDictionary
+ {
+ Source = new Uri("/Tango.PPC.Maintenance;component/Resources/Guides.xaml", UriKind.RelativeOrAbsolute)
+ };
+
+ Application.Current.Resources.MergedDictionaries.Add(resource);
+
+ List<GuideBase> guides = new List<GuideBase>();
+
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-New-Thread.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Loading-an-Ink-Cartridge.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Air-Filter.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Replacing-the-Thread.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/Residue-Cartridges-A.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/handling-the-waste-cartridges.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-an-ink-cartridge.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/loading-new-thread.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/machine-image.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-air-filter.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Guides/replacing-the-thread.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/absent.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_error.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_empty_right.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/Waste/present_full_right.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/action.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cl-full.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-empty.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/cone-full.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/guides.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/head_cleaning.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/inks.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/l-full.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/lubricant2.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/maintenance.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/status.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-green.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-red.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/temperature-yellow.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Maintenance/Images/thread_loading.png
Binary files 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<T> : 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
+{
+ /// <summary>
+ /// Represents a PPC <see cref="MaintenanceModule"/>.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
+ [PPCModule(3)]
+ public class MaintenanceModule : PPCModuleBase
+ {
+ /// <summary>
+ /// Gets the module name.
+ /// </summary>
+ public override string Name
+ {
+ get
+ {
+ return "Maintenance";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module description.
+ /// </summary>
+ public override string Description
+ {
+ get
+ {
+ return "PPC maintenance module.";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module cover image.
+ /// </summary>
+ public override BitmapSource Image
+ {
+ get
+ {
+ return ResourceHelper.GetImageFromResources("Images/maintenance.png");
+ }
+ }
+
+ /// <summary>
+ /// Gets the module entry point view type.
+ /// </summary>
+ public override Type MainViewType
+ {
+ get
+ {
+ return typeof(MainView);
+ }
+ }
+
+ /// <summary>
+ /// Gets the permission required to see and load this module.
+ /// </summary>
+ public override Permissions Permission
+ {
+ get
+ {
+ return Permissions.RunPPC;
+ }
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.PPC.Maintenance.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // 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() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [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;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+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 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ 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 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:sys="clr-namespace:System;assembly=mscorlib"
+ xmlns:local="clr-namespace:Tango.PPC.Maintenance.Resources">
+
+ <x:Array x:Key="LoadNewThread" Type="sys:String">
+ <sys:String>1. Loading New Thread</sys:String>
+ <sys:String>2. Wait for a message indicating the system is ready to load the thread</sys:String>
+ <sys:String>3. Place a cone with un-dyed thread into the thread feeding unit</sys:String>
+ <sys:String>4. Feed the thread along the thread groove to the winder</sys:String>
+ <sys:String>5. Place an empty collecting cone into the thread winder</sys:String>
+ <sys:String>6. Insert the end of the thread into the empty collecting cone</sys:String>
+ <sys:String>7. On the TS-1800 panel, press LOAD again</sys:String>
+ </x:Array>
+
+ <x:Array x:Key="HandleWasteCartridge" Type="sys:String">
+ <sys:String>1. On the TS-1800 panel, press LOAD</sys:String>
+ <sys:String>2. Wait for a message indicating the system is ready to load the thread</sys:String>
+ <sys:String>3. Place a cone with un-dyed thread into the thread feeding unit</sys:String>
+ <sys:String>4. Feed the tread along the feeding path up to the top cover</sys:String>
+ <sys:String>5. Feed the thread along the thread groove to the winder</sys:String>
+ <sys:String>6. Place an empty collecting cone into the thread winder</sys:String>
+ <sys:String>7. Insert the end of the thread into the empty collecting cone</sys:String>
+ <sys:String>8. On the TS-1800 panel, press LOAD again</sys:String>
+ </x:Array>
+
+ <x:Array x:Key="ReplaceThread" Type="sys:String">
+ <sys:String>1. Cut the current thread just after the feeding cone</sys:String>
+ <sys:String>2. Remove the current feeding cone</sys:String>
+ <sys:String>3. Place the new feeding cone into the thread feeding unit</sys:String>
+ <sys:String>4. Tie the new thread to the current thread</sys:String>
+ <sys:String>5. Cut off the ends of the thread leaving a small knot</sys:String>
+ <sys:String>6. On the TS-1800 panel, press and hold the JOG button</sys:String>
+ <sys:String>7. Hold the JOG button until the knot appears at the collecting cone</sys:String>
+ <sys:String>8. Cut the thread at the collecting cone after the knot</sys:String>
+ <sys:String>9. Remove the collecting cone</sys:String>
+ <sys:String>10. Place an empty collecting cone into the winder</sys:String>
+ <sys:String>11. Insert the end of the new thread into the empty collecting cone</sys:String>
+ </x:Array>
+
+ <x:Array x:Key="ReplaceAirFilter" Type="sys:String">
+ <sys:String>1. Open the air filter cover</sys:String>
+ <sys:String>2. Remove the old air filter</sys:String>
+ <sys:String>3. Insert a new air filter</sys:String>
+ <sys:String>4. Close the air filter cover</sys:String>
+ </x:Array>
+
+ <x:Array x:Key="LoadInkCartridge" Type="sys:String">
+ <sys:String>1. Open the cartridge cover</sys:String>
+ <sys:String>2. Insert a full ink cartridge into the ink-loading slot</sys:String>
+ <sys:String>3. Close the cartridge cover</sys:String>
+ <sys:String>4. When ink loading is complete, open the cartridge cover</sys:String>
+ <sys:String>5. Remove the empty ink cartridge</sys:String>
+ <sys:String>6. Remove the stopper from the residue-filling opening</sys:String>
+ <sys:String>7. Place the stopper into its allocated position on the top side of the empty ink cartridge</sys:String>
+ <sys:String>8. Put the empty ink cartridge into storage. Optional: if an empty recycling slot is available</sys:String>
+ <sys:String>9. Insert the empty ink cartridge into the slot for ink recycling</sys:String>
+ </x:Array>
+
+</ResourceDictionary> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{011470AC-6BD6-4366-B5F2-C82C065D4A84}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.PPC.Maintenance</RootNamespace>
+ <AssemblyName>Tango.PPC.Maintenance</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ </Reference>
+ <Reference Include="FontAwesome.WPF, Version=4.7.0.37774, Culture=neutral, PublicKeyToken=0758b07a11a4f466, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Ionic.Zip.1.9.1.8\lib\Ionic.Zip.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\System.Reactive.Core.3.1.1\lib\net46\System.Reactive.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Interfaces, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Linq, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\System.Reactive.Linq.3.1.1\lib\net46\System.Reactive.Linq.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\CleanerDispensingView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\HeadCleaningView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Resources\Guides.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Themes\Generic.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\GeneralGuideView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\MaintenanceView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\MainView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Commands\HomingMotorCommand.cs" />
+ <Compile Include="Commands\OpenCloseDyeingHeadCommand.cs" />
+ <Compile Include="Commands\OpenCloseRightLeadingWheelsCommand.cs" />
+ <Compile Include="Commands\OpenCloseLeftLeadingWheelsCommand.cs" />
+ <Compile Include="Commands\OpenCloseMotorCommand.cs" />
+ <Compile Include="Commands\ResetThreadLoadingCommand.cs" />
+ <Compile Include="Controls\StateTouchButton.cs" />
+ <Compile Include="Converters\LiquidTypeToBrushConverter.cs" />
+ <Compile Include="Converters\LiquidTypeToShortNameConverter.cs" />
+ <Compile Include="Converters\MidTankLevelToElementHeightConverter.cs" />
+ <Compile Include="Converters\StringToFirstLetterConverter.cs" />
+ <Compile Include="Dialogs\CleanerDispensingView.xaml.cs">
+ <DependentUpon>CleanerDispensingView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\HeadCleaningView.xaml.cs">
+ <DependentUpon>HeadCleaningView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\CleanerDispensingViewVM.cs" />
+ <Compile Include="Dialogs\HeadCleaningViewVM.cs" />
+ <Compile Include="GuideBase.cs" />
+ <Compile Include="GuideStep.cs" />
+ <Compile Include="Guides\LoadInkCartridgeGuide.cs" />
+ <Compile Include="Guides\ReplaceAirFilterGuide.cs" />
+ <Compile Include="Guides\ReplaceThreadGuide.cs" />
+ <Compile Include="Guides\HandleWasteCartridgeGuide.cs" />
+ <Compile Include="Guides\LoadNewThreadGuide.cs" />
+ <Compile Include="Helpers\GuideHelper.cs" />
+ <Compile Include="MaintenanceCommand.cs" />
+ <Compile Include="MaintenanceModule.cs" />
+ <Compile Include="Models\MidTankLevelModel.cs" />
+ <Compile Include="Models\OverallTemperatureModel.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="ViewModelLocator.cs" />
+ <Compile Include="ViewModels\GeneralGuideViewVM.cs" />
+ <Compile Include="ViewModels\MaintenanceViewVM.cs" />
+ <Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="Views\GeneralGuideView.xaml.cs">
+ <DependentUpon>GeneralGuideView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\MaintenanceView.xaml.cs">
+ <DependentUpon>MaintenanceView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\MainView.xaml.cs">
+ <DependentUpon>MainView.xaml</DependentUpon>
+ </Compile>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="app.config">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.DragAndDrop\Tango.DragAndDrop.csproj">
+ <Project>{b112d89a-a106-41ae-a0c1-4abc84c477f5}</Project>
+ <Name>Tango.DragAndDrop</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Explorer\Tango.Explorer.csproj">
+ <Project>{4399af76-db52-4cfb-8020-6f85bdb29fd5}</Project>
+ <Name>Tango.Explorer</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj">
+ <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
+ <Name>Tango.Integration</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Settings\Tango.Settings.csproj">
+ <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project>
+ <Name>Tango.Settings</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj">
+ <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project>
+ <Name>Tango.SharedUI</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Touch\Tango.Touch.csproj">
+ <Project>{fd86424c-6e84-491b-8df9-3d0f5c236a2a}</Project>
+ <Name>Tango.Touch</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Tango.PPC.Storage\Tango.PPC.Storage.csproj">
+ <Project>{04febb02-f782-4b96-b47d-f6902afa43be}</Project>
+ <Name>Tango.PPC.Storage</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\maintenance.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\action.png" />
+ <Resource Include="Images\guides.png" />
+ <Resource Include="Images\status.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\temperature-green.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\inks.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\loading-new-thread.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\machine-image.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\handling-the-waste-cartridges.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\loading-an-ink-cartridge.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\replacing-the-air-filter.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\replacing-the-thread.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\Loading-an-Ink-Cartridge.gif" />
+ <Resource Include="Images\Guides\Residue-Cartridges-A.gif" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\Replacing-the-Air-Filter.gif" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Guides\Loading-New-Thread.gif" />
+ <Resource Include="Images\Guides\Replacing-the-Thread.gif" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\temperature-red.png" />
+ <Resource Include="Images\temperature-yellow.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\lubricant2.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\cl-full.png" />
+ <Resource Include="Images\l-full.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\head_cleaning.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\cone-empty.png" />
+ <Resource Include="Images\cone-full.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Waste\present_empty_error.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Waste\absent.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\Waste\present_empty_right.png" />
+ <Resource Include="Images\Waste\present_full_right.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\thread_loading.png" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ 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 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:local="clr-namespace:Tango.PPC.Maintenance.Controls">
+
+ <Style TargetType="{x:Type local:StateTouchButton}" BasedOn="{StaticResource {x:Type touch:TouchButton}}">
+
+ </Style>
+</ResourceDictionary> \ 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
+ {
+ /// <summary>
+ /// Initializes a new instance of the ViewModelLocator class.
+ /// </summary>
+ static ViewModelLocator()
+ {
+ TangoIOC.Default.Register<MainViewVM>();
+ TangoIOC.Default.Register<MaintenanceViewVM>();
+ TangoIOC.Default.Register<GeneralGuideViewVM>();
+ }
+
+ /// <summary>
+ /// Gets the main view VM.
+ /// </summary>
+ public static MainViewVM MainViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<MainViewVM>();
+ }
+ }
+
+ /// <summary>
+ /// Gets the maintenance view VM.
+ /// </summary>
+ public static MaintenanceViewVM MaintenanceViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<MaintenanceViewVM>();
+ }
+ }
+
+ /// <summary>
+ /// Gets the general guide view VM.
+ /// </summary>
+ public static GeneralGuideViewVM GeneralGuideViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<GeneralGuideViewVM>();
+ }
+ }
+ }
+}
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<GuideBase>
+ {
+ 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
+{
+ /// <summary>
+ /// Represents the main view VM and entry point for <see cref="Synchronization.MyModule"/>.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.PPCViewModel" />
+ public class MainViewVM : PPCViewModel
+ {
+ /// <summary>
+ /// Called when the application has been started
+ /// </summary>
+ public override void OnApplicationStarted()
+ {
+ //Start initializing here rather then in the constructor.
+ }
+
+ public override void OnNavigatedTo()
+ {
+ base.OnNavigatedTo();
+ NavigationManager.NavigateTo<MaintenanceModule>(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<GuideBase> Guides { get; set; }
+
+ public RelayCommand<GuideBase> OpenGuideCommand { get; set; }
+
+ private List<MidTankLevelModel> _midTankLevels;
+ public List<MidTankLevelModel> 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<WasteStateModel> _wasteStates;
+ public List<WasteStateModel> 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<GuideBase>(GuideHelper.CreateAllGuides());
+ OverallTemperature = new OverallTemperatureModel();
+
+ OpenGuideCommand = new RelayCommand<GuideBase>(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<WasteStateModel>()
+ {
+ 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<BL.Entities.MachinesEvent> 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<MaintenanceModule, GeneralGuideView, GuideBase>(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<StorageModule,
+ Storage.Views.MainView, ExplorerFileItem,
+ Storage.Models.StorageNavigationRequest>(
+ 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<HeadCleaningViewVM>();
+ }
+
+ private void StartThreadLoadingWizard()
+ {
+ ThreadLoadingService.StartThreadLoadingWizard();
+ }
+
+ private void StartThreadBreakWizard()
+ {
+ ThreadLoadingService.StartThreadBreakWizard();
+ }
+
+ private async void DispenseCleanerLiquid()
+ {
+ await NotificationProvider.ShowDialog<CleanerDispensingViewVM>();
+ }
+ }
+}
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 @@
+<UserControl x:Class="Tango.PPC.Maintenance.Views.GeneralGuideView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Maintenance.Views"
+ xmlns:vm="clr-namespace:Tango.PPC.Maintenance.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.Maintenance"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:GeneralGuideViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.GeneralGuideViewVM}">
+ <Grid>
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <StackPanel Orientation="Horizontal" Margin="20">
+ <Image Source="{Binding Guide.Icon}" Stretch="None" VerticalAlignment="Center" />
+ <TextBlock Margin="20 0 0 0" VerticalAlignment="Center" FontSize="23" Text="{Binding Guide.Name}"></TextBlock>
+ </StackPanel>
+
+ <Grid Grid.Row="1" Margin="10">
+ <touch:TouchDropShadowBorder Padding="20" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding Guide.Steps}" AlternationCount="2">
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Border x:Name="FooBar" Padding="20 5">
+ <DockPanel>
+ <touch:TouchCheckBox Width="50" Padding="5 0 0 0" Height="50" DockPanel.Dock="Right" IsChecked="{Binding IsChecked,Mode=TwoWay}" />
+ <TextBlock VerticalAlignment="Center" FontSize="16" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Text}"></TextBlock>
+ </DockPanel>
+ </Border>
+ <DataTemplate.Triggers>
+ <Trigger Property="ItemsControl.AlternationIndex" Value="0">
+ <Setter Property="Background" Value="#f9f8f8" TargetName="FooBar"/>
+ </Trigger>
+ <Trigger Property="ItemsControl.AlternationIndex" Value="1">
+ <Setter Property="Background" Value="{StaticResource TangoPrimaryBackgroundBrush}" TargetName="FooBar"/>
+ </Trigger>
+ </DataTemplate.Triggers>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+
+ </ItemsControl>
+
+ <touch:TouchGifAnimation Margin="0 20 0 0" HorizontalAlignment="Left" VerticalAlignment="Bottom" EnableAnimation="{Binding IsVisible}" Source="{Binding Guide.Image}" Stretch="Uniform"></touch:TouchGifAnimation>
+ </DockPanel>
+ </touch:TouchDropShadowBorder>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for GeneralGuideView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Maintenance.Views.MainView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.Maintenance.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.Maintenance"
+ xmlns:views="clr-namespace:Tango.PPC.Maintenance.Views"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:local="clr-namespace:Tango.PPC.Maintenance.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}">
+
+ <Grid>
+ <controls:NavigationControl TransitionType="Slide" TransitionDuration="00:00:0.2" KeepElementsAttached="True">
+ <views:MaintenanceView/>
+ <views:GeneralGuideView/>
+ </controls:NavigationControl>
+ </Grid>
+
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Maintenance.Views.MaintenanceView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.Maintenance.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.Maintenance"
+ xmlns:ifs="clr-namespace:Tango.PMR.IFS;assembly=Tango.PMR"
+ xmlns:arr="clr-namespace:System.Collections;assembly=mscorlib"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:localConverters="clr-namespace:Tango.PPC.Maintenance.Converters"
+ xmlns:localControls="clr-namespace:Tango.PPC.Maintenance.Controls"
+ xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL"
+ xmlns:local="clr-namespace:Tango.PPC.Maintenance.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1800" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MaintenanceViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MaintenanceViewVM}">
+
+ <UserControl.Resources>
+
+ <localConverters:StringToFirstLetterConverter x:Key="StringToFirstLetterConverter" />
+ <localConverters:MidTankLevelToElementHeightConverter x:Key="MidTankLevelToElementHeightConverter" />
+ <localConverters:LiquidTypeToBrushConverter x:Key="LiquidTypeToBrushConverter" />
+ <localConverters:LiquidTypeToShortNameConverter x:Key="LiquidTypeToShortNameConverter"/>
+
+ <Style TargetType="FrameworkElement" x:Key="Level1Container">
+ <Setter Property="Margin" Value="20 15 60 15"></Setter>
+ </Style>
+ <Style TargetType="FrameworkElement" x:Key="Level2Container">
+ <Setter Property="Margin" Value="80 30 60 0"></Setter>
+ </Style>
+ <Style TargetType="FrameworkElement" x:Key="Level2ContainerExtraMargin">
+ <Setter Property="Margin" Value="80 40 60 0"></Setter>
+ </Style>
+
+ <DataTemplate x:Key="LiquidBox">
+ <DockPanel>
+ <TextBlock DockPanel.Dock="Top" Text="{Binding IDSPack.LiquidType,Converter={StaticResource LiquidTypeToShortNameConverter}}" HorizontalAlignment="Center"></TextBlock>
+ <Grid MaxWidth="20" Margin="1 0">
+ <touch:TouchIcon Icon="MapMarkerSolid" Width="20" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10" Foreground ="{Binding Path=IDSPack.LiquidType, Converter={StaticResource LiquidTypeToBrushConverter}}">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Visibility" Value="Hidden"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsLow}" Value="True">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsEmpty}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard Name="blinkDrop">
+ <Storyboard>
+ <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Duration="00:00:01" RepeatBehavior="Forever">
+ <DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="1" />
+ <DiscreteDoubleKeyFrame KeyTime="00:00:0.5" Value="0" />
+ </DoubleAnimationUsingKeyFrames>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <RemoveStoryboard BeginStoryboardName="blinkDrop" />
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ <Border BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}" CornerRadius="3" ClipToBounds="True" x:Name="pathBorder">
+ <Canvas Width="30" >
+ <Path Panel.ZIndex="1" VerticalAlignment="Bottom" ClipToBounds="True" MinHeight="2" Data="M0,0 C2,0 8.9,-1.1705073 11.3,-4.6 14.5,-7.7 15.5,-8 18.7,-10.8 21.7,-13.16 23.3,-14.5 28,-15.6 28,-13.7 28,80 28,100 L0,100 z" Height="90" Width="29" Stretch="Fill"
+ Canvas.Left="0" Fill="{Binding Path=IDSPack.LiquidType, Converter={StaticResource LiquidTypeToBrushConverter}}" Margin="0 -14 0 0" >
+
+ <Path.Style>
+ <Style>
+ <Setter Property="Canvas.Top" >
+ <Setter.Value>
+ <MultiBinding Converter="{StaticResource MidTankLevelToElementHeightConverter}">
+ <Binding ElementName="pathBorder" Path="ActualHeight" />
+ <Binding Path="Level" />
+ </MultiBinding>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </Path.Style>
+ </Path>
+ </Canvas>
+ </Border>
+ </Grid>
+ </DockPanel>
+ </DataTemplate>
+ </UserControl.Resources>
+
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}" IsEnabled="{Binding IsFree}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Border Padding="20" Background="{StaticResource TangoPrimaryBackgroundBrush}" BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}">
+ <Border.Effect>
+ <DropShadowEffect Color="Silver" ShadowDepth="0" BlurRadius="20" Opacity="1" />
+ </Border.Effect>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Maintenance</TextBlock>
+ </Border>
+
+ <Grid Grid.Row="1">
+ <touch:LightTouchScrollViewer>
+ <StackPanel Margin="10 60 10 0">
+
+ <!--STATUS-->
+ <touch:TouchDropShadowBorder Padding="0 0 0 50">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <Image Source="../Images/status.png" />
+ <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Current Status</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="20 40 40 0">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="180" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="180" />
+ <ColumnDefinition Width="100" />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="100" />
+ <RowDefinition Height="28" />
+ </Grid.RowDefinitions>
+
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
+ <Image Stretch="None">
+ <Image.Style>
+ <Style TargetType="Image">
+ <Setter Property="Source" Value="../Images/temperature-green.png"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding OverallTemperature.IsWarning}" Value="True">
+ <Setter Property="Source" Value="../Images/temperature-yellow.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding OverallTemperature.IsError}" Value="True">
+ <Setter Property="Source" Value="../Images/temperature-red.png"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Image.Style>
+ </Image>
+ <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ <Run Text="{Binding OverallTemperature.Temperature,StringFormat='0',Mode=OneWay}"></Run>
+ <Run>º</Run>
+ </TextBlock>
+ </StackPanel>
+
+ <Grid Grid.Column="1" Margin="0 0 0 10">
+ <ItemsControl ItemsSource="{Binding MidTankLevels}" ItemTemplate="{StaticResource LiquidBox}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <UniformGrid Rows="1" IsItemsHost="True"></UniformGrid>
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ </ItemsControl>
+ </Grid>
+
+ <Image Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="15" RenderOptions.BitmapScalingMode="Fant">
+ <Image.Style>
+ <Style TargetType="Image">
+ <Setter Property="Source" Value="../Images/cone-empty.png"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding SpoolState}" Value="Present">
+ <Setter Property="Source" Value="../Images/cone-full.png"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Image.Style>
+ </Image>
+
+ <Grid Grid.Column="3">
+ <ItemsControl ItemsSource="{Binding WasteStates}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <UniformGrid Columns="2" />
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Image Stretch="None" HorizontalAlignment="Right">
+ <Image.Style>
+ <Style TargetType="Image">
+ <Setter Property="Source" Value="../Images/Waste/absent.png"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Absent}">
+ <Setter Property="Source" Value="../Images/Waste/absent.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Present}">
+ <Setter Property="Source" Value="../Images/Waste/present_empty_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Empty}">
+ <Setter Property="Source" Value="../Images/Waste/present_empty_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Full}">
+ <Setter Property="Source" Value="../Images/Waste/present_full_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Emptying}">
+ <Setter Property="Source" Value="../Images/Waste/present_full_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Inserted}">
+ <Setter Property="Source" Value="../Images/Waste/present_empty_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.EmptyingCompleted}">
+ <Setter Property="Source" Value="../Images/Waste/present_empty_right.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="{x:Static ifs:CartridgeState.Error}">
+ <Setter Property="Source" Value="../Images/Waste/present_empty_error.png"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Image.Style>
+ </Image>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </Grid>
+
+ <TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Temperature</TextBlock>
+ <TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Inks</TextBlock>
+ <TextBlock Grid.Column="2" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Collecting Cone</TextBlock>
+ <TextBlock Margin="20 0 0 0" Grid.Column="3" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Waste</TextBlock>
+ </Grid>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <!--ACTIONS-->
+ <touch:TouchDropShadowBorder Margin="0 20 0 0" Padding="0 0 0 50" MinHeight="330">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <Image Source="../Images/action.png" />
+ <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Actions</TextBlock>
+ </StackPanel>
+
+ <StackPanel Style="{StaticResource Level2ContainerExtraMargin}">
+ <UniformGrid Columns="2" Margin="0 0">
+
+ <localControls:StateTouchButton Command="{Binding OpenCloseLeftLeadingWheelsCommand.Command}" SelectedState="{Binding OpenCloseLeftLeadingWheelsCommand.State}" Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}">
+ <localControls:ButtonState Value="Closed" Content="OPEN LEFT LEADING WHEELS" />
+ <localControls:ButtonState Value="Opened" Content="CLOSE LEFT LEADING WHEELS" />
+ </localControls:StateTouchButton>
+
+ <localControls:StateTouchButton Command="{Binding OpenCloseRightLeadingWheelsCommand.Command}" SelectedState="{Binding OpenCloseRightLeadingWheelsCommand.State}" Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}">
+ <localControls:ButtonState Value="Closed" Content="OPEN RIGHT LEADING WHEELS" />
+ <localControls:ButtonState Value="Opened" Content="CLOSE RIGHT LEADING WHEELS" />
+ </localControls:StateTouchButton>
+
+ <localControls:StateTouchButton Command="{Binding OpenCloseDyeingHeadCommand.Command}" SelectedState="{Binding OpenCloseDyeingHeadCommand.State}" Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Visibility="{Binding MachineProvider.Machine.MachineHeadType,Converter={StaticResource IsToStringEqualToVisibilityConverter},ConverterParameter='Flat'}">
+ <localControls:ButtonState Value="Closed" Content="OPEN DYEING HEAD LID" />
+ <localControls:ButtonState Value="Opened" Content="CLOSE DYEING HEAD LID" />
+ </localControls:StateTouchButton>
+
+ <touch:TouchButton Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding HeadCleaningCommand}">RUN HEAD CLEANING</touch:TouchButton>
+
+ <touch:TouchButton Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding DispenseCleanerLiquidCommand}">DISPENSE CLEANING LIQUID</touch:TouchButton>
+
+ <touch:TouchButton Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding ExportLogsCommand}" Visibility="{Binding ApplicationManager.IsInTechnicianMode,Converter={StaticResource BooleanToVisibilityConverter}}">EXPORT SYSTEM LOGS</touch:TouchButton>
+ </UniformGrid>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <!--THREAD LOADING-->
+ <touch:TouchDropShadowBorder Margin="0 20 0 0" Padding="0 0 0 50" MinHeight="330">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <Image Source="../Images/thread_loading.png" Width="48" RenderOptions.BitmapScalingMode="Fant" />
+ <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Thread Loading</TextBlock>
+ </StackPanel>
+
+ <StackPanel Style="{StaticResource Level2ContainerExtraMargin}">
+ <UniformGrid Columns="1" Margin="0 0" HorizontalAlignment="Left">
+ <StackPanel Margin="20">
+ <touch:TouchButton Width="280" HorizontalAlignment="Left" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding StartThreadBreakCommand}">THREAD BREAK WIZARD</touch:TouchButton>
+ <DockPanel Margin="15 10 0 0" TextElement.Foreground="{StaticResource TangoGrayTextBrush}" HorizontalAlignment="Left">
+ <touch:TouchIcon Icon="InformationOutline" Width="14" Height="18" VerticalAlignment="Center" />
+ <TextBlock Margin="5 0 0 0" FontSize="{StaticResource TangoSmallFontSize}">This wizard will help you resolve thread breaking issues</TextBlock>
+ </DockPanel>
+ </StackPanel>
+
+ <StackPanel Margin="20">
+ <touch:TouchButton Width="280" HorizontalAlignment="Left" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding StartThreadLoadingCommand}">THREAD LOADING WIZARD</touch:TouchButton>
+ <DockPanel Margin="15 10 0 0" TextElement.Foreground="{StaticResource TangoGrayTextBrush}" HorizontalAlignment="Left">
+ <touch:TouchIcon Icon="InformationOutline" Width="14" Height="18" VerticalAlignment="Center" />
+ <TextBlock Margin="5 0 0 0" FontSize="{StaticResource TangoSmallFontSize}">This wizard will help you load a new thread in to the system</TextBlock>
+ </DockPanel>
+ </StackPanel>
+
+ <touch:TouchButton Width="280" HorizontalAlignment="Left" Margin="20" CornerRadius="25" Height="50" FontSize="18" Style="{StaticResource TangoHollowButton}" Command="{Binding ResetThreadLoadingCommand.Command}">RESET THREAD LOADING</touch:TouchButton>
+ </UniformGrid>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <!--GUIDES-->
+ <touch:TouchDropShadowBorder Margin="0 20 0 0" Padding="0 0 0 50">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Style="{StaticResource Level1Container}">
+ <Image Source="../Images/guides.png" />
+ <TextBlock FontWeight="Medium" Margin="20 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Guides</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="65 10 0 0">
+ <ItemsControl ItemsSource="{Binding Guides}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <UniformGrid Columns="2" IsItemsHost="True" />
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <touch:TouchButton Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenGuideCommand}" CommandParameter="{Binding}" Padding="20" FontSize="{StaticResource TangoTitleFontSize}" Style="{StaticResource TangoLinkButton}" HorizontalAlignment="Left">
+ <TextBlock Text="{Binding Name}"></TextBlock>
+ </touch:TouchButton>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchDropShadowBorder>
+
+ <!--JOB RUNS-->
+ <StackPanel Margin="0 20 0 20" TextElement.FontSize="{StaticResource TangoTitleFontSize}" TextElement.Foreground="{StaticResource TangoGrayTextBrush}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
+ <TextBlock FontWeight="SemiBold">Total Dyeing Time:</TextBlock>
+ <TextBlock Margin="10 0 0 0" Text="{Binding TotalDyeTime,Mode=OneWay,FallbackValue=0}"></TextBlock>
+ </StackPanel>
+
+ <StackPanel Orientation="Horizontal" Margin="0 10 0 0" HorizontalAlignment="Center">
+ <TextBlock FontWeight="SemiBold">Total Dyed Length:</TextBlock>
+ <TextBlock Margin="10 0 0 0" Text="{Binding TotalDyeMeters,Mode=OneWay,FallbackValue=0}"></TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </StackPanel>
+ </touch:LightTouchScrollViewer>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for MainView.xaml
+ /// </summary>
+ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <configSections>
+ <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
+ </configSections>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
+ <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+ <entityFramework>
+ <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
+ <providers>
+ <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
+ </providers>
+ </entityFramework>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="EntityFramework" version="6.2.0" targetFramework="net461" />
+ <package id="Expression.Blend.Sdk" version="1.0.2" targetFramework="net46" />
+ <package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net46" />
+ <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" />
+ <package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" />
+ <package id="System.Reactive.Core" version="3.1.1" targetFramework="net461" />
+ <package id="System.Reactive.Interfaces" version="3.1.1" targetFramework="net461" />
+ <package id="System.Reactive.Linq" version="3.1.1" targetFramework="net461" />
+</packages> \ 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 <see cref="StorageModule"/>.
/// </summary>
/// <seealso cref="Tango.PPC.Common.PPCModuleBase" />
- [PPCModule(3)]
+ [PPCModule(5)]
public class StorageModule : PPCModuleBase
{
/// <summary>
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<ExplorerFileItem> FileSelectedCommand { get; set; }
+ public ObservableCollection<ExplorerFileItem> SelectedItems { get; set; }
+
public RelayCommand SaveCommand { get; set; }
+ public RelayCommand OpenCommand { get; set; }
+
public MainViewVM()
{
+ SelectedItems = new ObservableCollection<ExplorerFileItem>();
FileSelectedCommand = new RelayCommand<ExplorerFileItem>(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 };
}
/// <summary>
@@ -158,7 +175,6 @@ namespace Tango.PPC.Storage.ViewModels
{
if (_allow_exit || CurrentPath == StorageProvider.Drive.RootDirectory.FullName)
{
- Request = null;
return Task.FromResult(true);
}
else
@@ -170,9 +186,17 @@ namespace Tango.PPC.Storage.ViewModels
private async void OnFileSelected(ExplorerFileItem fileItem)
{
+ _selectedItem = fileItem;
+ _allow_exit = true;
+ await NavigationManager.NavigateBack();
+ StorageProvider.SubmitFileSelection(new List<ExplorerFileItem>() { 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 @@
<UserControl.InputBindings>
<KeyBinding Key="Return" Command="{Binding SaveCommand}"></KeyBinding>
</UserControl.InputBindings>
-
+
<Grid>
<Grid Background="{StaticResource TangoMidBackgroundBrush}">
<Grid.RowDefinitions>
@@ -32,31 +32,89 @@
</Border>
<Grid Margin="10" Grid.Row="1">
<DockPanel>
-
- <Grid DockPanel.Dock="Top" Visibility="{Binding Request.Intent,Converter={StaticResource EnumToVisibilityConverter},ConverterParameter=SaveFile}">
+ <Grid DockPanel.Dock="Top">
+ <Grid.Style>
+ <Style TargetType="Grid">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <MultiDataTrigger>
+ <MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding Request.Intent}" Value="LoadFiles" />
+ <Condition Binding="{Binding ElementName=explorer,Path=IsMultiSelecting}" Value="True" />
+ </MultiDataTrigger.Conditions>
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </MultiDataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Grid.Style>
+ <Border BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}" Padding="20">
+ <StackPanel>
+ <DockPanel Margin="0 0 0 0">
+ <touch:TouchButton Command="{Binding OpenCommand}" Margin="20 0 0 0" Height="55" Width="200" Style="{StaticResource TangoHollowButton}" CornerRadius="25" DockPanel.Dock="Right">
+ <touch:TouchButton.Content>
+ OPEN
+ </touch:TouchButton.Content>
+ </touch:TouchButton>
+ <Grid>
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}">
+ <Run Text="{Binding SelectedItems.Count,Mode=OneWay}"></Run>
+ <Run>files selected</Run>
+ </TextBlock>
+ </Grid>
+ </DockPanel>
+ </StackPanel>
+ </Border>
+ </Grid>
+
+ <Grid DockPanel.Dock="Top">
+ <Grid.Style>
+ <Style TargetType="Grid">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Request.Intent}" Value="SaveFile">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Request.Intent}" Value="SaveFiles">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Grid.Style>
<Border BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}" Padding="20">
<StackPanel>
<TextBlock Text="{Binding Request.Title}" FontSize="{StaticResource TangoHeaderFontSize}"></TextBlock>
<DockPanel Margin="0 10 0 0">
- <touch:TouchButton Command="{Binding SaveCommand}" Margin="20 0 0 0" Height="50" Width="200" Style="{StaticResource TangoHollowButton}" CornerRadius="0" DockPanel.Dock="Right">
+ <touch:TouchButton Command="{Binding SaveCommand}" Margin="20 0 0 0" Height="55" Width="200" Style="{StaticResource TangoHollowButton}" CornerRadius="25" DockPanel.Dock="Right">
<touch:TouchButton.Content>
SAVE
</touch:TouchButton.Content>
</touch:TouchButton>
- <touch:TouchTextBox x:Name="txtFileName" KeyboardAction="Go" FocusSelectionMode="SelectAll" VerticalAlignment="Bottom" Text="{Binding FileName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
+ <Grid>
+ <touch:TouchTextBox x:Name="txtFileName" Visibility="{Binding Request.Intent,Converter={StaticResource EnumToVisibilityConverter},ConverterParameter=SaveFile}" KeyboardAction="Go" FocusSelectionMode="SelectAll" VerticalAlignment="Bottom" Text="{Binding FileName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
+ <TextBlock VerticalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Visibility="{Binding Request.Intent,Converter={StaticResource EnumToVisibilityConverter},ConverterParameter=SaveFiles}">Select destination folder</TextBlock>
+ </Grid>
</DockPanel>
</StackPanel>
</Border>
</Grid>
- <explorer:ExplorerControl x:Name="explorer" CurrentPath="{Binding CurrentPath,Mode=TwoWay}" FileSelectedCommand="{Binding FileSelectedCommand}" Filter="{Binding Request.Filter}">
+ <explorer:ExplorerControl x:Name="explorer" CurrentPath="{Binding CurrentPath,Mode=TwoWay}" SelectedItems="{Binding SelectedItems}" FileSelectedCommand="{Binding FileSelectedCommand}" Filter="{Binding Request.Filter}" Visibility="{Binding DisplayItems,Converter={StaticResource BooleanToVisibilityConverter}}">
<explorer:ExplorerControl.Style>
<Style TargetType="explorer:ExplorerControl" BasedOn="{StaticResource {x:Type explorer:ExplorerControl}}">
<Setter Property="EnableFileSelection" Value="True"></Setter>
+ <Setter Property="EnableMultiSelect" Value="False"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Request.Intent}" Value="SaveFile">
<Setter Property="EnableFileSelection" Value="False"></Setter>
</DataTrigger>
+ <DataTrigger Binding="{Binding Request.Intent}" Value="LoadFiles">
+ <Setter Property="EnableFileSelection" Value="True"></Setter>
+ <Setter Property="EnableMultiSelect" Value="True"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Request.Intent}" Value="LoadFile">
+ <Setter Property="EnableFileSelection" Value="True"></Setter>
+ <Setter Property="EnableMultiSelect" Value="False"></Setter>
+ </DataTrigger>
</Style.Triggers>
</Style>
</explorer:ExplorerControl.Style>
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 @@
+<UserControl x:Class="Tango.PPC.Technician.Dialogs.EmbeddedLogItemDetailsView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Technician.Dialogs"
+ xmlns:converters="clr-namespace:Tango.PPC.Technician.Converters"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" Width="560" Height="700" d:DataContext="{d:DesignInstance Type=local:EmbeddedLogItemDetailsViewVM, IsDesignTimeCreatable=False}">
+
+ <UserControl.Resources>
+ <converters:LogItemToStringConverter x:Key="LogItemToStringConverter" />
+ </UserControl.Resources>
+
+ <Grid Margin="5">
+ <Grid Grid.RowSpan="2">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="60"/>
+ <RowDefinition Height="31*"/>
+ <RowDefinition Height="60"/>
+ </Grid.RowDefinitions>
+
+ <StackPanel Orientation="Horizontal">
+ <touch:TouchIcon Width="42" Height="42" VerticalAlignment="Center">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="InformationOutline"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Log.Category}" Value="Warning">
+ <Setter Property="Icon" Value="ExclamationTriangleSolid"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Log.Category}" Value="Error">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Log.Category}" Value="Critical">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ <TextBlock VerticalAlignment="Center" Text="{Binding Log.Message}" TextWrapping="NoWrap" Height="22" TextTrimming="CharacterEllipsis" Width="500" Margin="10 0 0 0" FontSize="16"></TextBlock>
+ </StackPanel>
+
+ <Grid Grid.Row="1">
+ <DockPanel>
+ <Grid DockPanel.Dock="Top">
+ <controls:TableGrid RowHeight="30">
+ <TextBlock Text="Time Stamp:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.TimeStamp,Converter={StaticResource DateTimeUTCToStringConverter},ConverterParameter='MM/dd/yyyy HH:mm:ss.fff'}"></TextBlock>
+ <TextBlock Text="Category:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.Category}"></TextBlock>
+ <TextBlock Text="File:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.DebugLogResponse.FileName}"></TextBlock>
+ <TextBlock Text="Line:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.DebugLogResponse.LineNumber}"></TextBlock>
+ <TextBlock Text="Module:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.DebugLogResponse.ModuleId}"></TextBlock>
+ <TextBlock Text="Filter:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Log.DebugLogResponse.Filter}"></TextBlock>
+ </controls:TableGrid>
+ </Grid>
+
+ <Border Padding="5" BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}">
+ <TextBox BorderThickness="0" Text="{Binding Log,Converter={StaticResource LogItemToStringConverter}}" Style="{x:Null}" TextWrapping="Wrap" IsReadOnly="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" Background="Transparent" />
+ </Border>
+ </DockPanel>
+ </Grid>
+
+ <Grid Grid.Row="2">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Right" Width="170" VerticalAlignment="Bottom" CornerRadius="25" Height="50" Command="{Binding CloseCommand}">CLOSE</touch:TouchButton>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for LogItemDetailsView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Technician.Dialogs.SynchronizationDetailsView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Technician.Dialogs"
+ xmlns:converters="clr-namespace:Tango.PPC.Technician.Converters"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" Width="560" Height="700" d:DataContext="{d:DesignInstance Type=local:SynchronizationDetailsViewVM, IsDesignTimeCreatable=False}">
+
+ <Grid Margin="5">
+ <Grid Grid.RowSpan="2">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="60"/>
+ <RowDefinition Height="31*"/>
+ <RowDefinition Height="60"/>
+ </Grid.RowDefinitions>
+
+ <StackPanel Orientation="Horizontal" DataContext="{Binding Status}">
+ <touch:TouchIcon Width="42" Height="42" VerticalAlignment="Center">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Information"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding State}" Value="Pending">
+ <Setter Property="Icon" Value="Pause"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Synchronizing">
+ <Setter Property="Icon" Value="CloudSync"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Failed">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Completed">
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGreenBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ <TextBlock VerticalAlignment="Center" Text="{Binding Message}" TextWrapping="NoWrap" Height="22" TextTrimming="CharacterEllipsis" Width="500" Margin="10 0 0 0" FontSize="16"></TextBlock>
+ </StackPanel>
+
+ <Grid Grid.Row="1">
+ <DockPanel>
+ <Grid DockPanel.Dock="Top">
+ <controls:TableGrid RowHeight="30">
+ <TextBlock Text="Status:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Status.State,Converter={StaticResource EnumToDescriptionConverter}}"></TextBlock>
+ <TextBlock Text="Start Time:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Status.StartDateTime,Converter={StaticResource DateTimeUTCToStringConverter},ConverterParameter='MM/dd/yyyy HH:mm:ss'}"></TextBlock>
+ <TextBlock Text="Duration:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Status.Duration,StringFormat='hh\\:mm\\:ss\\.fff'}"></TextBlock>
+ </controls:TableGrid>
+ </Grid>
+
+ <Border Padding="5" BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}">
+ <TextBox BorderThickness="0" Text="{Binding Status.ErrorReason,TargetNullValue='No further Information available.'}" Style="{x:Null}" TextWrapping="Wrap" IsReadOnly="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" Background="Transparent" />
+ </Border>
+ </DockPanel>
+ </Grid>
+
+ <Grid Grid.Row="2">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Right" Width="170" VerticalAlignment="Bottom" CornerRadius="25" Height="50" Command="{Binding CloseCommand}">CLOSE</touch:TouchButton>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for LogItemDetailsView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Technician.Dialogs.UpdateDetailsView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Technician.Dialogs"
+ xmlns:converters="clr-namespace:Tango.PPC.Technician.Converters"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" Width="560" Height="700" d:DataContext="{d:DesignInstance Type=local:UpdateDetailsViewVM, IsDesignTimeCreatable=False}">
+
+ <Grid Margin="5">
+ <Grid Grid.RowSpan="2">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="60"/>
+ <RowDefinition Height="31*"/>
+ <RowDefinition Height="60"/>
+ </Grid.RowDefinitions>
+
+ <StackPanel Orientation="Horizontal" DataContext="{Binding Update}">
+ <touch:TouchIcon Width="42" Height="42" VerticalAlignment="Center">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Information"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsSetup}" Value="True">
+ <Setter Property="Icon" Value="Settings"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsUpdate}" Value="True">
+ <Setter Property="Icon" Value="CloudDownload"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsDataBase}" Value="True">
+ <Setter Property="Icon" Value="Database"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsSynchronization}" Value="True">
+ <Setter Property="Icon" Value="Sync"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsOfflineUpdate}" Value="True">
+ <Setter Property="Icon" Value="Sd"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsOfflineFirmwareUpgrade}" Value="True">
+ <Setter Property="Icon" Value="Chip"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsStarted}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsCompleted}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsFailed}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ <TextBlock VerticalAlignment="Center" Text="{Binding UpdateStatus,Converter={StaticResource EnumToDescriptionConverter}}" TextWrapping="NoWrap" Height="22" TextTrimming="CharacterEllipsis" Width="500" Margin="10 0 0 0" FontSize="16"></TextBlock>
+ </StackPanel>
+
+ <Grid Grid.Row="1">
+ <DockPanel>
+ <Grid DockPanel.Dock="Top">
+ <controls:TableGrid RowHeight="30">
+ <TextBlock Text="Started On:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Update.StartDate,Converter={StaticResource DateTimeUTCToStringConverter},ConverterParameter='MM/dd/yyyy HH:mm:ss'}"></TextBlock>
+ <TextBlock Text="Application:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Update.ApplicationVersion}"></TextBlock>
+ <TextBlock Text="Firmware:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Update.FirmwareVersion}"></TextBlock>
+ <TextBlock Text="Ended:" FontWeight="SemiBold" />
+ <TextBlock Text="{Binding Update.EndDate,TargetNullValue='Never',FallbackValue='Never',Converter={StaticResource DateTimeUTCToStringConverter},ConverterParameter='MM/dd/yyyy HH:mm:ss'}"></TextBlock>
+ </controls:TableGrid>
+ </Grid>
+
+ <Border Padding="5" BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}">
+ <TextBox BorderThickness="0" Text="{Binding Update.FailedLog,TargetNullValue='No further Information available.'}" Style="{x:Null}" TextWrapping="Wrap" IsReadOnly="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" Background="Transparent" />
+ </Border>
+ </DockPanel>
+ </Grid>
+
+ <Grid Grid.Row="2">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Right" Width="170" VerticalAlignment="Bottom" CornerRadius="25" Height="50" Command="{Binding CloseCommand}">CLOSE</touch:TouchButton>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for LogItemDetailsView.xaml
+ /// </summary>
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/browser.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/circuit-board.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/conveyor.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/exit.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/mobile-phone.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/packages.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/remote_connections.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/shutdown.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.Technician/Images/sync.png
Binary files 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 @@
</Compile>
<Compile Include="Converters\LogItemMessageToOneLineConverter.cs" />
<Compile Include="Converters\LogItemToStringConverter.cs" />
+ <Compile Include="Dialogs\EmbeddedLogItemDetailsView.xaml.cs">
+ <DependentUpon>EmbeddedLogItemDetailsView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\SynchronizationDetailsView.xaml.cs">
+ <DependentUpon>SynchronizationDetailsView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\UpdateDetailsView.xaml.cs">
+ <DependentUpon>UpdateDetailsView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Dialogs\LogItemDetailsView.xaml.cs">
<DependentUpon>LogItemDetailsView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Dialogs\EmbeddedLogItemDetailsViewVM.cs" />
+ <Compile Include="Dialogs\SynchronizationDetailsViewVM.cs" />
+ <Compile Include="Dialogs\UpdateDetailsViewVM.cs" />
<Compile Include="Dialogs\LogItemDetailsViewVM.cs" />
<Compile Include="Models\DispenserController.cs" />
<Compile Include="TechnicianModule.cs" />
@@ -93,10 +105,22 @@
<Compile Include="ViewModels\DispensersViewVM.cs" />
<Compile Include="ViewModels\LoggingViewVM.cs" />
<Compile Include="ViewModels\MainViewVM.cs" />
+ <Compile Include="ViewModels\PackagesViewVM.cs" />
+ <Compile Include="ViewModels\RemoteConnectionsViewVM.cs" />
+ <Compile Include="ViewModels\UpdatesViewVM.cs" />
<Compile Include="ViewModels\SystemViewVM.cs" />
<Compile Include="Views\CatalogView.xaml.cs">
<DependentUpon>CatalogView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Views\RemoteConnectionsView.xaml.cs">
+ <DependentUpon>RemoteConnectionsView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\UpdatesView.xaml.cs">
+ <DependentUpon>UpdatesView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\PackagesView.xaml.cs">
+ <DependentUpon>PackagesView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Views\DispensersView.xaml.cs">
<DependentUpon>DispensersView.xaml</DependentUpon>
</Compile>
@@ -161,6 +185,10 @@
<Project>{0BE74EEE-22CB-4DBA-B896-793B9E1A3AC0}</Project>
<Name>Tango.PPC.Common</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208C8BD8-72C6-4E3C-ACAA-351091A2ACC7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<Page Include="App.xaml">
@@ -171,6 +199,18 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Dialogs\EmbeddedLogItemDetailsView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\SynchronizationDetailsView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\UpdateDetailsView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Dialogs\LogItemDetailsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -179,6 +219,18 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Views\RemoteConnectionsView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Views\UpdatesView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\PackagesView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Views\DispensersView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -208,5 +260,24 @@
<ItemGroup>
<Resource Include="Images\dispensers.png" />
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\circuit-board.png" />
+ <Resource Include="Images\conveyor.png" />
+ <Resource Include="Images\exit.png" />
+ <Resource Include="Images\mobile-phone.png" />
+ <Resource Include="Images\shutdown.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\packages.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\sync.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\browser.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\remote_connections.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> \ 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<CatalogViewVM>();
TangoIOC.Default.Register<DispensersViewVM>();
TangoIOC.Default.Register<SystemViewVM>();
+ TangoIOC.Default.Register<PackagesViewVM>();
+ TangoIOC.Default.Register<UpdatesViewVM>();
+ TangoIOC.Default.Register<RemoteConnectionsViewVM>();
}
/// <summary>
@@ -76,5 +79,38 @@ namespace Tango.PPC.Technician
return TangoIOC.Default.GetInstance<SystemViewVM>();
}
}
+
+ /// <summary>
+ /// Gets the system view VM.
+ /// </summary>
+ public static PackagesViewVM PackagesViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<PackagesViewVM>();
+ }
+ }
+
+ /// <summary>
+ /// Gets the synchronization view vm.
+ /// </summary>
+ public static UpdatesViewVM UpdatesViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<UpdatesViewVM>();
+ }
+ }
+
+ /// <summary>
+ /// Gets the remote connections view vm.
+ /// </summary>
+ public static RemoteConnectionsViewVM RemoteConnectionsViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<RemoteConnectionsViewVM>();
+ }
+ }
}
}
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
@@ -16,16 +19,22 @@ namespace Tango.PPC.Technician.ViewModels
public RelayCommand<String> NavigationCommand { get; set; }
/// <summary>
+ /// Gets or sets the browser command.
+ /// </summary>
+ public RelayCommand BrowserCommand { get; set; }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="CatalogViewVM"/> class.
/// </summary>
public CatalogViewVM()
{
NavigationCommand = new RelayCommand<string>(NavigateToView);
+ BrowserCommand = new RelayCommand(OpenBrowserModule);
}
public override void OnApplicationStarted()
{
-
+
}
/// <summary>
@@ -36,5 +45,17 @@ namespace Tango.PPC.Technician.ViewModels
{
NavigationManager.NavigateTo<TechnicianModule>(view);
}
+
+ /// <summary>
+ /// Opens the browser module.
+ /// </summary>
+ private void OpenBrowserModule()
+ {
+ //NavigationManager.NavigateWithObject<BrowserModule, BrowserView, BrowserNavigationRequest>(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<LogItemBase> paused_logs;
+ private List<LogItemBase> paused_embedded_logs;
public SynchronizedObservableCollection<LogItemBase> ApplicationLogs { get; set; }
public SynchronizedObservableCollection<LogItemBase> 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<LogItemBase>();
EmbeddedLogs = new SynchronizedObservableCollection<LogItemBase>();
ApplicationLogsViewSource = CollectionViewSource.GetDefaultView(ApplicationLogs);
+ EmbeddedLogsViewSource = CollectionViewSource.GetDefaultView(EmbeddedLogs);
paused_logs = new List<LogItemBase>();
+ paused_embedded_logs = new List<LogItemBase>();
+
+ 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<LogItemDetailsViewVM>(new LogItemDetailsViewVM()
+ if (SelectedLog.GetType() == typeof(EmbeddedLogItem))
{
- Log = SelectedLog,
- });
-
- SelectedLog = null;
+ await NotificationProvider.ShowDialog<EmbeddedLogItemDetailsViewVM>(new EmbeddedLogItemDetailsViewVM()
+ {
+ Log = SelectedLog as EmbeddedLogItem,
+ });
+ }
+ else
+ {
+ await NotificationProvider.ShowDialog<LogItemDetailsViewVM>(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<TechnicianModule>(nameof(CatalogView));
+ NavigationManager.NavigateTo<TechnicianModule>(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<PackageInstallation> _packages;
+ public List<PackageInstallation> 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<TangoUpdate> _updates;
+ public List<TangoUpdate> 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<TangoUpdate>();
+ 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<UpdateDetailsViewVM>(new UpdateDetailsViewVM() { Update = SelectedUpdate });
+ }
+ }
+
+ private async void OnSelectedSynchronizationChanged()
+ {
+ if (SelectedSynchronization != null)
+ {
+ await NotificationProvider.ShowDialog<SynchronizationDetailsViewVM>(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 @@
<Border.Effect>
<DropShadowEffect Color="Silver" ShadowDepth="0" BlurRadius="20" Opacity="1" />
</Border.Effect>
- <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Technician Mode</TextBlock>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Technician</TextBlock>
</Border>
- <Grid Grid.Row="1" VerticalAlignment="Top" Margin="20">
- <UniformGrid Columns="2">
- <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="LoggingView" Width="250" Height="250" Style="{StaticResource TangoHollowButton}" Padding="20">
- <DockPanel>
- <TextBlock Margin="0 10 0 0" DockPanel.Dock="Bottom" HorizontalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Logging</TextBlock>
- <Image Width="128" Source="../Images/logging.png" />
- </DockPanel>
- </touch:TouchButton>
+ <touch:LightTouchScrollViewer Grid.Row="1">
+ <Grid Grid.Row="1" VerticalAlignment="Top" Margin="20">
+ <StackPanel Margin="30 0 30 0" DockPanel.Dock="Bottom" VerticalAlignment="Center">
- <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="SystemView" Width="250" Height="250" Style="{StaticResource TangoHollowButton}" Padding="20">
- <DockPanel>
- <TextBlock Margin="0 10 0 0" DockPanel.Dock="Bottom" HorizontalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">System</TextBlock>
- <Image Width="128" Source="../Images/system.png" />
- </DockPanel>
- </touch:TouchButton>
+ <StackPanel.Resources>
+ <Style TargetType="touch:TouchButton" x:Key="ButtonMenu">
+ <Setter Property="Padding" Value="10"></Setter>
+ <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
+ <Setter Property="Height" Value="140"></Setter>
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="1"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="EnableDropShadow" Value="False"></Setter>
+ <Setter Property="CornerRadius" Value="5"></Setter>
+ <Setter Property="Margin" Value="0 0 0 20"></Setter>
+ <Setter Property="RippleBrush" Value="#4BB8B8B8"></Setter>
+ </Style>
+ </StackPanel.Resources>
- <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="DispensersView" Margin="0 60 0 0" Width="250" Height="250" Style="{StaticResource TangoHollowButton}" Padding="20">
- <DockPanel>
- <TextBlock Margin="0 10 0 0" DockPanel.Dock="Bottom" HorizontalAlignment="Center" FontSize="{StaticResource TangoExpanderHeaderFontSize}">Dispensers</TextBlock>
- <Image Width="128" Source="../Images/dispensers.png" />
- </DockPanel>
- </touch:TouchButton>
- </UniformGrid>
- </Grid>
+ <TextBlock Margin="0 20 0 40" Foreground="{StaticResource TangoGrayTextBrush}">The technician module enables additional diagnostic tools.</TextBlock>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="LoggingView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/logging.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Logging</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ Display and investigate issues using application and embedded device logs.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="SystemView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/system.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoTitleFontSize}">System</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ Display system properties, perform system actions, reset, shutdown etc...
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="DispensersView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/dispensers.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Dispensers</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ Perform manual dispensers homing priming.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="PackagesView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/packages.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Installed Packages</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ View the history of update packages installation.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="UpdatesView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/sync.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Updates &amp; Synchronization</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ View the current status and history of update and synchronization operations.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <touch:TouchButton Command="{Binding NavigationCommand}" CommandParameter="RemoteConnectionsView" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/remote_connections.png" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Remote Connections</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ View the current status of remote connections to this machine.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+
+ <!--<touch:TouchButton Command="{Binding BrowserCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/browser.png" RenderOptions.BitmapScalingMode="Fant" Width="80" Height="80" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Browser</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" TextWrapping="Wrap" Width="580">
+ Open the browser module and navigate the web.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>-->
+ </StackPanel>
+ </Grid>
+ </touch:LightTouchScrollViewer>
</Grid>
</UserControl>
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 @@
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<StackPanel Orientation="Horizontal">
- <touch:TouchNavigationLinks Margin="20" FontSize="{StaticResource TangoNavigationLinksFontSize}">
+ <touch:TouchNavigationLinks x:Name="nav" Margin="20" FontSize="{StaticResource TangoNavigationLinksFontSize}">
<sys:String>Application</sys:String>
<sys:String>Embedded</sys:String>
</touch:TouchNavigationLinks>
@@ -47,91 +47,109 @@
<touch:TouchIcon Icon="Magnify" Foreground="{StaticResource TangoGrayBrush}" Width="16" Height="16" />
<touch:TouchTextBox Width="200" VerticalAlignment="Center" Margin="5 -10 0 0" Text="{Binding Filter,Delay=1000}"></touch:TouchTextBox>
</StackPanel>
+
+ <touch:TouchCheckBox IsChecked="{Binding ProcessDebugLogs}" Margin="20 0 0 0" Content="Debug Logs">
+ <touch:TouchCheckBox.Style>
+ <Style TargetType="touch:TouchCheckBox" BasedOn="{StaticResource {x:Type touch:TouchCheckBox}}">
+ <Setter Property="Visibility" Value="Collapsed"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ElementName=nav,Path=SelectedIndex}" Value="0">
+ <Setter Property="Visibility" Value="Visible"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchCheckBox.Style>
+ </touch:TouchCheckBox>
</StackPanel>
</StackPanel>
<touch:TouchDatePicker Visibility="Collapsed" SelectedDate="12/15/2018" Height="40" />
</DockPanel>
<Grid Margin="20">
- <touch:TouchSimpleDataGrid AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" BorderThickness="1" BorderBrush="{StaticResource TangoDarkForegroundBrush}" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserResizeColumns="False" CanUserSortColumns="False" IsReadOnly="True" ItemsSource="{Binding ApplicationLogsViewSource}" SelectedItem="{Binding SelectedLog}" VerticalGridLinesBrush="{x:Null}" HorizontalGridLinesBrush="{StaticResource TangoGrayBrush}" RowHeight="50" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
- <DataGrid.Resources>
- <Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
- <Setter Property="Background" Value="{StaticResource TangoDarkForegroundBrush}" />
- <Setter Property="Foreground" Value="{StaticResource TangoLightForegroundBrush}" />
- <Setter Property="Padding" Value="5"></Setter>
- </Style>
- </DataGrid.Resources>
- <DataGrid.RowStyle>
- <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
- <Style.Triggers>
- <Trigger Property="IsSelected" Value="True">
- <Setter Property="Background" Value="Transparent"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
- </Trigger>
- <Trigger Property="IsFocused" Value="True">
- <Setter Property="Background" Value="Transparent"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
- </Trigger>
- </Style.Triggers>
- </Style>
- </DataGrid.RowStyle>
- <DataGrid.CellStyle>
- <Style TargetType="{x:Type DataGridCell}">
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type DataGridCell}">
- <Grid Background="{TemplateBinding Background}">
- <ContentPresenter VerticalAlignment="Center" />
- </Grid>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- <Style.Triggers>
- <Trigger Property="IsSelected" Value="True">
- <Setter Property="Background" Value="Transparent"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
- </Trigger>
- </Style.Triggers>
- </Style>
- </DataGrid.CellStyle>
- <DataGrid.Columns>
- <DataGridTemplateColumn Header="" Width="50">
- <DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <touch:TouchIcon Width="16">
- <touch:TouchIcon.Style>
- <Style TargetType="touch:TouchIcon">
- <Setter Property="Icon" Value="InformationOutline"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding Category}" Value="Warning">
- <Setter Property="Icon" Value="ExclamationTriangleSolid"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding Category}" Value="Error">
- <Setter Property="Icon" Value="Alert"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding Category}" Value="Critical">
- <Setter Property="Icon" Value="Alert"></Setter>
- <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </touch:TouchIcon.Style>
- </touch:TouchIcon>
- </DataTemplate>
- </DataGridTemplateColumn.CellTemplate>
- </DataGridTemplateColumn>
- <DataGridTextColumn Header="Time" Width="120" Binding="{Binding TimeStamp,Converter={StaticResource DateTimeUTCToStringConverter},Mode=OneWay,ConverterParameter='hh\\:mm\\:ss.ff'}" />
- <DataGridTemplateColumn Header="Message" Width="1*">
- <DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <TextBlock Text="{Binding Message,Converter={StaticResource LogItemMessageToOneLineConverter},ConverterParameter='70',Mode=OneWay}"/>
- </DataTemplate>
- </DataGridTemplateColumn.CellTemplate>
- </DataGridTemplateColumn>
- </DataGrid.Columns>
- </touch:TouchSimpleDataGrid>
+ <TabControl Padding="0" BorderThickness="0" Margin="0 10 0 0" Background="Transparent" SelectedIndex="{Binding ElementName=nav,Path=SelectedIndex,Mode=OneWay}">
+ <TabItem Header="Application" Visibility="Collapsed">
+ <touch:TouchSimpleDataGrid x:Name="gridApplication" Style="{StaticResource TechGrid}" ItemsSource="{Binding ApplicationLogsViewSource}" SelectedItem="{Binding SelectedLog}">
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="InformationOutline"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Category}" Value="Warning">
+ <Setter Property="Icon" Value="ExclamationTriangleSolid"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Category}" Value="Error">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Category}" Value="Critical">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="Time" Width="120" Binding="{Binding TimeStamp,Converter={StaticResource DateTimeUTCToStringConverter},Mode=OneWay,ConverterParameter='hh\\:mm\\:ss.ff'}" />
+ <DataGridTemplateColumn Header="Message" Width="1*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Message,Converter={StaticResource LogItemMessageToOneLineConverter},ConverterParameter='70',Mode=OneWay}"/>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </TabItem>
+ <TabItem Header="Embedded" Visibility="Collapsed">
+ <touch:TouchSimpleDataGrid x:Name="gridEmbedded" Style="{StaticResource TechGrid}" ItemsSource="{Binding EmbeddedLogsViewSource}" SelectedItem="{Binding SelectedLog}">
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="InformationOutline"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Category}" Value="Warning">
+ <Setter Property="Icon" Value="ExclamationTriangleSolid"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Category}" Value="Error">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Category}" Value="Critical">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="Time" Width="120" Binding="{Binding TimeStamp,Converter={StaticResource DateTimeUTCToStringConverter},Mode=OneWay,ConverterParameter='hh\\:mm\\:ss.ff'}" />
+ <DataGridTemplateColumn Header="Message" Width="1*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Message,Converter={StaticResource LogItemMessageToOneLineConverter},ConverterParameter='70',Mode=OneWay}"/>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </TabItem>
+ </TabControl>
</Grid>
</DockPanel>
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 @@
<local:LoggingView/>
<local:DispensersView/>
<local:SystemView/>
+ <local:PackagesView/>
+ <local:UpdatesView/>
+ <local:RemoteConnectionsView/>
</controls:NavigationControl>
</Grid>
</UserControl>
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 @@
+<UserControl x:Class="Tango.PPC.Technician.Views.PackagesView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Technician.Views"
+ xmlns:controls="clr-namespace:Tango.PPC.Technician.Controls"
+ xmlns:sys="clr-namespace:System;assembly=mscorlib"
+ xmlns:vm="clr-namespace:Tango.PPC.Technician.ViewModels"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:global="clr-namespace:Tango.PPC.Technician"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:PackagesViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.PackagesViewVM}">
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Border Padding="20" Background="{StaticResource TangoPrimaryBackgroundBrush}" BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}">
+ <Border.Effect>
+ <DropShadowEffect Color="Silver" ShadowDepth="0" BlurRadius="20" Opacity="1" />
+ </Border.Effect>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Installed Packages</TextBlock>
+ </Border>
+
+ <Grid Grid.Row="1">
+ <Grid Margin="20">
+ <touch:TouchSimpleDataGrid Background="{StaticResource TangoPrimaryBackgroundBrush}" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" BorderThickness="1" BorderBrush="{StaticResource TangoDarkForegroundBrush}" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserResizeColumns="False" CanUserSortColumns="False" IsReadOnly="True" ItemsSource="{Binding Packages}" VerticalGridLinesBrush="{x:Null}" HorizontalGridLinesBrush="{StaticResource TangoGrayBrush}" RowHeight="50" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
+ <DataGrid.Resources>
+ <Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
+ <Setter Property="Background" Value="{StaticResource TangoDarkForegroundBrush}" />
+ <Setter Property="Foreground" Value="{StaticResource TangoLightForegroundBrush}" />
+ <Setter Property="Padding" Value="5"></Setter>
+ </Style>
+ </DataGrid.Resources>
+ <DataGrid.RowStyle>
+ <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ <Trigger Property="IsFocused" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </DataGrid.RowStyle>
+ <DataGrid.CellStyle>
+ <Style TargetType="{x:Type DataGridCell}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type DataGridCell}">
+ <Grid Background="{TemplateBinding Background}">
+ <ContentPresenter VerticalAlignment="Center" />
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Pause"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding State}" Value="Failed">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Installed">
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="Type" Width="60" Binding="{Binding Type}" />
+ <DataGridTextColumn Header="Date" Width="180" Binding="{Binding InstallationDate}" />
+ <DataGridTextColumn Header="Name" Width="*" Binding="{Binding PackageName}" />
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for DispensersView.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.Technician.Views.RemoteConnectionsView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.Technician.ViewModels"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:global="clr-namespace:Tango.PPC.Technician"
+ xmlns:local="clr-namespace:Tango.PPC.Technician.Views"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RemoteConnectionsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RemoteConnectionsViewVM}">
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Border Padding="20" Background="{StaticResource TangoPrimaryBackgroundBrush}" BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}">
+ <Border.Effect>
+ <DropShadowEffect Color="Silver" ShadowDepth="0" BlurRadius="20" Opacity="1" />
+ </Border.Effect>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Remote Connections</TextBlock>
+ </Border>
+
+ <Grid Grid.Row="1">
+ <Grid Margin="20">
+ <DockPanel>
+ <touch:TouchButton Command="{Binding DisconnectCommand}" DockPanel.Dock="Bottom" HorizontalAlignment="Right" Style="{StaticResource TangoHollowButton}" Height="60" Width="250" Margin="0 20 0 0">DISCONNECT</touch:TouchButton>
+ <touch:TouchSimpleDataGrid IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedReceiver,Mode=TwoWay}" Background="{StaticResource TangoPrimaryBackgroundBrush}" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" BorderThickness="1" BorderBrush="{StaticResource TangoDarkForegroundBrush}" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserResizeColumns="False" CanUserSortColumns="False" IsReadOnly="True" ItemsSource="{Binding ExternalBridgeService.ActiveReceivers}" VerticalGridLinesBrush="{x:Null}" HorizontalGridLinesBrush="{StaticResource TangoGrayBrush}" RowHeight="50" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
+ <DataGrid.Resources>
+ <Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
+ <Setter Property="Background" Value="{StaticResource TangoDarkForegroundBrush}" />
+ <Setter Property="Foreground" Value="{StaticResource TangoLightForegroundBrush}" />
+ <Setter Property="Padding" Value="5"></Setter>
+ </Style>
+ </DataGrid.Resources>
+ <DataGrid.RowStyle>
+ <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ <Trigger Property="IsFocused" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </DataGrid.RowStyle>
+ <DataGrid.CellStyle>
+ <Style TargetType="{x:Type DataGridCell}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type DataGridCell}">
+ <Grid Background="{TemplateBinding Background}">
+ <ContentPresenter VerticalAlignment="Center" />
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </DataGrid.CellStyle>
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16" Icon="Bridge" />
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="App ID" Width="130" Binding="{Binding LoginInfo.AppID}" />
+ <DataGridTextColumn Header="User" Width="180" Binding="{Binding LoginInfo.UserName}" />
+ <DataGridTextColumn Header="Host Name" Width="180" Binding="{Binding LoginInfo.HostName}" />
+ <DataGridTextColumn Header="Safety Level Permissions" Width="1*" Binding="{Binding LoginInfo.RequireSafetyLevelOperations,Converter={StaticResource BooleanToYesNoConverter}}" />
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </DockPanel>
+ </Grid>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for RemoteConnectionsView.xaml
+ /// </summary>
+ 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">
<UserControl.Resources>
<converters:ByteArrayToFileSizeConverter x:Key="ByteArrayToFileSizeConverter" />
@@ -29,55 +30,283 @@
<TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">System</TextBlock>
</Border>
- <Grid Grid.Row="1" Margin="20">
+ <Grid Grid.Row="1">
- <DockPanel>
- <UniformGrid DockPanel.Dock="Top" Columns="3" Margin="50" TextElement.FontSize="{StaticResource TangoHeaderFontSize}">
- <TextBlock HorizontalAlignment="Center" FontWeight="SemiBold">
- <Run>CPU:</Run>
- <Run Text="{Binding CPU,Mode=OneWay,StringFormat='0'}"></Run><Run>%</Run>
- </TextBlock>
+ <touch:LightTouchScrollViewer>
+ <DockPanel Margin="20">
+ <StackPanel Margin="30 40 30 0" DockPanel.Dock="Bottom" VerticalAlignment="Center">
- <TextBlock HorizontalAlignment="Center" FontWeight="SemiBold">
- <Run>RAM:</Run>
- <Run Text="{Binding RAM,Mode=OneWay,Converter={StaticResource ByteArrayToFileSizeConverter},StringFormat='0'}"></Run>
- </TextBlock>
+ <StackPanel.Resources>
+ <Style TargetType="touch:TouchButton" x:Key="ButtonMenu">
+ <Setter Property="Padding" Value="10"></Setter>
+ <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
+ <Setter Property="Height" Value="100"></Setter>
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="1"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="EnableDropShadow" Value="False"></Setter>
+ <Setter Property="CornerRadius" Value="5"></Setter>
+ <Setter Property="Margin" Value="0 0 0 20"></Setter>
+ <Setter Property="RippleBrush" Value="#4BB8B8B8"></Setter>
+ </Style>
+ </StackPanel.Resources>
- <TextBlock HorizontalAlignment="Center" FontWeight="SemiBold">
- <Run>TEMP:</Run>
- <Run Text="{Binding Temperature,Mode=OneWay,StringFormat='0 °C'}"></Run>
- </TextBlock>
- </UniformGrid>
+ <touch:TouchButton Command="{Binding ResetDeviceCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/circuit-board.png" Width="60" Height="60" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Reset Embedded Device</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Resets the embedded device using the DFU channel.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
- <DockPanel>
+ <touch:TouchButton Command="{Binding RestartCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/mobile-phone.png" Width="60" Height="60" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Restart Panel PC</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Restarts the panel PC operation system.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ <touch:TouchButton Command="{Binding ShutdownCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/shutdown.png" Width="60" Height="60" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Shutdown Panel PC</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Turns off the panel PC (requires turning on from reset button).
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ <touch:TouchButton Command="{Binding FactoryResetCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/conveyor.png" Width="60" Height="60" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Factory Reset</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Removes all data associated with this machine and installs the latest version.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ <touch:TouchButton Command="{Binding ExitToExplorerCommand}" Style="{StaticResource ButtonMenu}">
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
+ <Image Source="../Images/exit.png" Width="60" Height="60" />
+ <StackPanel Margin="10 0 0 0">
+ <TextBlock FontSize="{StaticResource TangoButtonFontSize}">Exit To Shell</TextBlock>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}">
+ Closes the PPC application and opens the windows shell.
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ </StackPanel>
- <StackPanel DockPanel.Dock="Top" HorizontalAlignment="Center">
- <TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" FontSize="{StaticResource TangoHeaderFontSize}">
- <Run>UP TIME:</Run>
- <Run Text="{Binding UpTime,StringFormat=hh\\:mm\\:ss,FallbackValue='00:00:00'}"></Run>
- </TextBlock>
+ <FlowDocumentScrollViewer VerticalScrollBarVisibility="Disabled">
+ <FlowDocument>
+ <Table CellSpacing="0" FontFamily="{StaticResource TangoFlexoFontFamily}">
+ <Table.Resources>
+ <Style TargetType="{x:Type TableRowGroup}">
+ <Setter Property="FontSize" Value="{StaticResource TangoDefaultFontSize}"/>
+ </Style>
- <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontWeight="SemiBold" FontSize="{StaticResource TangoHeaderFontSize}">
- <Run>IP ADDRESS:</Run>
- <Run Text="{Binding IPAddress}"></Run>
- </TextBlock>
- </StackPanel>
+ <Style TargetType="TableCell">
+ <Setter Property="BorderThickness" Value="0 0 0 1"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource TangoGrayBrush}"></Setter>
+ <Setter Property="Padding" Value="5"></Setter>
+ </Style>
+ </Table.Resources>
+ <Table.Columns>
+ <TableColumn Width="160" />
+ <TableColumn />
+ <TableColumn />
+ </Table.Columns>
- <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Width="300" TextElement.FontSize="{StaticResource TangoTitleFontSize}">
- <touch:TouchButton Command="{Binding ResetDeviceCommand}" Height="60" Content="Reset Machine">
- <touch:TouchButton.Style>
- <Style TargetType="touch:TouchButton" BasedOn="{StaticResource {x:Type touch:TouchButton}}">
- <Setter Property="Background" Value="{StaticResource TangoErrorBrush}"></Setter>
- </Style>
- </touch:TouchButton.Style>
- </touch:TouchButton>
- <touch:TouchButton Command="{Binding RestartCommand}" Height="60" Background="{StaticResource TangoErrorBrush}" Margin="0 20 0 0">Restart Device</touch:TouchButton>
- <touch:TouchButton Command="{Binding ShutdownCommand}" Height="60" Background="{StaticResource TangoErrorBrush}" Margin="0 20 0 0">Shutdown Device</touch:TouchButton>
- <touch:TouchButton Command="{Binding FactoryResetCommand}" Height="60" Background="{StaticResource TangoErrorBrush}" Margin="0 20 0 0">Factory Reset</touch:TouchButton>
- <touch:TouchButton Command="{Binding ExitToExplorerCommand}" Height="60" Background="{StaticResource TangoErrorBrush}" Margin="0 20 0 0">Exit To Shell</touch:TouchButton>
- </StackPanel>
+ <TableRowGroup>
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Application Version:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding ApplicationManager.Version,Mode=OneWay,TargetNullValue='N/A',FallbackValue='N/A'}"/>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Firmware Version:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding MachineProvider.MachineOperator.DeviceInformation.Version,Mode=OneWay,TargetNullValue='N/A',FallbackValue='N/A'}"/>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>FPGA 1:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding MachineProvider.MachineOperator.DeviceInformation.FPGA1Version,Mode=OneWay,TargetNullValue='N/A',FallbackValue='N/A'}"/>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>FPGA 2:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding MachineProvider.MachineOperator.DeviceInformation.FPGA2Version,Mode=OneWay,TargetNullValue='N/A',FallbackValue='N/A'}"/>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>FPGA 3:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding MachineProvider.MachineOperator.DeviceInformation.FPGA3Version,Mode=OneWay,TargetNullValue='N/A',FallbackValue='N/A'}"/>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>CPU:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock>
+ <Run Text="{Binding CPU,Mode=OneWay,StringFormat='0',FallbackValue=0}"></Run>
+ <Run>%</Run>
+ </TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>RAM:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding RAM,Mode=OneWay,FallbackValue=0,Converter={StaticResource ByteArrayToFileSizeConverter},StringFormat='0'}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Temperature:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding Temperature,Mode=OneWay,FallbackValue=0,StringFormat='0 °C'}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Up Time:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding UpTime,Mode=OneWay,StringFormat=hh\\:mm\\:ss,FallbackValue='00:00:00'}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>IP Address:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding IPAddress,Mode=OneWay,FallbackValue=0}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Total Dye Time:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding TotalDyeTime,Mode=OneWay,FallbackValue=0}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+
+ <TableRow>
+ <TableCell>
+ <Paragraph>
+ <TextBlock>Total Dye Meters:</TextBlock>
+ </Paragraph>
+ </TableCell>
+
+ <TableCell>
+ <Paragraph>
+ <TextBlock Text="{Binding TotalDyeMeters,Mode=OneWay,FallbackValue=0}"></TextBlock>
+ </Paragraph>
+ </TableCell>
+ </TableRow>
+ </TableRowGroup>
+ </Table>
+ </FlowDocument>
+ </FlowDocumentScrollViewer>
</DockPanel>
- </DockPanel>
+ </touch:LightTouchScrollViewer>
</Grid>
</Grid>
</UserControl>
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 @@
+<UserControl x:Class="Tango.PPC.Technician.Views.UpdatesView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.Technician.Views"
+ xmlns:sys="clr-namespace:System;assembly=mscorlib"
+ xmlns:vm="clr-namespace:Tango.PPC.Technician.ViewModels"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:converters="clr-namespace:Tango.PPC.Technician.Converters"
+ xmlns:global="clr-namespace:Tango.PPC.Technician"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:UpdatesViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.UpdatesViewVM}">
+
+ <UserControl.Resources>
+ <converters:LogItemMessageToOneLineConverter x:Key="LogItemMessageToOneLineConverter" />
+ </UserControl.Resources>
+
+ <Grid Background="{StaticResource TangoMidBackgroundBrush}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="1*"/>
+ </Grid.RowDefinitions>
+
+ <Border Padding="20" Background="{StaticResource TangoPrimaryBackgroundBrush}" BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}">
+ <Border.Effect>
+ <DropShadowEffect Color="Silver" ShadowDepth="0" BlurRadius="20" Opacity="1" />
+ </Border.Effect>
+ <TextBlock VerticalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">Updates &amp; Synchronization</TextBlock>
+ </Border>
+
+ <Grid Grid.Row="1" Margin="15">
+
+ <DockPanel>
+ <touch:TouchNavigationLinks x:Name="nav" DockPanel.Dock="Top" FontSize="{StaticResource TangoTitleFontSize}">
+ <sys:String>Updates</sys:String>
+ <sys:String>Synchronization</sys:String>
+ </touch:TouchNavigationLinks>
+ <TabControl Padding="0" BorderThickness="0" Margin="0 10 0 0" Background="Transparent" SelectedIndex="{Binding ElementName=nav,Path=SelectedIndex,Mode=OneWay}">
+ <TabItem Visibility="Collapsed" Header="Software Updates">
+ <touch:TouchSimpleDataGrid Style="{StaticResource TechGrid}" ItemsSource="{Binding Updates}" SelectedItem="{Binding SelectedUpdate}">
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Pause"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsSetup}" Value="True">
+ <Setter Property="Icon" Value="Settings"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsUpdate}" Value="True">
+ <Setter Property="Icon" Value="CloudDownload"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsDataBase}" Value="True">
+ <Setter Property="Icon" Value="Database"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsSynchronization}" Value="True">
+ <Setter Property="Icon" Value="Sync"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsOfflineUpdate}" Value="True">
+ <Setter Property="Icon" Value="Sd"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsOfflineFirmwareUpgrade}" Value="True">
+ <Setter Property="Icon" Value="Chip"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsStarted}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsCompleted}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsFailed}" Value="True">
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="Date" Width="120" Binding="{Binding StartDate,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" />
+ <DataGridTextColumn Header="Application" Width="120" Binding="{Binding ApplicationVersion}" />
+ <DataGridTextColumn Header="Firmware" Width="120" Binding="{Binding FirmwareVersion}" />
+ <DataGridTemplateColumn Header="Message" Width="1*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding UpdateStatus,Converter={StaticResource EnumToDescriptionConverter}}"/>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </TabItem>
+ <TabItem Visibility="Collapsed" Header="Synchronization">
+ <DockPanel>
+ <DockPanel DockPanel.Dock="Bottom">
+ <DockPanel Margin="20">
+ <touch:TouchButton IsEnabled="{Binding MachineDataSynchronizer.IsEnabled}" DockPanel.Dock="Right" Padding="50 20" CornerRadius="30" Command="{Binding SynchronizeCommand}">Synchronize Now</touch:TouchButton>
+ <TextBlock Foreground="{StaticResource TangoGrayTextBrush}" VerticalAlignment="Center" TextWrapping="Wrap" Margin="0 0 20 0">Synchronization occurres automatically in the background. You can choose to synchronize now.</TextBlock>
+ </DockPanel>
+ </DockPanel>
+
+ <Grid>
+ <touch:TouchSimpleDataGrid Style="{StaticResource TechGrid}" ItemsSource="{Binding MachineDataSynchronizer.StatusHistory}" SelectedItem="{Binding SelectedSynchronization}">
+ <DataGrid.Columns>
+ <DataGridTemplateColumn Header="" Width="50">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <touch:TouchIcon Width="16">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Pause"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding State}" Value="Pending">
+ <Setter Property="Icon" Value="Pause"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Synchronizing">
+ <Setter Property="Icon" Value="CloudSync"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Failed">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoErrorBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding State}" Value="Completed">
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGreenBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ <DataGridTextColumn Header="Start Time" Width="120" Binding="{Binding StartDateTime,StringFormat=t}" />
+ <DataGridTextColumn Header="Status" Width="120" Binding="{Binding State,Converter={StaticResource EnumToDescriptionConverter}}" />
+ <DataGridTextColumn Header="Duration" Width="120" Binding="{Binding Duration,StringFormat='hh\\:mm\\:ss'}" />
+ <DataGridTemplateColumn Header="Message" Width="1*">
+ <DataGridTemplateColumn.CellTemplate>
+ <DataTemplate>
+ <TextBlock Text="{Binding Message,Converter={StaticResource StringEllipsisConverter},ConverterParameter='70',Mode=OneWay}"/>
+ </DataTemplate>
+ </DataGridTemplateColumn.CellTemplate>
+ </DataGridTemplateColumn>
+ </DataGrid.Columns>
+ </touch:TouchSimpleDataGrid>
+ </Grid>
+ </DockPanel>
+ </TabItem>
+ </TabControl>
+ </DockPanel>
+ </Grid>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for UpdatesView.xaml
+ /// </summary>
+ 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
@@ -46,6 +46,11 @@ namespace Tango.PPC.Common.Application
event EventHandler SystemRestartRequired;
/// <summary>
+ /// Occurs when the updater utility has failed to perform the last update.
+ /// </summary>
+ event EventHandler UpdaterFailed;
+
+ /// <summary>
/// Occurs when the application has encountered an error when initializing.
/// </summary>
event EventHandler<Exception> ApplicationInitializationError;
@@ -61,6 +66,16 @@ namespace Tango.PPC.Common.Application
bool IsInTechnicianMode { get; }
/// <summary>
+ /// Gets a value indicating whether an update has occurred before the application started.
+ /// </summary>
+ bool IsAfterUpdate { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether the updater utility has failed to perform the last update.
+ /// </summary>
+ bool IsUpdateFailed { get; }
+
+ /// <summary>
/// Shutdown the application.
/// </summary>
void ShutDown();
@@ -91,6 +106,11 @@ namespace Tango.PPC.Common.Application
Version Version { get; }
/// <summary>
+ /// Gets the firmware version.
+ /// </summary>
+ Version FirmwareVersion { get; }
+
+ /// <summary>
/// Gets the application build date.
/// </summary>
String BuildDate { get; }
@@ -101,6 +121,11 @@ namespace Tango.PPC.Common.Application
DateTime StartUpDate { get; }
/// <summary>
+ /// Gets or sets the application folder.
+ /// </summary>
+ String StartPath { get; }
+
+ /// <summary>
/// Gets or sets a value indicating whether the screen is currently locked.
/// </summary>
bool IsScreenLocked { get; set; }
@@ -114,5 +139,11 @@ namespace Tango.PPC.Common.Application
/// Invokes a dialog for entering a password and releasing the screen lock.
/// </summary>
void ReleaseScreenLock();
+
+ /// <summary>
+ /// Sets the state of the main window.
+ /// </summary>
+ /// <param name="state">The state.</param>
+ 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
@@ -23,6 +23,11 @@ namespace Tango.PPC.Common.Authentication
User CurrentUser { get; }
/// <summary>
+ /// Gets a value indicating whether the authentication provider is using a null user.
+ /// </summary>
+ bool AuthenticationRequired { get; }
+
+ /// <summary>
/// Performs a user login by the specified email and password.
/// </summary>
/// <param name="email">The email.</param>
@@ -32,6 +37,12 @@ namespace Tango.PPC.Common.Authentication
Task<User> Login(String email, String password, bool encrypt = true);
/// <summary>
+ /// Performs a fake login when no authentication is used.
+ /// </summary>
+ /// <returns></returns>
+ Task Login();
+
+ /// <summary>
/// Logs-out the current logged-in user.
/// </summary>
void LogOut();
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
+{
+ /// <summary>
+ /// Represents a backup file record.
+ /// </summary>
+ public class BackupFile
+ {
+ /// <summary>
+ /// Gets or sets the backup file version.
+ /// </summary>
+ public int Version { get; set; }
+
+ /// <summary>
+ /// Gets or sets the backup name.
+ /// </summary>
+ public String Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the creation date.
+ /// </summary>
+ public DateTime Date { get; set; }
+
+ /// <summary>
+ /// Gets or sets the machine serial number.
+ /// </summary>
+ public String MachineSerialNumber { get; set; }
+
+ /// <summary>
+ /// Gets or sets the application version.
+ /// </summary>
+ public String ApplicationVersion { get; set; }
+
+ /// <summary>
+ /// Gets or sets the firmware version.
+ /// </summary>
+ public String FirmwareVersion { get; set; }
+
+ /// <summary>
+ /// Gets or sets the settings file.
+ /// </summary>
+ public String SettingsFile { get; set; }
+
+ /// <summary>
+ /// Gets or sets the job files.
+ /// </summary>
+ public List<JobFile> JobFiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets the backup settings.
+ /// </summary>
+ public BackupSettings Settings { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BackupFile"/> class.
+ /// </summary>
+ public BackupFile()
+ {
+ Settings = new BackupSettings();
+ JobFiles = new List<JobFile>();
+ }
+
+ public String ToJson()
+ {
+ return JsonConvert.SerializeObject(this);
+ }
+
+ public static BackupFile FromJson(String json)
+ {
+ return JsonConvert.DeserializeObject<BackupFile>(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
+{
+ /// <summary>
+ /// Represents a backup mode.
+ /// </summary>
+ public enum BackupMode
+ {
+ /// <summary>
+ /// Jobs only backup.
+ /// </summary>
+ Jobs,
+ /// <summary>
+ /// Complete backup of data, app binaries, firmware and settings file.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Represents a backup restore procedure progress.
+ /// </summary>
+ /// <seealso cref="System.EventArgs" />
+ public class BackupRestoreProgressEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether the progress is intermediate.
+ /// </summary>
+ public bool IsIntermediate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the progress value.
+ /// </summary>
+ public double Progress { get; set; }
+
+
+ /// <summary>
+ /// Gets or sets the maximum progress.
+ /// </summary>
+ public double MaxProgress { get; set; }
+
+ /// <summary>
+ /// Gets or sets the progress stage.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Represents a backup restore procedure stage.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Represents a backup settings.
+ /// </summary>
+ public class BackupSettings
+ {
+ /// <summary>
+ /// Gets or sets the backup mode.
+ /// </summary>
+ 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<BackupRestoreProgressEventArgs> 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;
+ }
+ });
+ }
+
+ /// <summary>
+ /// Extracts the backup configuration from the specified backup file.
+ /// </summary>
+ /// <param name="filePath">The file path.</param>
+ /// <returns></returns>
+ public Task<BackupFile> ExtractBackupConfiguration(string filePath)
+ {
+ return Task.Factory.StartNew<BackupFile>(() =>
+ {
+ 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<RestoreResult> Restore(string filePath, RestoreSettings settings)
+ {
+ TaskCompletionSource<RestoreResult> completionSource = new TaskCompletionSource<RestoreResult>();
+
+ 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<RestoreResult> 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
+{
+ /// <summary>
+ /// Represents a backup/restore manager.
+ /// </summary>
+ public interface IBackupManager
+ {
+ /// <summary>
+ /// Occurs when the backup/restore procedure makes progress.
+ /// </summary>
+ event EventHandler<BackupRestoreProgressEventArgs> Progress;
+
+ /// <summary>
+ /// Creates a backup file containing database, application and firmware versions.
+ /// </summary>
+ /// <param name="filePath">The file path.</param>
+ /// <param name="name">The backup name.</param>
+ /// <param name="settings">Backup configuration.</param>
+ /// <returns></returns>
+ Task CreateBackup(String filePath, String name, BackupSettings settings);
+
+ /// <summary>
+ /// Restores a backup located in the specified file path.
+ /// </summary>
+ /// <param name="filePath">The file path.</param>
+ /// <param name="settings">The restore settings</param>
+ /// <returns></returns>
+ Task<RestoreResult> Restore(String filePath, RestoreSettings settings);
+
+ /// <summary>
+ /// Extracts the backup configuration from the specified backup file.
+ /// </summary>
+ /// <param name="filePath">The file path.</param>
+ /// <returns></returns>
+ Task<BackupFile> 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;
+ /// <summary>
+ /// Occurs when the machine has connected.
+ /// </summary>
+ public event EventHandler MachineConnected;
+
+ /// <summary>
+ /// Occurs when the machine has disconnected.
+ /// </summary>
+ public event EventHandler MachineDisconnected;
+
+ private bool _isConnected;
+ /// <summary>
+ /// Gets a value indicating whether the machine is currently connected.
+ /// </summary>
+ public bool IsConnected
+ {
+ get { return _isConnected; }
+ private set { _isConnected = value; RaisePropertyChangedAuto(); }
+ }
+
private Machine _machine;
/// <summary>
/// Gets the database machine entity associated with the current machine.
@@ -74,18 +95,24 @@ namespace Tango.PPC.Common.Connection
/// </summary>
public DefaultMachineProvider()
{
+ var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+
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<PPCSettings>();
+ 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<PPCSettings>();
@@ -116,22 +166,28 @@ namespace Tango.PPC.Common.Connection
{
TimeSpan timeout = TimeSpan.FromSeconds(SettingsManager.Default.GetOrCreate<PPCSettings>().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<ConnectRequest, ConnectResponse> scanner = new Transport.Discovery.UsbCommunicationScanner<ConnectRequest, ConnectResponse>(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;
}
+
+ /// <summary>
+ /// Called when the machine has connected.
+ /// </summary>
+ protected virtual void OnMachineConnected()
+ {
+ IsConnected = true;
+ MachineConnected?.Invoke(this, new EventArgs());
+ }
+
+ /// <summary>
+ /// Called when the machine has disconnected.
+ /// </summary>
+ 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
@@ -16,6 +16,21 @@ namespace Tango.PPC.Common.Connection
public interface IMachineProvider
{
/// <summary>
+ /// Occurs when the machine has connected.
+ /// </summary>
+ event EventHandler MachineConnected;
+
+ /// <summary>
+ /// Occurs when the machine has disconnected.
+ /// </summary>
+ event EventHandler MachineDisconnected;
+
+ /// <summary>
+ /// Gets a value indicating whether the machine is currently connected.
+ /// </summary>
+ bool IsConnected { get; }
+
+ /// <summary>
/// Gets the database machine entity associated with the current machine.
/// </summary>
Machine Machine { get; }
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,11 +20,16 @@ namespace Tango.PPC.Common.Connectivity
event EventHandler<ConnectionStateEventArgs> ConnectionStateChanged;
/// <summary>
- /// Gets a value indicating whether there is any Internet connection available.
+ /// Gets a value indicating whether there is a WiFi connection.
/// </summary>
bool IsConnected { get; }
/// <summary>
+ /// Gets a value indicating whether there is LAN connection.
+ /// </summary>
+ bool IsLanConnected { get; }
+
+ /// <summary>
/// Gets the available WiFi networks.
/// </summary>
ObservableCollection<WiFiNetwork> AvailableWiFiNetworks { get; }
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
+{
+ /// <summary>
+ /// Represents the <see cref="IConsoleEngineService"/> default implementation
+ /// which listens to incoming console request by registering as a external bridge request handler.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.Console.IConsoleEngineService" />
+ /// <seealso cref="Tango.Integration.ExternalBridge.IExternalBridgeRequestHandler" />
+ [TangoCreateWhenRegistered]
+ public class DefaultConsoleEngineService : ExtendedObject, IConsoleEngineService, IExternalBridgeRequestHandler
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="IConsoleEngineService" /> is enabled.
+ /// </summary>
+ public bool Enabled { get; set; } = true;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DefaultConsoleEngineService"/> class.
+ /// </summary>
+ /// <param name="externalBridge">The external bridge service instance.</param>
+ public DefaultConsoleEngineService(IPPCExternalBridgeService externalBridge)
+ {
+ externalBridge.RegisterRequestHandler(this);
+ }
+
+ /// <summary>
+ /// Handles <see cref="GetCurrentDirectoryRequest"/> requests.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="token">The token.</param>
+ /// <param name="transporter">The transporter.</param>
+ [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);
+ }
+
+ /// <summary>
+ /// Handles <see cref="ConsoleCommandRequest"/> requests.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="token">The token.</param>
+ /// <param name="transporter">The transporter.</param>
+ [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<ConsoleCommandResponse>(new ConsoleCommandResponse()
+ {
+ Output = result.Output,
+ Suggestions = result.Suggestions,
+ WorkingFolder = result.WorkingFolder
+ }, token);
+ }
+
+ /// <summary>
+ /// Called when any of the external bridge clients (receivers) has disconnected.
+ /// </summary>
+ /// <param name="receiver">The receiver.</param>
+ 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
+{
+ /// <summary>
+ /// Represents a command prompt console service which listens for incoming console requests.
+ /// </summary>
+ 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<FrameworkElement> Elements
+ {
+ get { return (ObservableCollection<FrameworkElement>)GetValue(ElementsProperty); }
+ set { SetValue(ElementsProperty, value); }
+ }
+ public static readonly DependencyProperty ElementsProperty =
+ DependencyProperty.Register("Elements", typeof(ObservableCollection<FrameworkElement>), 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<FrameworkElement>();
+ 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 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:local="clr-namespace:Tango.PPC.Common.Controls">
+
+ <Style TargetType="{x:Type ListBoxItem}" x:Key="Gallery_BlankListBoxItem">
+ <Setter Property="Background" Value="Transparent"/>
+ <Setter Property="BorderThickness" Value="0"></Setter>
+ <Setter Property="Foreground" Value="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource AncestorType=ContentPresenter}}"></Setter>
+ <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter>
+ <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
+ <Setter Property="Padding" Value="0"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type ListBoxItem}">
+ <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Background="{TemplateBinding Background}" Padding="0" SnapsToDevicePixels="true">
+ <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+ </Border>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsSelected" Value="true">
+ <Setter Property="Background" TargetName="Bd" Value="Transparent"/>
+ </Trigger>
+ <MultiTrigger>
+ <MultiTrigger.Conditions>
+ <Condition Property="IsSelected" Value="true"/>
+ <Condition Property="Selector.IsSelectionActive" Value="false"/>
+ </MultiTrigger.Conditions>
+ <Setter Property="Background" TargetName="Bd" Value="Transparent"/>
+ </MultiTrigger>
+ <Trigger Property="IsEnabled" Value="false">
+ <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style TargetType="{x:Type ListBox}" x:Key="Gallery_BlankListBox">
+ <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter>
+ <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"></Setter>
+ <Setter Property="BorderThickness" Value="0"></Setter>
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="ItemContainerStyle" Value="{StaticResource Gallery_BlankListBoxItem}"></Setter>
+ </Style>
+
+ <Style TargetType="{x:Type local:ImageGalleryControl}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type local:ImageGalleryControl}">
+ <Border Background="{TemplateBinding Background}"
+ BorderBrush="{TemplateBinding BorderBrush}"
+ BorderThickness="{TemplateBinding BorderThickness}">
+
+ <DockPanel>
+
+ <ListBox DockPanel.Dock="Bottom" ItemsSource="{TemplateBinding Elements}" SelectedIndex="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=SelectedIndex,Mode=TwoWay}" Style="{StaticResource Gallery_BlankListBox}">
+ <ListBox.ItemsPanel>
+ <ItemsPanelTemplate>
+ <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"></StackPanel>
+ </ItemsPanelTemplate>
+ </ListBox.ItemsPanel>
+ <ListBox.ItemContainerStyle>
+ <Style TargetType="ListBoxItem" BasedOn="{StaticResource Gallery_BlankListBoxItem}">
+ <Setter Property="Margin" Value="10 0"></Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="ListBoxItem">
+ <Ellipse x:Name="ellipse" Stroke="{StaticResource TangoPrimaryAccentBrush}" Width="20" Height="20" StrokeThickness="1">
+ <Ellipse.Style>
+ <Style TargetType="Ellipse">
+
+ </Style>
+ </Ellipse.Style>
+ </Ellipse>
+ <ControlTemplate.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter TargetName="ellipse" Property="Fill" Value="{StaticResource TangoGrayBrush}"></Setter>
+ </Trigger>
+ <Trigger Property="IsSelected" Value="False">
+ <Setter TargetName="ellipse" Property="Fill" Value="Transparent"></Setter>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </ListBox.ItemContainerStyle>
+ </ListBox>
+
+ <controls:NavigationControl x:Name="navigationControl" GalleryMode="True" TransitionType="Slide" TransitionDuration="00:00:0.2" SelectedIndex="{TemplateBinding SelectedIndex}">
+
+ </controls:NavigationControl>
+ </DockPanel>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+</ResourceDictionary> \ 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<ListerReceiver> _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<ListerReceiver>();
+ _machineProvider = machineProvider;
+ machineProvider.MachineOperator.RegisterRequestHandler<PutDataStoreItemRequest>(OnPutDataStoreItemRequest);
+ machineProvider.MachineOperator.RegisterRequestHandler<GetDataStoreItemRequest>(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<RemoteDataStoreCollection> collections = new List<RemoteDataStoreCollection>();
+
+ 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<BL.Entities.DataStoreItem> deleted = new List<BL.Entities.DataStoreItem>();
+
+ 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<DataStoreItemModifiedRequest, DataStoreItemModifiedResponse>(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<DataStoreItemModifiedRequest, DataStoreItemModifiedResponse>(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<MachinesEvent> _pendingEvents;
private List<MachinesEvent> _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
/// <summary>
@@ -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
/// <summary>
/// Represents a database events logger.
/// </summary>
- public interface IEventLogger
+ public interface IEventLogger : IExternalBridgeRequestHandler
{
/// <summary>
/// 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; }
+ }
+
/// <summary>
/// Represents the PPC external bridge service capable of exposing a remote API for communicating and controlling the machine through the PPC.
/// </summary>
@@ -28,11 +37,36 @@ namespace Tango.PPC.Common.ExternalBridge
/// <param name="machineProvider">The machine provider.</param>
public PPCExternalBridgeService(IPPCApplicationManager applicationManager, IMachineProvider machineProvider)
{
- applicationManager.ApplicationReady += (_, __) =>
+ var csvStream = EmbeddedResourceHelper.GetEmbeddedResourceStream("Tango.PPC.Common.SafetyLevelOperations.csv");
+
+ List<CsvEntry> entries = CsvFile.Read<CsvEntry>(new CsvSource(csvStream)).ToList();
+
+ foreach (var entry in entries)
+ {
+ MessageType type;
+ if (Enum.TryParse<MessageType>(entry.MessageType, out type))
+ {
+ ExternalBridgeService.SafetyLevelOperations.Add(type);
+ }
+ }
+
+ applicationManager.ApplicationReady += (_, __) =>
{
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ //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
+{
+ /// <summary>
+ /// Represents the <see cref="IFileSystemService"/> default implementation.
+ /// </summary>
+ /// <seealso cref="Tango.Core.ExtendedObject" />
+ /// <seealso cref="Tango.PPC.Common.FileSystem.IFileSystemService" />
+ /// <seealso cref="Tango.Integration.ExternalBridge.IExternalBridgeRequestHandler" />
+ [TangoCreateWhenRegistered]
+ public class DefaultFileSystemService : ExtendedObject, IFileSystemService, IExternalBridgeRequestHandler
+ {
+ private FileSystemManager _manager;
+ private Dictionary<String, FileSystemOperation> _operations;
+ private Dictionary<ExternalBridgeReceiver, BasicTransporter> _webRtcClients;
+ private PPCSettings _settings;
+
+ public bool Enabled { get; set; } = true;
+ public bool EnableWebRTC { get; set; } = true;
+
+ public DefaultFileSystemService(IPPCExternalBridgeService externalBridge)
+ {
+ _webRtcClients = new Dictionary<ExternalBridgeReceiver, BasicTransporter>();
+ _manager = new FileSystemManager();
+ _operations = new Dictionary<string, FileSystemOperation>();
+ externalBridge.RegisterRequestHandler(this);
+ _settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ }
+
+ [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<ChunkDownloadRequest>(WebRtcChunkDownloadRequestReceived);
+ webRtcTransporter.RegisterRequestHandler<ChunkUploadRequest>(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<FileItem>().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
+{
+ /// <summary>
+ /// Represents an active file system file/folder download/upload operation
+ /// </summary>
+ public class FileSystemOperation
+ {
+ /// <summary>
+ /// Gets or sets the operation mode.
+ /// </summary>
+ public FileSystemOperationMode Mode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the operation identifier.
+ /// </summary>
+ public String Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the path for the operation.
+ /// </summary>
+ public String Path { get; set; }
+
+ /// <summary>
+ /// Should be set to true when the <see cref="Path"/> is a temporary zip file when performing download of a folder.
+ /// </summary>
+ public bool IsPathTempZip { get; set; }
+
+ /// <summary>
+ /// Gets or sets the actual path to extract the zip file when uploading folder.
+ /// </summary>
+ public String UploadPostPath { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FileSystemOperation"/> class.
+ /// </summary>
+ /// <param name="mode">The mode.</param>
+ /// <param name="path">The path.</param>
+ public FileSystemOperation(FileSystemOperationMode mode, String path)
+ {
+ Mode = mode;
+ Id = Guid.NewGuid().ToString();
+ Path = path;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs
index df496c3be..e28843bce 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/FileSystemOperationMode.cs
@@ -4,10 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Tango.PPC.Common.MachineUpdate
+namespace Tango.PPC.Common.FileSystem
{
- public class UpdatePackageFile
+ public enum FileSystemOperationMode
{
- public Version Version { get; set; }
+ 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
+{
+ /// <summary>
+ /// Represents a PPC file system remote service.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.IPPCService" />
+ public interface IFileSystemService : IPPCService
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable the WebRTC transport channel.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Represents a PPC remoting service.
+ /// </summary>
+ public interface IPPCService
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="IPPCService"/> is enabled.
+ /// </summary>
+ bool Enabled { get; set; }
+ }
+}
+
+public static class ExtensionMethods
+{
+ /// <summary>
+ /// Throws an exception is the service is disabled.
+ /// </summary>
+ /// <param name="service">The service.</param>
+ /// <exception cref="System.InvalidOperationException"></exception>
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/cl-full.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Images/lubricant2.png
Binary files 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<PPCSettings>();
+ 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<LogItemBase> _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<LogItemBase>();
+ 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<MachineSetupResult> 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<MachineSetupResult> 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
/// <returns></returns>
public async Task<MachineSetupResult> Setup(string serialNumber)
{
+ _logs.Clear();
+
TaskCompletionSource<MachineSetupResult> result = new TaskCompletionSource<MachineSetupResult>();
+ MachineSetupResponse setup_response = null;
+ _setupStartDate = DateTime.UtcNow;
+
try
{
+ _isUpdating = true;
+
LogManager.Log($"Starting machine setup for serial number {serialNumber}...");
var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().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
{
+ /// <summary>
+ /// Occurs when an application update is available.
+ /// </summary>
+ event EventHandler<CheckForUpdateResponse> UpdateAvailable;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to automatically check for new application updates.
+ /// </summary>
+ bool EnableAutoCheckForUpdates { get; set; }
+
+ /// <summary>
+ /// Gets the current machine update progress status.
+ /// </summary>
MachineUpdateProgress Status { get; }
/// <summary>
@@ -23,46 +38,68 @@ namespace Tango.PPC.Common.MachineUpdate
event EventHandler<MachineUpdateProgress> Progress;
/// <summary>
- /// Performs a machine update using the specified serial number and machine service address.
+ /// Performs a machine update.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <param name="setupFirmware">if set to <c>true</c> updates the embedded device firmware.</param>
/// <param name="setupFPGA">if set to <c>true</c> updates the embedded device FPGA version and other parameters.</param>
/// <returns></returns>
- Task<MachineUpdateResult> Update(String serialNumber, bool setupFirmware, bool setupFPGA);
+ Task<MachineUpdateResult> Update(bool setupFirmware, bool setupFPGA);
/// <summary>
/// Performs a machine update using the specified software update package path.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns></returns>
- Task<MachineUpdateResult> UpdateFromTUP(String fileName);
+ Task<MachineUpdateResult> UpdateFromTUP(String fileName, bool setupFirmware, bool setupFPGA);
+
+ /// <summary>
+ /// Performs a firmware upgrade from the specified TFP file.
+ /// </summary>
+ /// <param name="fileName">Name of the file.</param>
+ /// <returns></returns>
+ Task UpdateFromTFP(String fileName);
/// <summary>
- /// Checks if any update are available for the specified machine serial number.
+ /// Checks if any update are available.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <returns></returns>
- Task<CheckForUpdateResponse> CheckForUpdate(String serialNumber);
+ Task<CheckForUpdateResponse> CheckForUpdate();
/// <summary>
/// Checks whether it is necessary to updates all the "overwrite-able" database tables.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <returns></returns>
- Task<DbCompareResult> UpdateDBCheck(String serialNumber);
+ Task<DbCompareResult> UpdateDBCheck();
/// <summary>
/// Updates all the "overwrite-able" database tables.
/// </summary>
/// <returns></returns>
- Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber);
+ Task UpdateDB(DbCompareResult dbCompareResult);
/// <summary>
/// Gets the update package file information.
/// </summary>
/// <param name="filePath">The file path.</param>
/// <returns></returns>
- Task<UpdatePackageFile> GetUpdatePackageFileInfo(String filePath);
+ Task<PublishInfo> GetUpdatePackageFileInfo(String filePath);
+
+ /// <summary>
+ /// Checks whether any post update packages needs to be installed.
+ /// </summary>
+ /// <returns></returns>
+ Task<bool> PostUpdatePackagesRequired();
+
+ /// <summary>
+ /// Runs all post update packages.
+ /// </summary>
+ /// <returns></returns>
+ Task<PackageRunnerResult> RunPostUpdatePackages();
+
+ /// <summary>
+ /// Restores the last database backup.
+ /// </summary>
+ /// <returns></returns>
+ 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,26 +18,48 @@ 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<LogItemBase> _logs;
+ private System.Timers.Timer _checkForUpdateTimer;
+ private bool _isUpdating;
+ private PPCSettings _settings;
+ private DateTime _updateStartDate;
#region Events
/// <summary>
+ /// Occurs when an application update is available.
+ /// </summary>
+ public event EventHandler<CheckForUpdateResponse> UpdateAvailable;
+
+ /// <summary>
/// Occurs when there is a text log message available.
/// </summary>
public event EventHandler<string> ProgressLog;
@@ -50,12 +74,25 @@ namespace Tango.PPC.Common.MachineUpdate
#region Properties
private MachineUpdateProgress _status;
+ /// <summary>
+ /// Gets the current machine update progress status.
+ /// </summary>
public MachineUpdateProgress Status
{
get { return _status; }
private set { _status = value; RaisePropertyChangedAuto(); }
}
+ private bool _autoCheckForUpdates;
+ /// <summary>
+ /// Gets or sets a value indicating whether to automatically check for new application updates.
+ /// </summary>
+ public bool EnableAutoCheckForUpdates
+ {
+ get { return _autoCheckForUpdates; }
+ set { _autoCheckForUpdates = value; RaisePropertyChangedAuto(); }
+ }
+
#endregion
#region Constructors
@@ -64,23 +101,531 @@ namespace Tango.PPC.Common.MachineUpdate
/// Initializes a new instance of the <see cref="MachineUpdateManager"/> class.
/// </summary>
/// <param name="applicationManager">The application manager.</param>
- 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;
+
+ _logs = new List<LogItemBase>();
+ LogManager.NewLog += LogManager_NewLog;
+
+ _settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+
+ _checkForUpdateTimer = new System.Timers.Timer(_settings.AutoUpdateCheckInterval.TotalMilliseconds);
+ _checkForUpdateTimer.Elapsed += _checkForUpdateTimer_Elapsed;
+ _checkForUpdateTimer.Stop();
+
+ externalBridge.RegisterRequestHandler(this);
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ private void _app_manager_ApplicationReady(object sender, EventArgs e)
+ {
+ _checkForUpdateTimer.Start();
+
+ if (!_app_manager.IsUpdateFailed)
+ {
+ ClearLastDatabaseBackup();
+ }
+ }
+
+ 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)
+ {
+ _logs.Add(e);
+ }
}
#endregion
#region Private Methods
- private Task Login(String serialNumber)
+ private Task Login(String machineGuid)
{
return _client.Login(new LoginRequest()
{
Mode = LoginMode.Machine,
- SerialNumber = serialNumber,
+ MachineGuid = machineGuid,
+ });
+ }
+
+ private async void OnFailed(Exception ex, TaskCompletionSource<MachineUpdateResult> 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.");
+
+ await Task.Factory.StartNew(() =>
+ {
+
+ if (performDatabaseRollback)
+ {
+ LogManager.Log("Rolling back database changes...");
+
+ using (DbManager db = DbManager.FromDataSource(localDataSource))
+ {
+ 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);
+ }
+ }
+ catch (Exception exx)
+ {
+ LogManager.Log(exx, "Error removing temporary database.");
+ }
+ }
+
+ try
+ {
+ Directory.Delete(backupsFolder, true);
+ }
+ catch (Exception ee)
+ {
+ LogManager.Log(ee, $"Error deleting backups folder '{backupsFolder}'.");
+ }
+
+ if (tempUpdatePackageFolder != null)
+ {
+ try
+ {
+ Directory.Delete(tempUpdatePackageFolder, true);
+ }
+ catch (Exception eee)
+ {
+ LogManager.Log(eee, "Error removing temporary package folder.");
+ }
+ }
+
+ });
+
+ completionSource.SetException(ex);
+
+ String logs = GetLogsStringAndClear();
+
+ 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.");
+ }
+
+ 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.");
+ }
+ }
+
+
+ if (tupPublishInfo != null)
+ {
+ try
+ {
+ 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();
+ }
+ }
+ catch (Exception xxx)
+ {
+ LogManager.Log(xxx, "Error saving tango offline update information to database.");
+ }
+ }
+
+ _isUpdating = false;
+ }
+
+ private async void OnCompleted(MachineUpdateResult result, TaskCompletionSource<MachineUpdateResult> completionSource, DownloadUpdateResponse response, String tempDbName, String backupsFolder, Core.DataSource localDataSource, PublishInfo tupPublishInfo = null)
+ {
+ await Task.Factory.StartNew(() =>
+ {
+ 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);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error removing temporary database.");
+ }
+ }
+
+ //try
+ //{
+ // Directory.Delete(backupsFolder, true);
+ //}
+ //catch (Exception ex)
+ //{
+ // LogManager.Log(ex, $"Error deleting backups folder '{backupsFolder}'.");
+ //}
+
+ if (!result.RequiresBinariesUpdate)
+ {
+ try
+ {
+ Directory.Delete(result.UpdatePackagePath, true);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error removing temporary package folder.");
+ }
+ }
+
+ });
+
+ completionSource.SetResult(result);
+
+ if (response != null)
+ {
+ try
+ {
+ var r = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
+ {
+ Token = response.NotifyCompletedToken,
+ Status = BL.Enumerations.TangoUpdateStatuses.UpdateCompleted,
+ });
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error notifying update 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.UpdateCompleted;
+ update.StartDate = _updateStartDate;
+ update.EndDate = DateTime.UtcNow;
+ db.TangoUpdates.Add(update);
+ await db.SaveChangesAsync();
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error saving tango update information to database.");
+ }
+ }
+
+
+ if (tupPublishInfo != null)
+ {
+ try
+ {
+ 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.");
+ }
+ }
+
+ _isUpdating = false;
+ }
+
+ 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 (performDatabaseRollback)
+ {
+ LogManager.Log("Rolling back database changes...");
+
+ using (DbManager db = DbManager.FromDataSource(localDataSource))
+ {
+ 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.");
+ throw ex;
+ }
+ finally
+ {
+ try
+ {
+ File.Delete(dbBackupFile);
+ }
+ catch { }
+ }
+ }
+ }
+
+ String logs = GetLogsStringAndClear();
+
+ if (response != null)
+ {
+ try
+ {
+ var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
+ {
+ Token = response.NotifyCompletedToken,
+ Status = BL.Enumerations.TangoUpdateStatuses.DatabaseFailed,
+ FailedReason = ex.FlattenMessage(),
+ FailedLog = logs,
+ }).Result;
+ }
+ catch (Exception xx)
+ {
+ LogManager.Log(xx, "Error notifying database failed.");
+ }
+
+ try
+ {
+ using (ObservablesContext db = ObservablesContext.CreateDefault())
+ {
+ 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.");
+ }
+ }
+
+ _isUpdating = false;
+ }
+
+ private void OnCompleted(UpdateDBResponse response, bool completedWithNoDifferences = false)
+ {
+ if (response != null)
+ {
+ try
+ {
+ 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.");
+ }
+
+ if (!completedWithNoDifferences)
+ {
+ try
+ {
+ using (ObservablesContext db = ObservablesContext.CreateDefault())
+ {
+ 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<object> completionSource, String firmwareVersion)
+ {
+ LogManager.Log(ex, "An error occurred in firmware upgrade.");
+
+ completionSource.SetException(ex);
+ String logs = GetLogsStringAndClear();
+
+ 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();
+ }
+ }
+ catch (Exception exx)
+ {
+ LogManager.Log(exx, "Error saving firmware upgrade information to database.");
+ }
+
+ _isUpdating = false;
+ }
+
+ private void OnCompleted(TaskCompletionSource<object> completionSource, String firmwareVersion)
+ {
+ LogManager.Log("Firmware upgrade completed successfully.");
+ completionSource.SetResult(true);
+
+ 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.OfflineFirmwareUpgradeCompleted;
+ update.StartDate = _updateStartDate;
+ update.EndDate = DateTime.UtcNow;
+ db.TangoUpdates.Add(update);
+ db.SaveChanges();
+ }
+ }
+ catch (Exception exx)
+ {
+ LogManager.Log(exx, "Error saving firmware upgrade information to database.");
+ }
+
+ _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<PPCSettings>().LastDatabaseBackupFile;
+
+ if (File.Exists(lastBackupFile))
+ {
+ File.Delete(lastBackupFile);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error removing last database backup file.");
+ }
});
}
@@ -89,9 +634,8 @@ namespace Tango.PPC.Common.MachineUpdate
#region Public Methods
/// <summary>
- /// Performs a machine update using the specified serial number and machine service address.
+ /// Performs a machine update.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <param name="setupFirmware">if set to <c>true</c> updates the embedded device firmware.</param>
/// <param name="setupFPGA">if set to <c>true</c> updates the embedded device FPGA version and other parameters.</param>
/// <returns></returns>
@@ -101,19 +645,32 @@ namespace Tango.PPC.Common.MachineUpdate
/// or
/// </exception>
/// <exception cref="System.InvalidProgramException">Database tango does not exists.</exception>
- public async Task<MachineUpdateResult> Update(String serialNumber, bool setupFirmware, bool setupFPGA)
+ public async Task<MachineUpdateResult> Update(bool setupFirmware, bool setupFPGA)
{
+ _updateStartDate = DateTime.UtcNow;
+ _logs.Clear();
+
TaskCompletionSource<MachineUpdateResult> result = new TaskCompletionSource<MachineUpdateResult>();
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().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<PPCSettings>().GetMachineServiceAddress();
+ _isUpdating = true;
+
+ var machineServiceAddress = _settings.GetMachineServiceAddress();
- LogManager.Log($"Starting machine update for serial number {serialNumber}...");
+ LogManager.Log($"Starting machine update...");
//Connecting to machine...
LogManager.Log("Verifying machine connection and state...");
@@ -132,10 +689,11 @@ namespace Tango.PPC.Common.MachineUpdate
{
throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected."));
}
- if (op.IsPrinting)
- {
- throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status."));
- }
+ }
+
+ 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.
@@ -143,21 +701,14 @@ namespace Tango.PPC.Common.MachineUpdate
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
- await Login(serialNumber);
+ await Login(machineGuid);
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.
@@ -167,68 +718,102 @@ namespace Tango.PPC.Common.MachineUpdate
LogManager.Log("Downloading software package...");
- long fileSize = 0;
UpdateProgress("Downloading software package", "Downloading...", false);
- using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) =>
+ using (AutoFileDownloader downloader = new AutoFileDownloader(update_response.BlobAddress, update_response.CdnAddress, tempFile))
{
- UpdateProgress("Downloading software package", "Downloading...", false, current, fileSize);
- }))
- {
- 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);
+ 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...");
- //Extract software package.
- ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder);
+ 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);
-
- //Synchronize database
- UpdateProgress("Updating Database", "Initializing...");
-
- LogManager.Log($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
-
- 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))
+ //Create Database Backup
+ UpdateProgress("Updating Database", "Creating database backup...");
+ try
{
- throw new InvalidProgramException("Database tango does not exists.");
+ 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.");
}
- if (setupFirmware)
+ //Run pre-update packages.
+ try
{
- LogManager.Log("Setup firmware is active so a database rollback procedure should be configured.");
- UpdateProgress("Updating Database", "Creating database backup...");
+ 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
{
- 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.");
+ updateVersion = Version.Parse(update_response.Version);
}
catch (Exception ex)
{
- throw LogManager.Log(ex, "Setup manager error while trying to create a database backup.");
+ 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($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
+
+ UpdateProgress("Updating Database", "Connecting to local database...");
+
+ LogManager.Log("Checking Tango database exists on the local machine...");
+ if (!db.Exists(localDataSource.Catalog))
+ {
+ throw new InvalidProgramException("Database tango does not exists.");
}
LogManager.Log("Disposing database manager.");
@@ -243,7 +828,7 @@ namespace Tango.PPC.Common.MachineUpdate
Path.Combine(_newPackageTempFolder, "Update Scripts"),
update_response.DataSource,
localDataSource,
- serialNumber);
+ machineGuid);
runner.Log += (x, msg) =>
{
@@ -267,14 +852,12 @@ namespace Tango.PPC.Common.MachineUpdate
}
catch (Exception ex)
{
- throw LogManager.Log(ex, "Setup manager error while trying to synchronize database.");
+ throw LogManager.Log(ex, "Update manager error while trying to synchronize database.");
}
//Updating firmware
if (setupFirmware)
{
- performDatabaseRollback = true;
-
UpdateProgress("Updating Firmware", "Connecting to firmware device...");
LogManager.Log("");
LogManager.Log("-------------------------------------------------------------------------");
@@ -293,106 +876,88 @@ namespace Tango.PPC.Common.MachineUpdate
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU;
}
- var handler = await op.UpgradeFirmware(stream);
+ var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo);
handler.Failed += (_, ex) =>
{
stream.Dispose();
- throw ex;
+ OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder);
};
handler.Completed += (_, __) =>
{
UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
stream.Dispose();
- result.SetResult(new MachineUpdateResult()
+ OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
- });
+ }, result, update_response, null, backupsFolder, localDataSource);
};
handler.Canceled += (_, __) =>
{
stream.Dispose();
- throw new Exception("The operation has been canceled.");
+ 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, false, e.Current, e.Total);
+ UpdateProgress("Updating Firmware", e.Message, e.IsIndeterminate, e.Current, e.Total);
};
}
else
{
- result.SetResult(new MachineUpdateResult()
+ OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
- });
+ }, result, update_response, null, backupsFolder, localDataSource);
}
}
catch (Exception ex)
{
- LogManager.Log(ex, "An error occurred in machine update.");
-
- if (performDatabaseRollback)
- {
- LogManager.Log("Rolling back database changes...");
-
- using (DbManager db = DbManager.FromDataSource(localDataSource))
- {
- 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
- {
- try
- {
- File.Delete(dbBackupFile);
- }
- catch { }
- }
- }
- }
-
- result.SetException(ex);
- }
- finally
- {
- try
- {
- File.Delete(dbBackupFile);
- }
- catch { }
+ OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder);
}
return await result.Task;
}
/// <summary>
- /// Checks if any update are available for the specified machine serial number.
+ /// Checks if any update are available for the specified machine.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
- public Task<CheckForUpdateResponse> CheckForUpdate(string serialNumber)
+ public Task<CheckForUpdateResponse> CheckForUpdate()
{
return Task.Factory.StartNew<CheckForUpdateResponse>(() =>
{
- var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress();
+ _isUpdating = true;
+
+ var machineServiceAddress = _settings.GetMachineServiceAddress();
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
- Login(serialNumber).GetAwaiter().GetResult();
+ String machineGuid = _machineProvider.Machine.Guid;
+
+ Login(machineGuid).GetAwaiter().GetResult();
LogManager.Log($"Checking if updates available...");
CheckForUpdateRequest request = new CheckForUpdateRequest();
- request.SerialNumber = serialNumber;
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;
@@ -400,6 +965,8 @@ namespace Tango.PPC.Common.MachineUpdate
LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}");
+ _isUpdating = false;
+
return update_response;
});
}
@@ -407,96 +974,145 @@ namespace Tango.PPC.Common.MachineUpdate
/// <summary>
/// Updates all the "overwrite-able" database tables.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
- public Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber)
+ public Task UpdateDB(DbCompareResult dbCompareResult)
{
+ _updateStartDate = DateTime.UtcNow;
+ _logs.Clear();
+
return Task.Factory.StartNew(() =>
{
- LogManager.Log("Starting database update...");
+ _isUpdating = true;
+ UpdateDBResponse update_response = null;
+ var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
+ bool performDatabaseRollback = false;
+ String dbBackupFile = null;
- UpdateProgress("Updating Database", "Initializing...");
+ try
+ {
+ LogManager.Log("Starting database update...");
- LogManager.Log("Looking for update scripts configuration on application path...");
+ if (_machineProvider.MachineOperator.IsPrinting)
+ {
+ throw LogManager.Log(new InvalidOperationException($"Could not perform a database update while the machine is dyeing."));
+ }
- String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml");
+ UpdateProgress("Updating Database", "Initializing...");
- if (!File.Exists(config_file))
- {
- throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder."));
- }
+ LogManager.Log("Looking for update scripts configuration on application path...");
- UpdateDBResponse update_response = dbCompareResult.UpdateDBResponse;
+ String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml");
- var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
+ if (!File.Exists(config_file))
+ {
+ throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder."));
+ }
- LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
+ update_response = dbCompareResult.UpdateDBResponse;
- UpdateProgress("Updating Database", "Initializing update sequence...");
+ LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
- ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file);
+ UpdateProgress("Updating Database", "Initializing update sequence...");
- 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}...'");
+ ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file);
- ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName));
- builder.SetSource(update_response.DataSource);
- builder.SetTarget(localDataSource);
+ UpdateProgress("Updating Database", "Connecting to local database...");
+ LogManager.Log("Initializing database manager...");
+ DbManager db = DbManager.FromDataSource(localDataSource);
- if (item.RequiresSerialNumber)
+ LogManager.Log("Checking Tango database exists on the local machine...");
+ if (!db.Exists(localDataSource.Catalog))
{
- builder.SetMachineSerialNumber(serialNumber);
+ throw new InvalidProgramException("Database tango does not exists.");
}
- builder.Synchronize();
-
- var config = builder.Build();
+ UpdateProgress("Updating Database", "Creating database backup...");
- ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema);
- process.Progress += (x, msg) =>
+ //Create Database Backup
+ try
{
- LogManager.Log(msg);
- };
+ 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.");
+ }
- try
+ 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))
{
- UpdateProgress("Updating Database", item.Name + "...");
+ LogManager.Log($"Executing update script '{item.FileName}...'");
- var result = process.Execute().Result;
+ ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName));
+ builder.SetSource(update_response.DataSource);
+ builder.SetTarget(localDataSource);
- if (result.ExitCode != ExaminerProcessExitCode.Success)
+ if (item.RequiresSerialNumber)
{
- throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'."));
+ builder.SetMachineSerialNumber(_machineProvider.Machine.Guid);
}
- LogManager.Log("Script executed successfully.");
- }
- catch (Exception ex)
- {
- throw LogManager.Log(ex, "Setup manager error while trying to update the database.");
+ 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.");
+ 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;
+ }
});
}
/// <summary>
/// Checks whether it is necessary to updates all the "overwrite-able" database tables.
/// </summary>
- /// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
- public Task<DbCompareResult> UpdateDBCheck(string serialNumber)
+ public Task<DbCompareResult> UpdateDBCheck()
{
return Task.Factory.StartNew<DbCompareResult>(() =>
{
- var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress();
+ var machineServiceAddress = _settings.GetMachineServiceAddress();
- LogManager.Log($"Checking if database update is required for serial number {serialNumber}...");
+ LogManager.Log($"Checking if database update is required...");
LogManager.Log("Looking for update scripts configuration on application path...");
@@ -509,10 +1125,11 @@ namespace Tango.PPC.Common.MachineUpdate
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
- Login(serialNumber).Wait();
+ Login(_machineProvider.Machine.Guid).Wait();
UpdateDBRequest request = new UpdateDBRequest();
- request.SerialNumber = serialNumber;
+ request.ApplicationVersion = _app_manager.Version.ToString();
+ request.FirmwareVersion = _app_manager.FirmwareVersion.ToString();
UpdateDBResponse update_response = null;
@@ -541,7 +1158,7 @@ namespace Tango.PPC.Common.MachineUpdate
if (item.RequiresSerialNumber)
{
- builder.SetMachineSerialNumber(serialNumber);
+ builder.SetMachineSerialNumber(_machineProvider.Machine.Guid);
}
var config = builder.Build();
@@ -580,12 +1197,18 @@ namespace Tango.PPC.Common.MachineUpdate
}
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,
@@ -599,31 +1222,373 @@ namespace Tango.PPC.Common.MachineUpdate
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns></returns>
- public Task<MachineUpdateResult> UpdateFromTUP(string fileName)
+ public async Task<MachineUpdateResult> UpdateFromTUP(string fileName, bool setupFirmware, bool setupFPGA)
{
- return Task.Factory.StartNew<MachineUpdateResult>(() =>
+ _updateStartDate = DateTime.UtcNow;
+ _logs.Clear();
+
+ TaskCompletionSource<MachineUpdateResult> result = new TaskCompletionSource<MachineUpdateResult>();
+
+ var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().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
{
- LogManager.Log($"Starting machine update from update package '{fileName}'...");
+ _isUpdating = true;
- //Create temporary folders for packages.
- var _newPackageTempFolder = TemporaryManager.CreateFolder();
- _newPackageTempFolder.Persist = true;
+ LogManager.Log($"Starting machine update (TUP) for serial number {serialNumber}...");
- LogManager.Log("Extracting downloaded zip file...");
- //Extract software package.
- ZipFile.ExtractToDirectory(fileName, _newPackageTempFolder);
+ //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);
- LogManager.Log("Update operation completed!");
+ //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.");
+ }
- return new MachineUpdateResult()
+ await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder);
+ }
+ catch (Exception ex)
{
- UpdatePackagePath = _newPackageTempFolder,
+ 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("Getting setup firmware/fpga directly from db..");
+
+ 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");
+
+ setupFirmware = bool.Parse(firmware);
+ setupFPGA = bool.Parse(fpga);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error getting new values of SETUP_FIRMWARE and SETUP_FPGA.");
+ }
+ }
+
+ //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, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo);
+ };
+ handler.Completed += (_, __) =>
+ {
+ UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
+ stream.Dispose();
+ OnCompleted(new MachineUpdateResult()
+ {
+ UpdatePackagePath = _newPackageTempFolder,
+ RequiresBinariesUpdate = replaceBinaries,
+ }, result, null, tempDbName, backupsFolder, localDataSource, publishInfo);
+ };
+ handler.Canceled += (_, __) =>
+ {
+ 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);
+ }
+
+ return await result.Task;
+ }
+
+ /// <summary>
+ /// Performs a firmware upgrade from the specified TFP file.
+ /// </summary>
+ /// <param name="fileName">Name of the file.</param>
+ /// <returns></returns>
+ /// <exception cref="InvalidOperationException">
+ /// Could not perform a firmware upgrade while the machine is not connected.
+ /// or
+ /// </exception>
+ public async Task UpdateFromTFP(String fileName)
+ {
+ _updateStartDate = DateTime.UtcNow;
+ _logs.Clear();
+
+ TaskCompletionSource<object> result = new TaskCompletionSource<object>();
+
+ String version = String.Empty;
+ Stream stream = null;
+
+ try
+ {
+ _isUpdating = true;
+
+ IMachineOperator op = _machineProvider.MachineOperator;
+
+ UpdateProgress("Updating Firmware", "Loading firmware package...");
+ stream = new FileStream(fileName, FileMode.Open);
+
+ var packageInfo = await op.GetFirmwarePackageInfo(stream);
+ stream.Position = 0;
+ version = packageInfo.FileDescriptors.FirstOrDefault(x => x.Destination == PMR.FirmwareUpgrade.VersionFileDestination.Mcu)?.Version;
+
+ LogManager.Log("Verifying machine connection and state...");
+
+ UpdateProgress("Verifying machine state", "Initializing...");
+
+ await Task.Delay(1000);
+
+ 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."));
+ }
+
+ UpdateProgress("Updating Firmware", "Connecting to firmware device...");
+ LogManager.Log("");
+ LogManager.Log("-------------------------------------------------------------------------");
+ LogManager.Log("Updating Firmware...");
+
+ op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE;
+
+ var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo);
+ handler.Failed += (_, ex) =>
+ {
+ 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)
+ {
+ stream.Dispose();
+ }
+ }
+ catch { }
+
+ OnFailed(ex, result, version);
+ }
+
+ await result.Task;
}
/// <summary>
@@ -631,25 +1596,88 @@ namespace Tango.PPC.Common.MachineUpdate
/// </summary>
/// <param name="filePath">The file path.</param>
/// <returns></returns>
- public Task<UpdatePackageFile> GetUpdatePackageFileInfo(string filePath)
+ public Task<PublishInfo> GetUpdatePackageFileInfo(string filePath)
{
- return Task.Factory.StartNew<UpdatePackageFile>(() =>
+ return Task.Factory.StartNew<PublishInfo>(() =>
{
- UpdatePackageFile file = new UpdatePackageFile();
- var tempFolder = TemporaryManager.CreateFolder();
-
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);
+ var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "version.json");
+ var reader = appEntry.OpenReader();
+
+ using (StreamReader stReader = new StreamReader(reader))
+ {
+ String json = stReader.ReadToEnd();
+ reader.Dispose();
+
+ return PublishInfo.FromJson(json);
+ }
}
+ });
+ }
+
+ /// <summary>
+ /// Checks whether any post update packages needs to be installed.
+ /// </summary>
+ /// <returns></returns>
+ public Task<bool> PostUpdatePackagesRequired()
+ {
+ String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages");
+ return _packageRunner.IsPackageInstallationRequired(PackageType.Post, packagesFolder);
+ }
+
+ /// <summary>
+ /// Runs all post update packages.
+ /// </summary>
+ /// <returns></returns>
+ public Task<PackageRunnerResult> RunPostUpdatePackages()
+ {
+ String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages");
- FileVersionInfo info = FileVersionInfo.GetVersionInfo(Path.Combine(tempFolder, "Tango.PPC.UI.exe"));
- file.Version = Version.Parse(info.ProductVersion);
+ Version previousVersion = null;
+ String str = _settings.PreviousApplicationVersion;
- tempFolder.Delete();
+ if (Version.TryParse(str, out previousVersion))
+ {
+ return _packageRunner.Run(PackageType.Post, previousVersion, packagesFolder);
+ }
+ else
+ {
+ throw new InvalidCastException($"Error parsing the previous version string '{str}'.");
+ }
+ }
- return file;
+ public Task RestoreLastDatabaseBackup()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ LogManager.Log("Rolling back database changes...");
+ UpdateProgress("Rollback", "Rolling back database changes...");
+
+ var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
+ var lastBackupFile = SettingsManager.Default.GetOrCreate<PPCSettings>().LastDatabaseBackupFile;
+
+ 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.
/// </summary>
public String UpdatePackagePath { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the application should replace it's binaries.
+ /// </summary>
+ public bool RequiresBinariesUpdate { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MachineUpdateResult"/> class.
+ /// </summary>
+ public MachineUpdateResult()
+ {
+ RequiresBinariesUpdate = true;
+ }
}
}
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; }
+
/// <summary>
/// Gets or sets the brush stops.
/// </summary>
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
@@ -13,6 +13,11 @@ namespace Tango.PPC.Common.Navigation
public interface INavigationManager
{
/// <summary>
+ /// Occurs when the current view model has changed.
+ /// </summary>
+ event EventHandler<PPCViewModel> CurrentVMChanged;
+
+ /// <summary>
/// Gets the current module.
/// </summary>
IPPCModule CurrentModule { get; }
@@ -28,6 +33,16 @@ namespace Tango.PPC.Common.Navigation
bool CanNavigateBack { get; }
/// <summary>
+ /// Gets a value indicating whether the back should be enabled.
+ /// </summary>
+ bool IsBackEnabled { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the navigation system is currently navigating.
+ /// </summary>
+ bool IsNavigating { get; set; }
+
+ /// <summary>
/// Navigates to the previous view if <see cref="CanNavigateBack"/> is true.
/// </summary>
Task<bool> NavigateBack();
@@ -79,7 +94,7 @@ namespace Tango.PPC.Common.Navigation
/// Navigates to the specified module and view by full path (e.g Jobs.JobsView).
/// </summary>
/// <param name="fullPath">The full path.</param>
- Task<bool> NavigateTo(String fullPath, bool pushToHistory = true);
+ Task<bool> NavigateTo(String fullPath, bool pushToHistory = true, Action<PPCViewModel, PPCViewModel> onNavigating = null, Action<PPCViewModel, PPCViewModel> onNavigated = null);
/// <summary>
/// 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
/// </summary>
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;
@@ -23,19 +24,24 @@ namespace Tango.PPC.Common.Notifications
ObservableCollection<NotificationItem> NotificationItems { get; }
/// <summary>
+ /// Gets the notification items view.
+ /// </summary>
+ ICollectionView NotificationItemsView { get; }
+
+ /// <summary>
/// Gets the collection of taskbar items.
/// </summary>
ObservableCollection<TaskBarItem> TaskBarItems { get; }
/// <summary>
- /// Gets the current application bar item.
+ /// Gets the application bar items.
/// </summary>
- AppBarItem CurrentAppBarItem { get; }
+ ObservableCollection<AppBarItem> AppBarItems { get; }
/// <summary>
- /// Gets a value indicating whether this instance has application bar item.
+ /// Gets a value indicating whether this instance has any application bar items.
/// </summary>
- bool HasAppBarItem { get; }
+ bool HasAppBarItems { get; }
/// <summary>
/// Gets a value indicating whether this instance has notification items.
@@ -176,7 +182,7 @@ namespace Tango.PPC.Common.Notifications
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
- AppBarItem PushAppBarItem<T>() where T : AppBarItem;
+ T PushAppBarItem<T>() where T : AppBarItem;
/// <summary>
/// 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
/// </summary>
public abstract class NotificationItem : ItemBase
{
- /// <summary>
- /// Initializes a new instance of the <see cref="NotificationItem"/> class.
- /// </summary>
- public NotificationItem() : base()
+ public enum NotificationPriority
{
- CanClose = true;
+ Low,
+ Normal,
+ High,
+ VeryHigh,
+ Critical,
}
- private bool _isExpanded;
/// <summary>
- /// Gets or sets a value indicating whether the notification panel is expanded.
+ /// Initializes a new instance of the <see cref="NotificationItem"/> class.
/// </summary>
- public bool IsExpanded
+ public NotificationItem() : base()
{
- get { return _isExpanded; }
- set { _isExpanded = value; RaisePropertyChangedAuto(); }
+ CanClose = true;
+ Priority = NotificationPriority.Normal;
}
private bool _canClose;
@@ -43,6 +43,11 @@ namespace Tango.PPC.Common.Notifications
}
/// <summary>
+ /// Gets or sets the notification priority.
+ /// </summary>
+ public NotificationPriority Priority { get; set; }
+
+ /// <summary>
/// Called when the item has been pressed.
/// </summary>
protected override void OnPreesed()
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
/// <param name="expandedMessage">The expanded message.</param>
/// <param name="type">The type.</param>
/// <param name="pressedAction">The pressed action.</param>
- 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 @@
</touch:TouchIcon.Style>
</touch:TouchIcon>
- <StackPanel Margin="10 0 0 0" VerticalAlignment="Center">
- <TextBlock Text="{Binding Message}" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Foreground="Black" VerticalAlignment="Center"></TextBlock>
+ <StackPanel Margin="10 5 40 5" VerticalAlignment="Center">
+ <TextBlock Text="{Binding Message}" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Foreground="Black" VerticalAlignment="Center" ></TextBlock>
- <Canvas Margin="0 5 0 0">
- <TextBlock Foreground="{StaticResource TangoDarkForegroundBrush}" Text="{Binding ExpandedMessage}" TextWrapping="Wrap" VerticalAlignment="Center">
- <TextBlock.Opacity>
+
+ <TextBlock Margin="0 5 0 0" Foreground="{StaticResource TangoDarkForegroundBrush}" Text="{Binding ExpandedMessage}" FontSize="{StaticResource TangoSmallFontSize}" TextWrapping="Wrap" VerticalAlignment="Center" >
+ <!--<TextBlock.Opacity>
<MultiBinding Converter="{StaticResource heightToOpacityConverter}">
<Binding Path="ActualHeight" ElementName="MessageNotificationItemControl" />
<Binding Path="MinHeight" ElementName="MessageNotificationItemControl" />
<Binding Path="MaxHeight" ElementName="MessageNotificationItemControl" />
</MultiBinding>
- </TextBlock.Opacity>
+ </TextBlock.Opacity>-->
</TextBlock>
- </Canvas>
+
</StackPanel>
</DockPanel>
</ContentControl>
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;
});
}
+
+ /// <summary>
+ /// Sets the device host name.
+ /// </summary>
+ /// <returns></returns>
+ public async Task SetDeviceName(String name)
+ {
+ var command = new CmdCommand("wmic", $"computersystem where caption='{Environment.MachineName}' rename '{name}'");
+ await command.Run();
+ }
+
+ /// <summary>
+ /// Opens the operating system shell (explorer).
+ /// </summary>
+ 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
@@ -57,6 +57,12 @@ namespace Tango.PPC.Common.OS
Task<String> GetDeviceName();
/// <summary>
+ /// Sets the device host name.
+ /// </summary>
+ /// <returns></returns>
+ Task SetDeviceName(String name);
+
+ /// <summary>
/// Restarts the system.
/// </summary>
/// <returns></returns>
@@ -67,5 +73,10 @@ namespace Tango.PPC.Common.OS
/// </summary>
/// <returns></returns>
void Shutdown();
+
+ /// <summary>
+ /// Opens the operating system shell (explorer).
+ /// </summary>
+ 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
@@ -18,11 +22,6 @@ namespace Tango.PPC.Common
public class PPCSettings : SettingsBase
{
/// <summary>
- /// Gets or sets the logging categories.
- /// </summary>
- public List<LogCategory> LoggingCategories { get; set; }
-
- /// <summary>
/// Gets or sets the state of the application.
/// </summary>
public ApplicationStates ApplicationState { get; set; }
@@ -138,6 +137,157 @@ namespace Tango.PPC.Common
public bool EnableJobLiquidQuantityValidation { get; set; }
/// <summary>
+ /// Gets or sets the job number of units method.
+ /// </summary>
+ public JobUnitsMethods JobUnitsMethod { get; set; }
+
+ /// <summary>
+ /// Gets or sets the loaded RML unique identifier.
+ /// </summary>
+ public String LoadedRmlGuid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default RML unique identifier.
+ /// </summary>
+ public String DefaultRmlGuid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default color space unique identifier.
+ /// </summary>
+ public List<ColorSpaces> SupportedColorSpaces { get; set; }
+
+ /// <summary>
+ /// Gets or sets the target job types.
+ /// </summary>
+ public List<JobTypes> SupportedJobTypes { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default spool type unique identifier.
+ /// </summary>
+ public String DefaultSpoolTypeGuid { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default length of the segment.
+ /// </summary>
+ public int DefaultSegmentLength { get; set; }
+
+ /// <summary>
+ /// Gets or sets the previous application version.
+ /// </summary>
+ public String PreviousApplicationVersion { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether synchronize jobs with twine server.
+ /// </summary>
+ public bool SynchronizeJobs { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether synchronize diagnostics data.
+ /// </summary>
+ public bool SynchronizeDiagnostics { get; set; }
+
+ /// <summary>
+ /// Gets or sets the synchronization interval.
+ /// </summary>
+ public TimeSpan SynchronizationInterval { get; set; }
+
+ /// <summary>
+ /// Gets or sets the known firmware version.
+ /// </summary>
+ public String FirmwareVersion { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to display the power up screen.
+ /// </summary>
+ public bool DisplayPowerUpScreen { get; set; }
+
+ /// <summary>
+ /// Gets or sets the power up screen timeout.
+ /// </summary>
+ public TimeSpan PowerUpScreenTimeout { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to automatically check for software and database (quick) updates.
+ /// </summary>
+ public bool AutoCheckForUpdates { get; set; }
+
+ /// <summary>
+ /// Gets or sets the automatic update check interval.
+ /// </summary>
+ public TimeSpan AutoUpdateCheckInterval { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable the automatic thread loading support.
+ /// </summary>
+ public bool EnableAutomaticThreadLoading { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to display the thread loading screen.
+ /// </summary>
+ public bool DisplayAutomaticThreadLoadingScreen { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable embedded debug logs.
+ /// </summary>
+ public bool EnableEmbeddedDebugLogs { get; set; }
+
+ /// <summary>
+ /// Gets or sets the TCP transport adapter write mode.
+ /// </summary>
+ public TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to expose the external bridge service via SignalR.
+ /// </summary>
+ public bool EnableExternalBridgeSignalR { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the exteral bridge SignalR hub.
+ /// </summary>
+ public String ExternalBridgeSignalRHub { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable the internal remote desktop service.
+ /// </summary>
+ public bool EnableRemoteDesktop { get; set; }
+
+ /// <summary>
+ /// Gets or sets the internal remote desktop service frame rate (1-20).
+ /// </summary>
+ public int RemoteDesktopFrameRate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to enable insights.
+ /// </summary>
+ public bool InsightsEnabled { get; set; }
+
+ /// <summary>
+ /// Gets or sets the insights sampling interval.
+ /// </summary>
+ public TimeSpan InsightsSamplingInterval { get; set; }
+
+ /// <summary>
+ /// Gets or sets the insights storage cleanup interval.
+ /// </summary>
+ public TimeSpan InsightsStorageCleanupInterval { get; set; }
+
+ /// <summary>
+ /// Gets or sets the duration of the insights maximum storage duration.
+ /// </summary>
+ public TimeSpan InsightsMaxStorageDuration { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to bypass Internet connectivity checks before attempting to perform an update for example.
+ /// </summary>
+ public bool BypassInternetConnectivityCheck { get; set; }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public String LastDatabaseBackupFile { get; set; }
+
+ /// <summary>
/// Gets the machine service address.
/// </summary>
/// <returns></returns>
@@ -155,18 +305,44 @@ namespace Tango.PPC.Common
EnableGradientGeneration = true;
GradientGenerationResolution = 20;
MachineScanningTimeoutSeconds = 20;
- LoggingCategories = new List<LogCategory>();
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<ColorSpaces>();
+ SupportedJobTypes = new List<JobTypes>();
+ 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.
/// </summary>
/// <seealso cref="Tango.SharedUI.ViewModel" />
- public abstract class PPCViewModel : ViewModel, INavigationViewModel, INavigationBlocker
+ public abstract class PPCViewModel : ViewModel, INavigationBlocker
{
/// <summary>
/// Gets the static observable entities adapter.
@@ -109,6 +112,24 @@ namespace Tango.PPC.Common
[TangoInject]
public IEventLogger EventLogger { get; set; }
+ /// <summary>
+ /// Gets or sets the machine data synchronizer.
+ /// </summary>
+ [TangoInject]
+ public IMachineDataSynchronizer MachineDataSynchronizer { get; set; }
+
+ /// <summary>
+ /// Gets or sets the remote desktop service.
+ /// </summary>
+ [TangoInject]
+ public IRemoteDesktopService RemoteDesktopService { get; set; }
+
+ /// <summary>
+ /// Gets or sets the thread loading service.
+ /// </summary>
+ [TangoInject]
+ public IThreadLoadingService ThreadLoadingService { get; set; }
+
private PPCSettings _settings;
/// <summary>
/// Gets the main PPC settings.
@@ -159,6 +180,15 @@ namespace Tango.PPC.Common
}
/// <summary>
+ /// Called when the navigation system has navigated to this VM view.
+ /// </summary>
+ /// <param name="fromVM">The view model instance of the previous view model</param>
+ public virtual void OnNavigatedTo(PPCViewModel fromVM)
+ {
+
+ }
+
+ /// <summary>
/// Called when the navigation system has navigated from this VM view.
/// </summary>
public virtual void OnNavigatedFrom()
@@ -167,6 +197,22 @@ namespace Tango.PPC.Common
}
/// <summary>
+ /// Called before the navigation system has navigated to this VM view.
+ /// </summary>
+ public virtual void OnBeforeNavigatedTo()
+ {
+
+ }
+
+ /// <summary>
+ /// Called before the navigation system has navigated from this VM view.
+ /// </summary>
+ public virtual void OnBeforeNavigatedFrom()
+ {
+ IsVisible = false;
+ }
+
+ /// <summary>
/// Raises the specified message using the default <see cref="TangoMessenger"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
@@ -220,7 +266,7 @@ namespace Tango.PPC.Common
/// </summary>
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<PerformanceClient> _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<PerformanceClient>();
+ 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;
}
}
+
+ /// <summary>
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ /// </summary>
+ internal static System.Drawing.Bitmap finger3 {
+ get {
+ object obj = ResourceManager.GetObject("finger3", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ /// </summary>
+ 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.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
@@ -68,9 +69,10 @@
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
@@ -85,9 +87,10 @@
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
@@ -109,9 +112,16 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="finger3" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>..\Resources\finger3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
+ <data name="tap" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>..\Resources\tap.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
</root> \ 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.
/// </summary>
/// <returns></returns>
- public async Task<String> GetRemoteVersion(String machineVersionGuid)
+ public async Task<LatestVersionResponse> 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;
}
/// <summary>
@@ -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, "/");
@@ -404,6 +469,16 @@ namespace Tango.PPC.Common.Publish
}
/// <summary>
+ /// Gets the MCU version from the specified TFP file.
+ /// </summary>
+ /// <param name="tfpFile">The TFP file.</param>
+ /// <returns></returns>
+ public String GetLocalFirmwareVersion(String tfpFile)
+ {
+ return GetVersionInfoFromTFP(tfpFile).GetMcuVersion().ToString();
+ }
+
+ /// <summary>
/// Raises the publish progress event.
/// </summary>
/// <param name="progress">The progress.</param>
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<PublishInfo>(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.
/// </summary>
/// <param name="machineSerialNumber">The machine serial number.</param>
+ /// <param name="group">The remote assistance group.</param>
+ /// <param name="environment">The machine working environment.</param>
/// <returns></returns>
- public async Task InstallRemoteAssistance(String machineSerialNumber)
+ /// <exception cref="FileNotFoundException"></exception>
+ /// <exception cref="ApplicationException">The remote assistance service was installed but could not be found.</exception>
+ 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.
/// </summary>
/// <param name="machineSerialNumber">The machine serial number.</param>
+ /// <param name="group">The remote assistance group.</param>
+ /// <param name="environment">The machine working environment.</param>
/// <returns></returns>
- 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<RemoteDesktopClient> _clients;
+ private JsonSerializerSettings _jsonSettings;
+ private IOperationSystemManager _osManager;
+ private IPPCApplicationManager _appManager;
+ private bool _drawCursor;
+ private bool _isMouseDown;
+ private bool _ensureMouseDown;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="IPPCService" /> is enabled.
+ /// </summary>
+ public bool Enabled { get; set; } = true;
+
+ private bool _isStarted;
+ /// <summary>
+ /// Gets a value indicating whether the remote desktop service has started.
+ /// </summary>
+ public bool IsStarted
+ {
+ get { return _isStarted; }
+ private set { _isStarted = value; RaisePropertyChangedAuto(); }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether there is any active remote desktop session with a remote peer.
+ /// </summary>
+ public bool InSession
+ {
+ get
+ {
+ return _clients.Count > 0;
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DefaultRemoteDesktopService"/> class.
+ /// </summary>
+ /// <param name="applicationManager">The application manager.</param>
+ /// <param name="externalBridge">The external bridge.</param>
+ /// <param name="osManager">The os manager.</param>
+ public DefaultRemoteDesktopService(IPPCApplicationManager applicationManager, IPPCExternalBridgeService externalBridge, IOperationSystemManager osManager)
+ {
+ _osManager = osManager;
+ _appManager = applicationManager;
+
+ _jsonSettings = new JsonSerializerSettings()
+ {
+ TypeNameHandling = TypeNameHandling.All
+ };
+
+ _settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ Enabled = _settings.EnableRemoteDesktop;
+
+ applicationManager.ApplicationReady += ApplicationManager_ApplicationReady;
+
+ externalBridge.RegisterRequestHandler(this);
+
+ _clients = new List<RemoteDesktopClient>();
+ _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<WebRtcIceCandidateRequest, WebRtcIceCandidateResponse>(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<JpegEncoder>().ToArray(80);
+ frame.Dispose();
+
+ await receiver.SendGenericResponse(new GetScreenshotResponse() { Bitmap = data }, token);
+ }
+
+ private async void _engine_FrameReceived(object sender, ScreenCaptureFrameReceivedEventArgs<RasterFrame> 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<PngEncoder>().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<JpegEncoder>().ToArray(30),
+ MousePosition = mousePosition,
+ CursorVisible = _drawCursor
+ };
+ }
+ else
+ {
+ var diffFrame = e.Frame.ToDifference();
+ diffFrame = diffFrame.OptimizeBounds();
+
+ packet = new RemoteDesktopPacket()
+ {
+ Bitmap = diffFrame.ToEncoder<PngEncoder>().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<string> 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
+{
+ /// <summary>
+ /// Represents a PPC remote desktop service.
+ /// </summary>
+ public interface IRemoteDesktopService : IPPCService
+ {
+ /// <summary>
+ /// Gets a value indicating whether the remote desktop service has started.
+ /// </summary>
+ bool IsStarted { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether there is any active remote desktop session with a remote peer.
+ /// </summary>
+ 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<RunningJobUpdateClient> _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<RunningJobUpdateClient>();
+ 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">
+ <BitmapImage x:Key="TangoImageLubricant" UriSource="../Images/lubricant2.png" />
+ <BitmapImage x:Key="TangoImageCleaner" UriSource="../Images/cl-full.png" />
+ <SolidColorBrush x:Key="TangoBlackInkBrush" Color="Black" />
+ <SolidColorBrush x:Key="TangoMagentaInkBrush" Color="#ED008C" />
+ <SolidColorBrush x:Key="TangoCyanInkBrush" Color="#1662EB" />
+ <SolidColorBrush x:Key="TangoYellowInkBrush" Color="#E8FF0C" />
+ <SolidColorBrush x:Key="TangoWasteBrush" Color="#2BA221" />
+ <SolidColorBrush x:Key="TangoTransparentInkBrush" Color="#E9E9E9" />
+ <SolidColorBrush x:Key="TangoLubricantBrush" Color="#DEDAC4" />
+ <SolidColorBrush x:Key="TangoCleanerBrush" Color="#8BEC83" />
+
</ResourceDictionary> \ 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 @@
<ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Resources/Fonts.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Resources/Styles.xaml"/>
+ <!--PPC Controls-->
+ <ResourceDictionary Source="pack://application:,,,/Tango.PPC.Common;component/Controls/ImageGalleryControl.xaml"/>
+
<!--Converters-->
</ResourceDictionary.MergedDictionaries>
@@ -51,6 +54,13 @@
<converters:StringToLinesConverter x:Key="StringToLinesConverter" />
<converters:ColorToIntegerConverter x:Key="ColorToIntegerConverter" />
<converters:StringEllipsisConverter x:Key="StringEllipsisConverter" />
+ <converters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter" />
+ <converters:TimeSpanToMinutesConverter x:Key="TimeSpanToMinutesConverter" />
+ <converters:TimeSpanToSecondsConverter x:Key="TimeSpanToSecondsConverter" />
+ <converters:TimeSpanToDaysConverter x:Key="TimeSpanToDaysConverter" />
+ <converters:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter" />
+ <converters:IsEqualToVisibilityConverter x:Key="IsEqualToVisibilityConverter" />
+ <converters:IsToStringEqualToVisibilityConverter x:Key="IsToStringEqualToVisibilityConverter" />
<Style TargetType="FrameworkElement">
<Setter Property="TextElement.FontFamily" Value="{StaticResource TangoFlexoFontFamily}"></Setter>
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Styles.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Styles.xaml
index 426372688..317b2f13f 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Styles.xaml
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Styles.xaml
@@ -44,4 +44,69 @@
<Setter Property="ItemContainerStyle" Value="{StaticResource BlankListBoxItem}"></Setter>
</Style>
+ <Style TargetType="touch:TouchSimpleDataGrid" x:Key="TechGrid" BasedOn="{StaticResource {x:Type touch:TouchSimpleDataGrid}}">
+ <Style.Resources>
+ <Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
+ <Setter Property="Background" Value="{StaticResource TangoDarkForegroundBrush}" />
+ <Setter Property="Foreground" Value="{StaticResource TangoLightForegroundBrush}" />
+ <Setter Property="Padding" Value="5"></Setter>
+ </Style>
+ </Style.Resources>
+ <Setter Property="RowStyle">
+ <Setter.Value>
+ <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ <Trigger Property="IsFocused" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="CellStyle">
+ <Setter.Value>
+ <Style TargetType="{x:Type DataGridCell}">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type DataGridCell}">
+ <Grid Background="{TemplateBinding Background}">
+ <ContentPresenter VerticalAlignment="Center" />
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ <Style.Triggers>
+ <Trigger Property="IsSelected" Value="True">
+ <Setter Property="Background" Value="Transparent"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}" />
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </Setter.Value>
+ </Setter>
+
+ <Setter Property="Background" Value="{StaticResource TangoPrimaryBackgroundBrush}"></Setter>
+ <Setter Property="AutoGenerateColumns" Value="False"></Setter>
+ <Setter Property="SelectionUnit" Value="FullRow"></Setter>
+ <Setter Property="SelectionMode" Value="Single"></Setter>
+ <Setter Property="BorderBrush" Value="{StaticResource TangoDarkForegroundBrush}"></Setter>
+ <Setter Property="BorderThickness" Value="1"></Setter>
+ <Setter Property="HeadersVisibility" Value="Column"></Setter>
+ <Setter Property="CanUserAddRows" Value="True"></Setter>
+ <Setter Property="CanUserDeleteRows" Value="False"></Setter>
+ <Setter Property="CanUserReorderColumns" Value="False"></Setter>
+ <Setter Property="CanUserResizeColumns" Value="False"></Setter>
+ <Setter Property="CanUserSortColumns" Value="False"></Setter>
+ <Setter Property="IsReadOnly" Value="True"></Setter>
+ <Setter Property="VerticalGridLinesBrush" Value="{x:Null}"></Setter>
+ <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource TangoGrayBrush}"></Setter>
+ <Setter Property="RowHeight" Value="50"></Setter>
+ <Setter Property="VerticalScrollBarVisibility" Value="Visible"></Setter>
+ <Setter Property="HorizontalScrollBarVisibility" Value="Disabled"></Setter>
+ </Style>
</ResourceDictionary> \ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/finger3.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/tap.png
Binary files 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<String, Action<ExplorerFileItem>> _fileHandlers;
+ private Dictionary<String, Action<List<ExplorerFileItem>>> _fileHandlers;
/// <summary>
/// Occurs when a new storage drive has been inserted.
@@ -58,7 +58,7 @@ namespace Tango.PPC.Common.Storage
/// </summary>
public DefaultStorageProvider(IPPCApplicationManager applicationManager)
{
- _fileHandlers = new Dictionary<string, Action<ExplorerFileItem>>();
+ _fileHandlers = new Dictionary<string, Action<List<ExplorerFileItem>>>();
var drives = DriveInfo.GetDrives().Where(x => x.DriveType == DriveType.Removable).ToList();
if (drives.Count > 0)
@@ -86,7 +86,7 @@ namespace Tango.PPC.Common.Storage
/// <param name="extension">The file extension.</param>
/// <param name="handler">The handler.</param>
/// <exception cref="System.InvalidOperationException">Cannot register multiple file handlers for the same extension.</exception>
- public void RegisterFileHandler(string extension, Action<ExplorerFileItem> handler)
+ public void RegisterFileHandler(string extension, Action<List<ExplorerFileItem>> handler)
{
if (_fileHandlers.ContainsKey(extension))
{
@@ -99,7 +99,7 @@ namespace Tango.PPC.Common.Storage
/// Unregisters the file handler.
/// </summary>
/// <param name="handler">The handler.</param>
- public void UnregisterFileHandler(Action<ExplorerFileItem> handler)
+ public void UnregisterFileHandler(Action<List<ExplorerFileItem>> handler)
{
var h = _fileHandlers.SingleOrDefault(x => x.Value == handler);
@@ -112,14 +112,17 @@ namespace Tango.PPC.Common.Storage
/// <summary>
/// Submits a file selection.
/// </summary>
- /// <param name="fileItem">The file item.</param>
- public void SubmitFileSelection(ExplorerFileItem fileItem)
+ /// <param name="fileItems">The file item.</param>
+ public void SubmitFileSelection(List<ExplorerFileItem> 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
/// </summary>
/// <param name="extension">The file extension.</param>
/// <param name="handler">The handler.</param>
- void RegisterFileHandler(String extension, Action<ExplorerFileItem> handler);
+ void RegisterFileHandler(String extension, Action<List<ExplorerFileItem>> handler);
/// <summary>
/// Unregisters the file handler.
/// </summary>
/// <param name="handler">The handler.</param>
- void UnregisterFileHandler(Action<ExplorerFileItem> handler);
+ void UnregisterFileHandler(Action<List<ExplorerFileItem>> handler);
/// <summary>
/// Submits a file selection.
/// </summary>
/// <param name="fileItem">The file item.</param>
- void SubmitFileSelection(ExplorerFileItem fileItem);
+ void SubmitFileSelection(List<ExplorerFileItem> 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<LogItemBase> _logs;
+ private bool _synchronizedOnce;
+
+ [TangoInject(TangoInjectMode.WhenAvailable)]
+ private IPPCApplicationManager _appManager;
+
+ public event EventHandler<SynchronizationStatusChangedEventArgs> CurrentStatusChanged;
+ public event EventHandler SynchronizationStarted;
+ public event EventHandler<SynchronizationEndedEventArgs> 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<SynchronizationStatus> 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<SynchronizationStatus>();
+
+ MaxJobs = 10;
+ MaxJobRuns = 10;
+ MaxMachinesEvents = 10;
+ MaxOfflineUpdates = 10;
+ MaxDataStoreItems = 100;
+
+ var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ 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<LogItemBase>();
+ _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<UploadMachineDataRequest> 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<JobDTO> dtos = new List<JobDTO>();
+
+ 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<JobRunDTO> dtos = new List<JobRunDTO>();
+
+ 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<MachinesEventDTO> dtos = new List<MachinesEventDTO>();
+
+ 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<TangoUpdateDTO> dtos = new List<TangoUpdateDTO>();
+
+ 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<DataStoreItemDTO> dtos = new List<DataStoreItemDTO>();
+
+ 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<DownloadMachineDataResponse> 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<NotifyMachineDataDownloadCompletedRequest> 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<PPCSettings>();
+
+ 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<SynchronizationEndedEventArgs> SynchronizationEnded;
+ event EventHandler<SynchronizationStatusChangedEventArgs> CurrentStatusChanged;
+ int MaxJobs { get; set; }
+ int MaxJobRuns { get; set; }
+ int MaxMachinesEvents { get; set; }
+ SynchronizationStatus CurrentStatus { get; }
+ SynchronizationStatus LastStatus { get; }
+ SynchronizedObservableCollection<SynchronizationStatus> 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<SystemObjectsCollection> _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<SystemObjectsCollection>();
+
+ 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<PPCSettings>();
+
+ var applicationCollection = new SystemObjectsCollection();
+ applicationCollection.Name = "Application";
+ system.Insert(0, applicationCollection);
+
+ //Application.
+ applicationCollection.Objects.Add(new SystemObject()
+ {
+ Name = "Tango PPC",
+ Properties = new List<SystemObjectProperty>()
+ {
+ 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<SystemObjectProperty>()
+ {
+ 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<SystemObjectProperty>()
+ {
+ 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
+{
+ /// <summary>
+ /// Represents a PPC system information service.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.IPPCService" />
+ 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 @@
<Reference Include="Microsoft.Azure.Common.NetFramework, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Azure.ResourceManager, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.SqlServer.AzureStorageEnum, Version=14.100.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualBasic" />
+ <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.WindowsAPICodePack-Core.1.1.0.0\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
+ </Reference>
<Reference Include="Microsoft.WindowsAzure.Storage, Version=4.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
@@ -120,7 +124,15 @@
<Link>GlobalVersionInfo.cs</Link>
</Compile>
<Compile Include="ApplicationStates.cs" />
- <Compile Include="Backup\IBackupManager.cs" />
+ <Compile Include="BackupRestore\BackupMode.cs" />
+ <Compile Include="BackupRestore\BackupRestoreProgressEventArgs.cs" />
+ <Compile Include="BackupRestore\BackupFile.cs" />
+ <Compile Include="BackupRestore\BackupSettings.cs" />
+ <Compile Include="BackupRestore\BackupRestoreStage.cs" />
+ <Compile Include="BackupRestore\DefaultBackupManager.cs" />
+ <Compile Include="BackupRestore\IBackupManager.cs" />
+ <Compile Include="BackupRestore\RestoreResult.cs" />
+ <Compile Include="BackupRestore\RestoreSettings.cs" />
<Compile Include="Connection\DefaultMachineProvider.cs" />
<Compile Include="Connection\IMachineProvider.cs" />
<Compile Include="Connection\MachineOperatorChangedEventArgs.cs" />
@@ -131,23 +143,66 @@
<Compile Include="Connectivity\WiFiAuthentication.cs" />
<Compile Include="Connectivity\WiFiNetwork.cs" />
<Compile Include="Connectivity\IConnectivityProvider.cs" />
+ <Compile Include="Console\DefaultConsoleEngineService.cs" />
+ <Compile Include="Console\IConsoleEngineService.cs" />
<Compile Include="Controls\AsyncAdornerControl.cs" />
+ <Compile Include="Controls\ImageGalleryControl.cs" />
<Compile Include="Controls\TwineCatalogControl.xaml.cs">
<DependentUpon>TwineCatalogControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\TwineCatalogRenderer.cs" />
<Compile Include="Converters\HeightToOpacityConverter.cs" />
+ <Compile Include="DataStore\DefaultDataStoreService.cs" />
+ <Compile Include="DataStore\IDataStoreService.cs" />
<Compile Include="ExtensionMethods\IListExtensions.cs" />
<Compile Include="ExtensionMethods\ObservableCollectionExtensions.cs" />
<Compile Include="ExternalBridge\IPPCExternalBridgeService.cs" />
<Compile Include="ExternalBridge\PPCExternalBridgeService.cs" />
+ <Compile Include="FileSystem\DefaultFileSystemService.cs" />
+ <Compile Include="FileSystem\FileSystemOperation.cs" />
+ <Compile Include="FileSystem\FileSystemOperationMode.cs" />
+ <Compile Include="FileSystem\IFileSystemService.cs" />
+ <Compile Include="Helpers\KeyboardHelper.cs" />
+ <Compile Include="Helpers\LogsHelper.cs" />
<Compile Include="HotSpot\DefaultHotSpotProvider.cs" />
<Compile Include="HotSpot\IHotSpotProvider.cs" />
+ <Compile Include="Insights\DefaultInsightsService.cs" />
+ <Compile Include="Insights\IInsightsService.cs" />
<Compile Include="IPPCView.cs" />
+ <Compile Include="IPPCService.cs" />
<Compile Include="MachineSetup\IMachineSetupManager.cs" />
<Compile Include="MachineSetup\MachineSetupManager.cs" />
<Compile Include="MachineSetup\MachineSetupProgress.cs" />
<Compile Include="MachineSetup\MachineSetupResult.cs" />
+ <Compile Include="Notifications\AppBarPriority.cs" />
+ <Compile Include="Performance\DefaultPerformanceService.cs" />
+ <Compile Include="Performance\IPerformanceService.cs" />
+ <Compile Include="RemoteDesktop\DefaultRemoteDesktopService.cs" />
+ <Compile Include="RemoteDesktop\IRemoteDesktopService.cs" />
+ <Compile Include="RemoteDesktop\RemoteDesktopClient.cs" />
+ <Compile Include="RemoteJob\DefaultRemoteJobService.cs" />
+ <Compile Include="RemoteJob\IRemoteJobService.cs" />
+ <Compile Include="RemoteActions\IRemoteActionsService.cs" />
+ <Compile Include="SQL\DefaultRemoteSqlService.cs" />
+ <Compile Include="SQL\IRemoteSqlService.cs" />
+ <Compile Include="Synchronization\DefaultMachineDataSynchronizer.cs" />
+ <Compile Include="Synchronization\IMachineDataSynchronizer.cs" />
+ <Compile Include="Synchronization\SynchronizationEndedEventArgs.cs" />
+ <Compile Include="Synchronization\SynchronizationState.cs" />
+ <Compile Include="Synchronization\SynchronizationStatus.cs" />
+ <Compile Include="Synchronization\SynchronizationStatusChangedEventArgs.cs" />
+ <Compile Include="SystemInfo\DefaultSystemInfoService.cs" />
+ <Compile Include="SystemInfo\ISystemInfoService.cs" />
+ <Compile Include="ThreadLoading\IThreadLoadingService.cs" />
+ <Compile Include="UpdatePackages\DefaultPackageRunner.cs" />
+ <Compile Include="UpdatePackages\IPackageRunner.cs" />
+ <Compile Include="UpdatePackages\IPPCPackage.cs" />
+ <Compile Include="UpdatePackages\PackageContext.cs" />
+ <Compile Include="UpdatePackages\PackageProgressEventArgs.cs" />
+ <Compile Include="UpdatePackages\PackageRunnerResult.cs" />
+ <Compile Include="UpdatePackages\PackageStateChangedEventArgs.cs" />
+ <Compile Include="UpdatePackages\PackagesFile.cs" />
+ <Compile Include="UpdatePackages\PPCPackageAttribute.cs" />
<Compile Include="Publish\PPCPublisher.cs" />
<Compile Include="Publish\PublishInfo.cs" />
<Compile Include="Publish\PublishOptions.cs" />
@@ -158,12 +213,16 @@
<Compile Include="Web\CheckForUpdateRequest.cs" />
<Compile Include="Web\CheckForUpdateResponse.cs" />
<Compile Include="MachineUpdate\DbCompareResult.cs" />
+ <Compile Include="Web\NotifyMachineDataDownloadCompletedResponse.cs" />
+ <Compile Include="Web\NotifyMachineDataDownloadCompletedRequest.cs" />
<Compile Include="Web\DownloadUpdateRequest.cs" />
+ <Compile Include="Web\MachineUpdateCompletedResponse.cs" />
<Compile Include="Web\DownloadUpdateResponse.cs" />
<Compile Include="MachineUpdate\IMachineUpdateManager.cs" />
<Compile Include="Web\LoginMode.cs" />
<Compile Include="Web\LoginRequest.cs" />
<Compile Include="Web\LoginResponse.cs" />
+ <Compile Include="Web\MachineUpdateCompletedRequest.cs" />
<Compile Include="Web\MachineSetupRequest.cs" />
<Compile Include="Web\MachineSetupResponse.cs" />
<Compile Include="MachineUpdate\MachineUpdateProgress.cs" />
@@ -171,9 +230,9 @@
<Compile Include="MachineUpdate\MachineUpdateResult.cs" />
<Compile Include="Web\PPCWebClient.cs" />
<Compile Include="Web\PPCWebClientBase.cs" />
+ <Compile Include="Web\SynchronizationFailedEntity.cs" />
<Compile Include="Web\UpdateDBRequest.cs" />
<Compile Include="Web\UpdateDBResponse.cs" />
- <Compile Include="MachineUpdate\UpdatePackageFile.cs" />
<Compile Include="Messages\JobRemovedMessage.cs" />
<Compile Include="Messages\JobSavedMessage.cs" />
<Compile Include="Messages\MachineSettingsSavedMessage.cs" />
@@ -205,8 +264,13 @@
<Compile Include="Web\MachineVersionsResponse.cs" />
<Compile Include="Web\LatestVersionRequest.cs" />
<Compile Include="Web\LatestVersionResponse.cs" />
+ <Compile Include="Web\UpdatedEntity.cs" />
+ <Compile Include="Web\DownloadMachineDataRequest.cs" />
+ <Compile Include="Web\DownloadMachineDataResponse.cs" />
+ <Compile Include="Web\UploadMachineDataResponse.cs" />
<Compile Include="Web\UploadCompletedResponse.cs" />
<Compile Include="Web\UploadCompletedRequest.cs" />
+ <Compile Include="Web\UploadMachineDataRequest.cs" />
<Compile Include="Web\UploadVersionRequest.cs" />
<Compile Include="Web\UploadVersionResponse.cs" />
<Compile Include="UWF\DefaultUnifiedWriteFilterManager.cs" />
@@ -217,6 +281,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
+ <Page Include="Controls\ImageGalleryControl.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Controls\MultiPieChart.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -293,8 +361,29 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
+ <EmbeddedResource Include="SafetyLevelOperations.csv" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\DataStore\Tango.DataStore.Editing\Tango.DataStore.Editing.csproj">
+ <Project>{ee088ff7-04d1-41fb-9d6a-cedeee7a7b9c}</Project>
+ <Name>Tango.DataStore.Editing</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\DataStore\Tango.DataStore.EF\Tango.DataStore.EF.csproj">
+ <Project>{88d9906b-8fc4-4fe0-b7eb-127a0a8fcee4}</Project>
+ <Name>Tango.DataStore.EF</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\DataStore\Tango.DataStore.LiteDB\Tango.DataStore.Lite.csproj">
+ <Project>{fa96bc0c-4055-475c-9dcc-70a5a9436b10}</Project>
+ <Name>Tango.DataStore.Lite</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\DataStore\Tango.DataStore.Remote\Tango.DataStore.Remote.csproj">
+ <Project>{29448f3c-9b3e-4da6-8555-46a8b9a6b3aa}</Project>
+ <Name>Tango.DataStore.Remote</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\DataStore\Tango.DataStore\Tango.DataStore.csproj">
+ <Project>{e0364dfa-0721-4637-9d32-9d22aac109d6}</Project>
+ <Name>Tango.DataStore</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.AdvancedInstaller\Tango.AdvancedInstaller.csproj">
<Project>{c5df1816-34e5-4700-824c-29623a1baa22}</Project>
<Name>Tango.AdvancedInstaller</Name>
@@ -307,10 +396,18 @@
<Project>{b4fe6485-4161-4b36-bc08-67e0b53d01b7}</Project>
<Name>Tango.ColorConversion</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.Console\Tango.Console.csproj">
+ <Project>{199e8359-cad3-433d-9eed-2027652b24a4}</Project>
+ <Name>Tango.Console</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.CSV\Tango.CSV.csproj">
+ <Project>{58e8825f-0c96-449c-b320-1e82b0aa876b}</Project>
+ <Name>Tango.CSV</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Emulations\Tango.Emulations.csproj">
<Project>{63561e19-ff5a-414b-a5ef-e30711543e1d}</Project>
<Name>Tango.Emulations</Name>
@@ -319,6 +416,18 @@
<Project>{4399AF76-DB52-4CFB-8020-6F85BDB29FD5}</Project>
<Name>Tango.Explorer</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.FileSystem\Tango.FileSystem.csproj">
+ <Project>{c6ebbbbe-2123-44dc-aef7-a0d47d736ac0}</Project>
+ <Name>Tango.FileSystem</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Git\Tango.Git.csproj">
+ <Project>{99081c0e-065c-4d68-bf60-f82330cca02d}</Project>
+ <Name>Tango.Git</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Insights\Tango.Insights.csproj">
+ <Project>{4a55c185-3f8d-41b0-8815-c15f6213a14a}</Project>
+ <Name>Tango.Insights</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Integration\Tango.Integration.csproj">
<Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
<Name>Tango.Integration</Name>
@@ -331,6 +440,10 @@
<Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project>
<Name>Tango.PMR</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.RemoteDesktop\Tango.RemoteDesktop.csproj">
+ <Project>{a78068d4-2061-4376-8ede-583d8d880dec}</Project>
+ <Name>Tango.RemoteDesktop</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Settings\Tango.Settings.csproj">
<Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project>
<Name>Tango.Settings</Name>
@@ -343,6 +456,10 @@
<Project>{e1e66ed9-597d-45fa-8048-de90a6930484}</Project>
<Name>Tango.SQLExaminer</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.SystemInfo\Tango.SystemInfo.csproj">
+ <Project>{997a961c-beda-4b56-aa0f-c39e532f7ffa}</Project>
+ <Name>Tango.SystemInfo</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Touch\Tango.Touch.csproj">
<Project>{fd86424c-6e84-491b-8df9-3d0f5c236a2a}</Project>
<Name>Tango.Touch</Name>
@@ -351,6 +468,10 @@
<Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
<Name>Tango.Transport</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.WebRTC\Tango.WebRTC.csproj">
+ <Project>{09f81a12-0f77-4336-854d-9e0a74a17f9e}</Project>
+ <Name>Tango.WebRTC</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Web\Tango.Web.csproj">
<Project>{5001990f-977b-48ff-b217-0236a5022ad8}</Project>
<Name>Tango.Web</Name>
@@ -359,6 +480,10 @@
<Project>{6aa425c9-ea6a-4b01-aaed-5ff122e8b663}</Project>
<Name>Tango.WiFi</Name>
</ProjectReference>
+ <ProjectReference Include="..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6">
@@ -375,6 +500,16 @@
<ItemGroup>
<Folder Include="Scripting\" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="Resources\finger3.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Resources\tap.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\cl-full.png" />
+ <Resource Include="Images\lubricant2.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@@ -385,7 +520,7 @@
</Target>
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
+ <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
</VisualStudio>
</ProjectExtensions>
</Project> \ 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,20 +4,16 @@ 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";
/// <summary>
- /// Gets a value indicating whether UWF if currently enabled on the system.
- /// </summary>
- public bool IsEnabled { get; private set; }
-
- /// <summary>
/// Installs and configures the service (requires restart).
/// </summary>
/// <returns></returns>
@@ -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();
}
/// <summary>
@@ -67,5 +64,32 @@ namespace Tango.PPC.Common.UWF
command.OutputEncoding = CmdCommand.OutEncoding.Unicode;
await command.Run();
}
+
+ /// <summary>
+ /// Gets a value indicating whether UWF if currently enabled on the system.
+ /// </summary>
+ /// <returns></returns>
+ public async Task<bool> 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.
/// </summary>
/// <seealso cref="Tango.PPC.Common.UWF.IUnifiedWriteFilterManager" />
- 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";
@@ -24,11 +26,6 @@ namespace Tango.PPC.Common.UWF
};
/// <summary>
- /// Gets a value indicating whether UWF if currently enabled on the system.
- /// </summary>
- public bool IsEnabled { get; }
-
- /// <summary>
/// Installs and configures the service (requires restart).
/// </summary>
public async Task Setup()
@@ -95,5 +92,31 @@ namespace Tango.PPC.Common.UWF
command.OutputEncoding = CmdCommand.OutEncoding.Unicode;
await command.Run();
}
+
+ /// <summary>
+ /// Gets a value indicating whether UWF if currently enabled on the system.
+ /// </summary>
+ /// <returns></returns>
+ public async Task<bool> 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
/// <summary>
/// Gets a value indicating whether UWF if currently enabled on the system.
/// </summary>
- bool IsEnabled { get; }
+ /// <returns></returns>
+ Task<bool> IsEnabled();
/// <summary>
/// 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<PackageStateChangedEventArgs> PackageStateChanged;
+ public event EventHandler<PackageProgressEventArgs> 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<PackagesFile> GetPackagesFile()
+ {
+ return Task.Factory.StartNew<PackagesFile>(() =>
+ {
+ 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<PackagesFile>(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<PackageRunnerResult> Run(PackageType type, Version deltaVersion, String packagesFolder)
+ {
+ return Task.Factory.StartNew<PackageRunnerResult>(() =>
+ {
+ PackageRunnerResult result = new PackageRunnerResult();
+
+ PackageContext context = new PackageContext();
+ context.ApplicationManager = TangoIOC.Default.GetInstance<IPPCApplicationManager>();
+ context.MachineProvider = TangoIOC.Default.GetInstance<IMachineProvider>();
+ context.NotificationProvider = TangoIOC.Default.GetInstance<INotificationProvider>();
+ 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<PPCPackageAttribute>() != null &&
+ x.GetCustomAttribute<PPCPackageAttribute>().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<PPCPackageAttribute>();
+
+ 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<bool> IsPackageInstallationRequired(PackageType type, String packagesFolder)
+ {
+ return Task.Factory.StartNew<bool>(() =>
+ {
+ 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<PPCPackageAttribute>() != null &&
+ x.GetCustomAttribute<PPCPackageAttribute>().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<PackageStateChangedEventArgs> PackageStateChanged;
+ event EventHandler<PackageProgressEventArgs> PackageProgress;
+ Task<PackagesFile> GetPackagesFile();
+ Task<PackageRunnerResult> Run(PackageType type, Version deltaVersion, String packagesFolder);
+ Task<bool> 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<PackageInstallation> PackageInstallations { get; set; }
+
+ public PackagesFile()
+ {
+ PackageInstallations = new List<PackageInstallation>();
+ }
+ }
+}
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<UpdatedEntity> Rmls { get; set; }
+ public List<UpdatedEntity> HardwareVersions { get; set; }
+ public List<UpdatedEntity> Catalogs { get; set; }
+ public DateTime MachineLastUpdated { get; set; }
+ public List<String> UsedRmlsGuids { get; set; }
+
+ public CheckForUpdateRequest()
+ {
+ Rmls = new List<UpdatedEntity>();
+ HardwareVersions = new List<UpdatedEntity>();
+ Catalogs = new List<UpdatedEntity>();
+ UsedRmlsGuids = new List<string>();
+ }
}
}
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<String> UsedNotExistingRmlsGuids { get; set; }
+
+ public CheckForUpdateResponse()
+ {
+ UpdateDBResponse = new UpdateDBResponse();
+ UsedNotExistingRmlsGuids = new List<string>();
+ }
}
}
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<JobDTO> Jobs { get; set; }
+ public List<JobRunDTO> JobRuns { get; set; }
+ public List<MachinesEventDTO> MachineEvents { get; set; }
+ public List<DataStoreItemDTO> DataStoreItems { get; set; }
+
+ public DownloadMachineDataResponse()
+ {
+ Jobs = new List<JobDTO>();
+ JobRuns = new List<JobRunDTO>();
+ MachineEvents = new List<MachinesEventDTO>();
+ DataStoreItems = new List<DataStoreItemDTO>();
+ }
+ }
+}
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<String> SynchronizedJobs { get; set; }
+ public List<String> SynchronizedJobRuns { get; set; }
+ public List<String> SynchronizedMachineEvents { get; set; }
+ public List<String> SynchronizedDataStoreItems { get; set; }
+
+ public NotifyMachineDataDownloadCompletedRequest()
+ {
+ SynchronizedJobs = new List<string>();
+ SynchronizedJobRuns = new List<string>();
+ SynchronizedMachineEvents = new List<string>();
+ SynchronizedDataStoreItems = new List<string>();
+ }
+ }
+}
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
@@ -41,6 +41,15 @@ namespace Tango.PPC.Common.Web
}
/// <summary>
+ /// Initializes a new instance of the <see cref="PPCWebClientBase"/> class.
+ /// </summary>
+ /// <param name="cloned">Other instance.</param>
+ public PPCWebClientBase(PPCWebClientBase cloned) : base(cloned)
+ {
+
+ }
+
+ /// <summary>
/// Executes the MachineSetup action and returns Tango.PPC.Common.Web.MachineSetupResponse.
/// </summary>
/// <returns></returns>
@@ -59,6 +68,15 @@ namespace Tango.PPC.Common.Web
}
/// <summary>
+ /// Executes the NotifyUpdateCompleted action and returns Tango.PPC.Common.Web.MachineUpdateCompletedResponse.
+ /// </summary>
+ /// <returns></returns>
+ public Task<Tango.PPC.Common.Web.MachineUpdateCompletedResponse> NotifyUpdateCompleted(Tango.PPC.Common.Web.MachineUpdateCompletedRequest request)
+ {
+ return Post<Tango.PPC.Common.Web.MachineUpdateCompletedRequest, Tango.PPC.Common.Web.MachineUpdateCompletedResponse>("NotifyUpdateCompleted", request);
+ }
+
+ /// <summary>
/// Executes the CheckForUpdates action and returns Tango.PPC.Common.Web.CheckForUpdateResponse.
/// </summary>
/// <returns></returns>
@@ -77,6 +95,33 @@ namespace Tango.PPC.Common.Web
}
/// <summary>
+ /// Executes the UploadMachineData action and returns Tango.PPC.Common.Web.UploadMachineDataResponse.
+ /// </summary>
+ /// <returns></returns>
+ public Task<Tango.PPC.Common.Web.UploadMachineDataResponse> UploadMachineData(Tango.PPC.Common.Web.UploadMachineDataRequest request)
+ {
+ return Post<Tango.PPC.Common.Web.UploadMachineDataRequest, Tango.PPC.Common.Web.UploadMachineDataResponse>("UploadMachineData", request);
+ }
+
+ /// <summary>
+ /// Executes the DownloadMachineData action and returns Tango.PPC.Common.Web.DownloadMachineDataResponse.
+ /// </summary>
+ /// <returns></returns>
+ public Task<Tango.PPC.Common.Web.DownloadMachineDataResponse> DownloadMachineData(Tango.PPC.Common.Web.DownloadMachineDataRequest request)
+ {
+ return Post<Tango.PPC.Common.Web.DownloadMachineDataRequest, Tango.PPC.Common.Web.DownloadMachineDataResponse>("DownloadMachineData", request);
+ }
+
+ /// <summary>
+ /// Executes the NotifyMachineDataDownloadCompleted action and returns Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedResponse.
+ /// </summary>
+ /// <returns></returns>
+ public Task<Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedResponse> NotifyMachineDataDownloadCompleted(Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedRequest request)
+ {
+ return Post<Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedRequest, Tango.PPC.Common.Web.NotifyMachineDataDownloadCompletedResponse>("NotifyMachineDataDownloadCompleted", request);
+ }
+
+ /// <summary>
/// Executes the GetLatestVersion action and returns Tango.PPC.Common.Web.LatestVersionResponse.
/// </summary>
/// <returns></returns>
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<JobDTO> Jobs { get; set; }
+ public List<JobRunDTO> JobRuns { get; set; }
+ public List<MachinesEventDTO> MachineEvents { get; set; }
+ public List<TangoUpdateDTO> OfflineUpdates { get; set; }
+ public List<DataStoreItemDTO> DataStoreItems { get; set; }
+ public String ApplicationVersion { get; set; }
+ public String FirmwareVersion { get; set; }
+
+ public UploadMachineDataRequest()
+ {
+ Jobs = new List<JobDTO>();
+ JobRuns = new List<JobRunDTO>();
+ MachineEvents = new List<MachinesEventDTO>();
+ OfflineUpdates = new List<TangoUpdateDTO>();
+ DataStoreItems = new List<DataStoreItemDTO>();
+ }
+ }
+}
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<SynchronizationFailedEntity> FailedJobs { get; set; }
+ public List<SynchronizationFailedEntity> FailedJobRuns { get; set; }
+ public List<SynchronizationFailedEntity> FailedMachineEvents { get; set; }
+ public List<SynchronizationFailedEntity> FailedOfflineUpdates { get; set; }
+ public List<SynchronizationFailedEntity> FailedDataStoreItems { get; set; }
+
+ public String NotifyCompletedToken { get; set; }
+
+ public UploadMachineDataResponse()
+ {
+ FailedJobs = new List<SynchronizationFailedEntity>();
+ FailedJobRuns = new List<SynchronizationFailedEntity>();
+ FailedMachineEvents = new List<SynchronizationFailedEntity>();
+ FailedOfflineUpdates = new List<SynchronizationFailedEntity>();
+ FailedDataStoreItems = new List<SynchronizationFailedEntity>();
+ }
+ }
+}
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 @@
<package id="FontAwesome.WPF" version="4.7.0.9" targetFramework="net46" />
<package id="Google.Protobuf" version="3.4.1" targetFramework="net46" />
<package id="Ionic.Zip" version="1.9.1.8" targetFramework="net461" />
+ <package id="Microsoft.WindowsAPICodePack-Core" version="1.1.0.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
<package id="System.Data.SQLite" version="1.0.108.0" targetFramework="net46" />
<package id="System.Data.SQLite.Core" version="1.0.108.0" targetFramework="net46" />
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <configSections>
+ <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </configSections>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+ </startup>
+ <entityFramework>
+ <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
+ <providers>
+ <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+ </providers>
+ </entityFramework>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Z.EntityFramework.Extensions" publicKeyToken="59b66d028979105b" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.50.0" newVersion="4.0.50.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{3E07ED4E-A755-443F-B18C-3775555A2DD7}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Tango.PPC.DataSynchronizer.CLI</RootNamespace>
+ <AssemblyName>Tango.PPC.DataSynchronizer.CLI</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.SQLExaminer\Tango.SQLExaminer.csproj">
+ <Project>{e1e66ed9-597d-45fa-8048-de90a6930484}</Project>
+ <Name>Tango.SQLExaminer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="EntityFramework" version="6.2.0" targetFramework="net461" />
+</packages> \ 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">
<Window.Resources>
<converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter" />
@@ -67,15 +67,17 @@
<TextBlock Margin="0 20 0 0">
<TextBlock>
- <Run>Remote Version:</Run>
- <Run Text="{Binding RemoteVersion}"></Run>
+ <Run>Remote Versions:</Run>
+ <Run Text="{Binding RemoteVersion}"></Run>,
+ <Run Text="{Binding RemoteFirmwareVersion}"></Run>
</TextBlock>
</TextBlock>
<TextBlock Margin="0 20 0 0">
<TextBlock>
- <Run>Local Version:</Run>
- <Run Text="{Binding LocalVersion}"></Run>
+ <Run>Local Versions:</Run>
+ <Run Text="{Binding LocalVersion}"></Run>,
+ <Run Text="{Binding LocalFirmwareVersion}"></Run>
</TextBlock>
</TextBlock>
@@ -129,6 +131,13 @@
<TextBlock Margin="0 10 0 0">Password</TextBlock>
<TextBox Margin="0 5 0 0" Text="{Binding Options.Password}"></TextBox>
</StackPanel>
+
+ <StackPanel Margin="0 20 0 0">
+ <CheckBox x:Name="chkCreateTag" IsChecked="{Binding Options.CreateTag}">Create Tag On Repository</CheckBox>
+ <CheckBox Margin="0 5 0 0" IsChecked="{Binding Options.AutoCommitAndPush}">Auto Commit &amp; Push</CheckBox>
+ <TextBlock Margin="0 10 0 0">Personal Access Token</TextBlock>
+ <TextBox IsEnabled="{Binding ElementName=chkCreateTag,Path=IsChecked}" Margin="0 5 0 0" Text="{Binding Options.PersonalAccessToken}"></TextBox>
+ </StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
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 @@
<Reference Include="Microsoft.WindowsAzure.Storage, Version=4.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
@@ -133,6 +134,7 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
+ <None Include="Tango.PPC.Publisher.UI.json" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -146,6 +148,10 @@
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.Git\Tango.Git.csproj">
+ <Project>{99081c0e-065c-4d68-bf60-f82330cca02d}</Project>
+ <Name>Tango.Git</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Settings\Tango.Settings.csproj">
<Project>{D8F1AD85-526A-4F50-B6DC-D437AF63D8D8}</Project>
<Name>Tango.Settings</Name>
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 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+ </startup>
+</configuration> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{F3746F2B-E4AE-498B-9D42-74F95D992460}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Tango.PPC.SchemaSynchronizer.CLI</RootNamespace>
+ <AssemblyName>Tango.PPC.SchemaSynchronizer.CLI</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.SQLExaminer\Tango.SQLExaminer.csproj">
+ <Project>{e1e66ed9-597d-45fa-8048-de90a6930484}</Project>
+ <Name>Tango.SQLExaminer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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<SystemObjectsCollection> System { get; set; }
+
+ public InformationPackage()
+ {
+ System = new List<SystemObjectsCollection>();
+ }
+ }
+}
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<RemoteLogFile> LogFiles { get; set; }
+
+ public GetLogFilesResponse()
+ {
+ LogFiles = new List<RemoteLogFile>();
+ }
+ }
+}
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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.PPC.Shared.Properties {
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // 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() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [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;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ 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 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+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 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ 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<double> Progress { get; set; }
+
+ public StartRemoteApplicationUpgradeResponse()
+ {
+ Progress = new TangoProgress<double>()
+ {
+ 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<double> Progress { get; set; }
+
+ public StartRemoteFirmwareUpgradeResponse()
+ {
+ Progress = new TangoProgress<double>()
+ {
+ 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
+{
+ /// <summary>
+ /// Represents a <see cref="RemoteSqlDataSet"/> column.
+ /// </summary>
+ public class RemoteSqlColumn
+ {
+ /// <summary>
+ /// Gets or sets the column name.
+ /// </summary>
+ public String Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the column index.
+ /// </summary>
+ public int Index { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RemoteSqlColumn"/> class.
+ /// </summary>
+ public RemoteSqlColumn()
+ {
+
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RemoteSqlColumn"/> class.
+ /// </summary>
+ /// <param name="name">The column name.</param>
+ public RemoteSqlColumn(String name)
+ {
+ Name = name;
+ }
+
+ /// <summary>
+ /// Returns a <see cref="System.String" /> that represents this instance.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="System.String" /> that represents this instance.
+ /// </returns>
+ 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
+{
+ /// <summary>
+ /// Represents a <see cref="RemoteSqlDataSet"/> columns collection.
+ /// </summary>
+ /// <seealso cref="System.Collections.ObjectModel.Collection{Tango.PPC.Shared.SQL.RemoteSqlColumn}" />
+ public class RemoteSqlColumnCollection : Collection<RemoteSqlColumn>
+ {
+ private Dictionary<String, RemoteSqlColumn> _dictionary;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RemoteSqlColumnCollection"/> class.
+ /// </summary>
+ public RemoteSqlColumnCollection()
+ {
+ _dictionary = new Dictionary<string, RemoteSqlColumn>();
+ }
+
+ /// <summary>
+ /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1" /> at the specified index.
+ /// </summary>
+ /// <param name="index">The zero-based index at which <paramref name="item" /> should be inserted.</param>
+ /// <param name="item">The object to insert. The value can be null for reference types.</param>
+ protected override void InsertItem(int index, RemoteSqlColumn item)
+ {
+ item.Index = Count;
+ _dictionary.Add(item.Name, item);
+ base.InsertItem(index, item);
+ }
+
+ /// <summary>
+ /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1" />.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to remove.</param>
+ /// <exception cref="NotSupportedException"></exception>
+ protected override void RemoveItem(int index)
+ {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Removes all elements from the <see cref="T:System.Collections.ObjectModel.Collection`1" />.
+ /// </summary>
+ protected override void ClearItems()
+ {
+ _dictionary.Clear();
+ base.ClearItems();
+ }
+
+ /// <summary>
+ /// Replaces the element at the specified index.
+ /// </summary>
+ /// <param name="index">The zero-based index of the element to replace.</param>
+ /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>
+ /// <exception cref="NotSupportedException"></exception>
+ protected override void SetItem(int index, RemoteSqlColumn item)
+ {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Gets the column index by column name.
+ /// </summary>
+ /// <param name="columnName">Column name.</param>
+ /// <returns></returns>
+ 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
+{
+ /// <summary>
+ /// Represents remote database query result composed of rows and columns.
+ /// </summary>
+ /// <example>
+ /// <para>
+ /// <i>
+ /// The following example demonstrates how to set the connected machine's demo state and query for the connected machine's jobs.
+ /// </i>
+ /// </para>
+ /// <code lang="C#" source="../Tango.FSE.Procedures/Examples/Sql/Program.cs" title="Remote SQL" region="Example" />
+ /// </example>
+ public class RemoteSqlDataSet
+ {
+ /// <summary>
+ /// Gets or sets the dataset columns.
+ /// </summary>
+ public RemoteSqlColumnCollection Columns { get; set; }
+
+ private ObservableCollection<RemoteSqlRow> _rows;
+ /// <summary>
+ /// Gets or sets the dataset rows.
+ /// </summary>
+ public ObservableCollection<RemoteSqlRow> Rows
+ {
+ get { return _rows; }
+ set { _rows = value; OnRowsChanged(); }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RemoteSqlDataSet"/> class.
+ /// </summary>
+ public RemoteSqlDataSet()
+ {
+ Columns = new RemoteSqlColumnCollection();
+ Rows = new ObservableCollection<RemoteSqlRow>();
+ }
+
+ 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];
+ });
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates a new <see cref="RemoteSqlDataSet"/> using the specified <see cref="SqlDataReader"/>.
+ /// </summary>
+ /// <param name="reader">The reader.</param>
+ /// <returns></returns>
+ public static Task<RemoteSqlDataSet> Load(SqlDataReader reader)
+ {
+ return Task.Factory.StartNew<RemoteSqlDataSet>(() =>
+ {
+ 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;
+ });
+ }
+
+ /// <summary>
+ /// Returns a <see cref="System.String" /> that represents this instance.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="System.String" /> that represents this instance.
+ /// </returns>
+ public override string ToString()
+ {
+ return String.Join(", ", Columns.Select(x => x.Name)) + "\n" + String.Join(Environment.NewLine, Rows.Select(x => x.ToString()));
+ }
+
+ /// <summary>
+ /// Formats this dataset as a string with columns and rows.
+ /// </summary>
+ /// <returns></returns>
+ public String ToTableString()
+ {
+ Dictionary<int, int> columnsMaxLength = new Dictionary<int, int>();
+
+ 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
+{
+ /// <summary>
+ /// Represents a <see cref="RemoteSqlDataSet"/> row.
+ /// </summary>
+ /// <example>
+ /// <para>
+ /// <i>
+ /// The following example demonstrates how to set the connected machine's demo state and query for the connected machine's jobs.
+ /// </i>
+ /// </para>
+ /// <code lang="C#" source="../Tango.FSE.Procedures/Examples/Sql/Program.cs" title="Remote SQL" region="Example" />
+ /// </example>
+ public class RemoteSqlRow
+ {
+ private Func<String, Object> _getFuncKey;
+ private Func<int, Object> _getFuncIndex;
+
+ /// <summary>
+ /// Gets or sets the row values.
+ /// </summary>
+ public List<Object> Values { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="RemoteSqlRow"/> class.
+ /// </summary>
+ public RemoteSqlRow()
+ {
+ Values = new List<object>();
+ }
+
+ /// <summary>
+ /// Gets a row value by its column name.
+ /// </summary>
+ /// <param name="columnName">Name of the column.</param>
+ /// <returns>The column value.</returns>
+ public Object Get(String columnName)
+ {
+ return _getFuncKey.Invoke(columnName);
+ }
+
+ /// <summary>
+ /// Gets a row value by its column index.
+ /// </summary>
+ /// <param name="columnIndex">Index of the column.</param>
+ /// <returns>The column value.</returns>
+ public Object Get(int columnIndex)
+ {
+ return _getFuncIndex.Invoke(columnIndex);
+ }
+
+ /// <summary>
+ /// Gets a row value as type T by its column name.
+ /// </summary>
+ /// <typeparam name="T">Expected column type.</typeparam>
+ /// <param name="columnName">Name of the column.</param>
+ /// <returns>The column value.</returns>
+ public T Get<T>(String columnName)
+ {
+ var value = _getFuncKey.Invoke(columnName);
+
+ if (typeof(T) != value.GetType())
+ {
+ return (T)Convert.ChangeType(value, typeof(T));
+ }
+ else
+ {
+ return (T)value;
+ }
+ }
+
+ /// <summary>
+ /// Gets a row value by its column index.
+ /// </summary>
+ /// <typeparam name="T">Expected column type</typeparam>
+ /// <param name="columnIndex">Index of the column.</param>
+ /// <returns>The column value.</returns>
+ public T Get<T>(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<String, Object> getFuncKey, Func<int, Object> getFuncIndex)
+ {
+ _getFuncKey = getFuncKey;
+ _getFuncIndex = getFuncIndex;
+ }
+
+ /// <summary>
+ /// Returns a <see cref="System.String" /> that represents this instance.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="System.String" /> that represents this instance.
+ /// </returns>
+ public override string ToString()
+ {
+ return String.Join(", ", Values);
+ }
+
+ /// <summary>
+ /// Creates an object of type T and maps this row to it based on its properties decorated with <see cref="ColumnAttribute"/>.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns></returns>
+ public T Map<T>() where T : class, new()
+ {
+ var obj = Activator.CreateInstance<T>();
+ Map<T>(obj);
+ return obj;
+ }
+
+ /// <summary>
+ /// Maps this row to the specified object based on its properties decorated with <see cref="ColumnAttribute"/>.
+ /// </summary>
+ /// <typeparam name="T">Model type</typeparam>
+ /// <param name="obj">The object.</param>
+ public void Map<T>(T obj) where T : class
+ {
+ foreach (var prop in typeof(T).GetPropertiesWithAttribute<ColumnAttribute>())
+ {
+ try
+ {
+ var columnName = prop.GetCustomAttribute<ColumnAttribute>().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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{208C8BD8-72C6-4E3C-ACAA-351091A2ACC7}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <RootNamespace>Tango.PPC.Shared</RootNamespace>
+ <AssemblyName>Tango.PPC.Shared</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\Build\PPC\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>..\..\Build\PPC\Debug\Tango.PPC.Shared.xml</DocumentationFile>
+ <NoWarn>1591</NoWarn>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\Build\PPC\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>..\..\Build\PPC\Release\Tango.PPC.Shared.xml</DocumentationFile>
+ <NoWarn>1591</NoWarn>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xaml">
+ <RequiredTargetFramework>4.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="Themes\Generic.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="Events\PushEmulatedEventRequest.cs" />
+ <Compile Include="Events\PushEmulatedEventResponse.cs" />
+ <Compile Include="Information\GetMachineInformationRequest.cs" />
+ <Compile Include="Information\GetMachineInformationResponse.cs" />
+ <Compile Include="Information\InformationPackage.cs" />
+ <Compile Include="Insights\InsightsDownloadCompletedRequest.cs" />
+ <Compile Include="Insights\InsightsDownloadCompletedResponse.cs" />
+ <Compile Include="Insights\InsightsMinDateRequest.cs" />
+ <Compile Include="Insights\InsightsMinDateResponse.cs" />
+ <Compile Include="Insights\InsightsRequest.cs" />
+ <Compile Include="Insights\InsightsResponse.cs" />
+ <Compile Include="Jobs\RemoteJobProgress.cs" />
+ <Compile Include="Jobs\RemoteJobStage.cs" />
+ <Compile Include="Jobs\RemoteJobUpdateRequest.cs" />
+ <Compile Include="Jobs\RemoteJobUpdateResponse.cs" />
+ <Compile Include="Logs\GetLogFilesRequest.cs" />
+ <Compile Include="Logs\GetLogFilesResponse.cs" />
+ <Compile Include="Logs\RemoteLogFile.cs" />
+ <Compile Include="Logs\RemoteLogFileType.cs" />
+ <Compile Include="Performance\PerformancePackage.cs" />
+ <Compile Include="Performance\StartPerformanceUpdatesRequest.cs" />
+ <Compile Include="Performance\StartPerformanceUpdatesResponse.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="RemoteActions\SimulateApplicationExceptionRequest.cs" />
+ <Compile Include="RemoteActions\SimulateApplicationExceptionResponse.cs" />
+ <Compile Include="RemoteUpgrade\StartRemoteFirmwareUpgradeRequest.cs" />
+ <Compile Include="RemoteUpgrade\StartRemoteFirmwareUpgradeResponse.cs" />
+ <Compile Include="RemoteUpgrade\StartRemoteApplicationUpgradeResponse.cs" />
+ <Compile Include="RemoteUpgrade\StartRemoteApplicationUpgradeRequest.cs" />
+ <Compile Include="SQL\ExecuteSqlRequest.cs" />
+ <Compile Include="SQL\ExecuteSqlResponse.cs" />
+ <Compile Include="SQL\RemoteSqlColumn.cs" />
+ <Compile Include="SQL\RemoteSqlColumnCollection.cs" />
+ <Compile Include="SQL\RemoteSqlDataSet.cs" />
+ <Compile Include="SQL\RemoteSqlRow.cs" />
+ <Compile Include="Updates\GetUpdatesAndPackagesRequest.cs" />
+ <Compile Include="Updates\GetUpdatesAndPackagesResponse.cs" />
+ <Compile Include="Updates\PackageInstallation.cs" />
+ <Compile Include="Updates\PackageInstallationState.cs" />
+ <Compile Include="Updates\PackageType.cs" />
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PMR\Tango.PMR.csproj">
+ <Project>{E4927038-348D-4295-AAF4-861C58CB3943}</Project>
+ <Name>Tango.PMR</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.SystemInfo\Tango.SystemInfo.csproj">
+ <Project>{997a961c-beda-4b56-aa0f-c39e532f7ffa}</Project>
+ <Name>Tango.SystemInfo</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Simulation\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<ResourceDictionary
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:Tango.PPC.Shared">
+
+</ResourceDictionary>
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<TangoUpdateDTO> Updates { get; set; }
+
+ public List<PackageInstallation> Packages { get; set; }
+
+ public GetUpdatesAndPackagesResponse()
+ {
+ Updates = new List<TangoUpdateDTO>();
+ Packages = new List<PackageInstallation>();
+ }
+ }
+}
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 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
- <legacyCorruptedStateExceptionsPolicy enabled="true|false"/>
+ <legacyCorruptedStateExceptionsPolicy enabled="true" />
+ <legacyUnhandledExceptionPolicy enabled="1" />
+
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <!--Required for cefCharp-->
+ <probing privatePath="x86"/>
+
<!--<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" />
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs
index 0bd9f9d1d..e478dba77 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs
@@ -5,15 +5,20 @@ using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Tango.BL;
using Tango.Core;
using Tango.Core.DI;
using Tango.Core.Helpers;
+using Tango.Insights;
+using Tango.Integration.Operation;
using Tango.Logging;
using Tango.PPC.Common;
using Tango.PPC.Common.EventLogging;
+using Tango.PPC.Common.Helpers;
using Tango.PPC.Common.Notifications;
using Tango.PPC.Common.WatchDog;
using Tango.Settings;
@@ -25,7 +30,7 @@ namespace Tango.PPC.UI
/// </summary>
public partial class App : Application
{
- private WpfGlobalExceptionTrapper exceptionTrapper;
+ public static WpfGlobalExceptionTrapper ExceptionTrapper;
public static String[] StartupArgs { get; private set; }
private LogManager LogManager = LogManager.Default;
@@ -36,6 +41,12 @@ namespace Tango.PPC.UI
/// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the event data.</param>
protected override void OnStartup(StartupEventArgs e)
{
+ //throw new InvalidOperationException("This is a fake exception!!!");
+
+ //removed due to possibly causing this issue:
+ //https://stackoverflow.com/questions/41543956/how-to-debug-not-enough-storage-is-available-to-process-this-command
+ //ThreadPool.SetMaxThreads(1000, 1000);
+
//If no debugger is attached and the argument -debug was passed launch the debugger.
if (e.Args.Contains("-debug") && !Debugger.IsAttached)
{
@@ -45,18 +56,34 @@ namespace Tango.PPC.UI
StartupArgs = e.Args;
//LogManager.RegisterLogger(new ConsoleLogger("Tango PPC Debug"));
- LogManager.RegisterLogger(new FileLogger());
+ LogManager.RegisterLogger(new FileLogger()
+ {
+ EnableAutoLogRemoval = true,
+ EnableMaxFileSizeLimit = true,
+ AutoLogRemovalPeriod = TimeSpan.FromDays(30)
+ });
+
+#if DEBUG
LogManager.RegisterLogger(new VSOutputLogger());
+#endif
- LogManager.Log("Application Started...");
+ //Configure machine operator logger.
+ var operatorLogger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.SingleOrDefault(x => x is FileLogger) as FileLogger;
+ if (operatorLogger != null)
+ {
+ operatorLogger.EnableAutoLogRemoval = true;
+ operatorLogger.EnableMaxFileSizeLimit = true;
+ operatorLogger.AutoLogRemovalPeriod = TimeSpan.FromDays(30);
+ }
- base.OnStartup(e);
+ LogsHelper.SetLogSafe(LogManager.CreateLogSafe());
+ LogManager.Log($"Application Started... Version: '{AssemblyHelper.GetCurrentAssemblyVersion()}'.");
- exceptionTrapper = new WpfGlobalExceptionTrapper();
- exceptionTrapper.Initialize(this);
- exceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed;
+ base.OnStartup(e);
- LogManager.Categories.Clear();
+ ExceptionTrapper = new WpfGlobalExceptionTrapper();
+ ExceptionTrapper.Initialize(this);
+ ExceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed;
CoreSettings.DefaultDataSource = new DataSource()
{
@@ -65,25 +92,33 @@ namespace Tango.PPC.UI
IntegratedSecurity = true,
};
- SettingsManager.Default.GetOrCreate<CoreSettings>();
+ WebRequest.DefaultWebProxy = null;
- var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
+ GetLastApplicationCrashFromWindows();
+ }
- if (settings.LoggingCategories.Count == 0)
- {
- settings.LoggingCategories.Add(LogCategory.Critical);
- settings.LoggingCategories.Add(LogCategory.Error);
- settings.LoggingCategories.Add(LogCategory.Info);
- settings.LoggingCategories.Add(LogCategory.Warning);
- }
+ #region Global Exception Trapping
- settings.Save();
+ private async void GetLastApplicationCrashFromWindows()
+ {
+ var logItem = await ExceptionTrapper.GetLastApplicationCrashEventLog(60);
+ if (logItem != null)
+ {
+ LogManager.Log(logItem);
- LogManager.Categories.AddRange(settings.LoggingCategories);
+ try
+ {
+ InsightsManager.Default.InsertApplicationException(new InsightsApplicationException()
+ {
+ Time = DateTime.UtcNow,
+ Exception = logItem.Message,
+ IsApplicationCrash = true
+ });
+ }
+ catch { }
+ }
}
- #region Global Exception Trapping
-
/// <summary>
/// Handles the ApplicationCrashed event of the ExceptionTrapper.
/// </summary>
@@ -91,7 +126,19 @@ namespace Tango.PPC.UI
/// <param name="e">The <see cref="ApplicationCrashedEventArgs"/> instance containing the event data.</param>
private void ExceptionTrapper_ApplicationCrashed(object sender, ApplicationCrashedEventArgs e)
{
- e.TryRecover = true;
+ List<String> ignoredExceptions = new List<string>()
+ {
+ "FocusVisualStyle",
+ "ThreadAbortException",
+ "A Task's exception(s) were not observed"
+ };
+
+ String exceptionString = e.Exception.ToStringSafe();
+
+ if (ignoredExceptions.Exists(x => exceptionString.Contains(x)))
+ {
+ return;
+ }
try
{
@@ -100,6 +147,17 @@ namespace Tango.PPC.UI
try
{
+ InsightsManager.Default.InsertApplicationException(new InsightsApplicationException()
+ {
+ Time = DateTime.UtcNow,
+ Exception = e.Exception.ToString()
+ });
+ }
+ catch
+ { }
+
+ try
+ {
if (Application.Current == null)
{
new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.cs
new file mode 100644
index 000000000..c2bdc3926
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItem.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 PowerOffAppBarItem : AppBarItem
+ {
+ private StartPowerDownResponse _status;
+ public StartPowerDownResponse Status
+ {
+ get { return _status; }
+ set { _status = value; RaisePropertyChangedAuto(); }
+ }
+
+ /// <summary>
+ /// Gets or sets the view type.
+ /// </summary>
+ public override Type ViewType
+ {
+ get
+ {
+ return typeof(PowerOffAppBarItemView);
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml
new file mode 100644
index 000000000..9a9f8e912
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/AppBarItems/PowerOffAppBarItemView.xaml
@@ -0,0 +1,30 @@
+<UserControl x:Class="Tango.PPC.UI.AppBarItems.PowerOffAppBarItemView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.UI.AppBarItems"
+ mc:Ignorable="d"
+ d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:PowerOffAppBarItem, IsDesignTimeCreatable=False}">
+ <Grid>
+ <touch:TouchButton Style="{StaticResource TangoFlatButton}" Command="{Binding PressedCommand}" Padding="0">
+ <StackPanel VerticalAlignment="Center">
+ <TextBlock Text="{Binding Status.Message}" FontSize="{StaticResource TangoDefaultFontSize}" TextTrimming="CharacterEllipsis"></TextBlock>
+ <ProgressBar Maximum="100" Value="{Binding Status.ProgressPercentage}" Margin="0 10 0 5" Background="{StaticResource TangoGrayBrush}" Height="5" Foreground="{StaticResource TangoPrimaryAccentBrush}" BorderThickness="0" />
+ <DockPanel LastChildFill="False">
+ <TextBlock DockPanel.Dock="Left">
+
+ <Run Text="{Binding Status.ProgressPercentage}"></Run><Run>%</Run>
+ <Run>Completed</Run>
+ </TextBlock>
+
+ <!--<TextBlock DockPanel.Dock="Right">
+ <Run Text="{Binding MachineProvider.MachineOperator.RunningJobStatus.RemainingTime,Converter={StaticResource TimeSpanToTwoDigitsTimeConverter},FallbackValue=5}"></Run>
+ <Run FontSize="16" Text="{Binding MachineProvider.MachineOperator.RunningJobStatus.RemainingTime,Converter={StaticResource TimeSpanToLabelConverter},FallbackValue=min}"></Run>
+ </TextBlock>-->
+ </DockPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerOffAppBarItemView.xaml
+ /// </summary>
+ 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(); }
+ }
+
+ /// <summary>
+ /// Gets or sets the view type.
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.UI.AppBarItems.PowerUpAppBarItemView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.UI.AppBarItems"
+ mc:Ignorable="d"
+ d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:PowerUpAppBarItem, IsDesignTimeCreatable=False}">
+ <Grid>
+ <touch:TouchButton Style="{StaticResource TangoFlatButton}" Command="{Binding PressedCommand}" Padding="0">
+ <StackPanel VerticalAlignment="Center">
+ <TextBlock Text="{Binding Status.Message}" FontSize="{StaticResource TangoDefaultFontSize}" TextTrimming="CharacterEllipsis"></TextBlock>
+ <ProgressBar Maximum="100" Value="{Binding Status.ProgressPercentage}" Margin="0 10 0 5" Background="{StaticResource TangoGrayBrush}" Height="5" Foreground="{StaticResource TangoPrimaryAccentBrush}" BorderThickness="0" />
+ <DockPanel LastChildFill="False">
+ <TextBlock DockPanel.Dock="Left">
+
+ <Run Text="{Binding Status.ProgressPercentage}"></Run><Run>%</Run>
+ <Run>Completed</Run>
+ </TextBlock>
+
+ <!--<TextBlock DockPanel.Dock="Right">
+ <Run Text="{Binding MachineProvider.MachineOperator.RunningJobStatus.RemainingTime,Converter={StaticResource TimeSpanToTwoDigitsTimeConverter},FallbackValue=5}"></Run>
+ <Run FontSize="16" Text="{Binding MachineProvider.MachineOperator.RunningJobStatus.RemainingTime,Converter={StaticResource TimeSpanToLabelConverter},FallbackValue=min}"></Run>
+ </TextBlock>-->
+ </DockPanel>
+ </StackPanel>
+ </touch:TouchButton>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerOffAppBarItemView.xaml
+ /// </summary>
+ 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
@@ -46,6 +46,11 @@ namespace Tango.PPC.UI.Authentication
}
/// <summary>
+ /// Gets a value indicating whether the authentication provider is using a null user.
+ /// </summary>
+ public bool AuthenticationRequired { get; private set; }
+
+ /// <summary>
/// Performs a user login by the specified email and password.
/// </summary>
/// <param name="email">The email.</param>
@@ -56,6 +61,9 @@ namespace Tango.PPC.UI.Authentication
{
return Task.Factory.StartNew<User>(() =>
{
+
+ 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);
+ });
+ }
+
/// <summary>
/// Logs-out the current logged-in user.
/// </summary>
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;
/// <summary>
/// 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;
+ /// <summary>
+ /// Gets a value indicating whether there is LAN connection.
+ /// </summary>
+ 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<PPCSettings>();
}
/// <summary>
@@ -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;
}
/// <summary>
@@ -223,6 +260,11 @@ namespace Tango.PPC.UI.Connectivity
/// <returns></returns>
public Task<bool> CheckInternetConnection()
{
+ if (_settings.BypassInternetConnectivityCheck)
+ {
+ return Task.FromResult(true);
+ }
+
return Task.Factory.StartNew<bool>(() =>
{
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 @@
+<UserControl x:Class="Tango.PPC.UI.Controls.MachineStatusControl"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:operations="clr-namespace:Tango.Integration.Operation;assembly=Tango.Integration"
+ xmlns:local="clr-namespace:Tango.PPC.UI.Controls"
+ mc:Ignorable="d"
+ Width="36" Height="Auto">
+ <Grid>
+ <touch:TouchGifAnimation Width="36" HorizontalAlignment="Center" EnableAnimation="True">
+ <touch:TouchGifAnimation.Style>
+ <Style TargetType="touch:TouchGifAnimation">
+ <Setter Property="Source" Value="/Images/GlobalStatus/standby.png"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.Disconnected}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/machine_off_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.PowerUp}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/getting_ready_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.Standby}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/standby_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.ReadyToDye}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/Ready_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.GettingReady}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/getting_ready_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.Printing}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/dyeing_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.ShuttingDown}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/shutdown_icon_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.Error}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/error_Anim.gif"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Status}" Value="{x:Static operations:MachineStatuses.Service}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/service_Anim.gif"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchGifAnimation.Style>
+ </touch:TouchGifAnimation>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for MachineStatusControl.xaml
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.UI.Dialogs.FirmwareUpgradeFromFileView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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: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="570" Height="700" d:DataContext="{d:DesignInstance Type=local:FirmwareUpgradeFromFileViewVM, IsDesignTimeCreatable=False}">
+ <Grid Margin="20">
+ <DockPanel>
+ <Grid DockPanel.Dock="Bottom">
+ <touch:TouchButton HorizontalAlignment="Left" CornerRadius="25" Command="{Binding CloseCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">CANCEL</touch:TouchButton>
+ <touch:TouchButton HorizontalAlignment="Right" CornerRadius="25" Command="{Binding OKCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">UPGRADE</touch:TouchButton>
+ </Grid>
+ <StackPanel>
+ <Image Source="../Images/firmware.png" Stretch="Uniform" Height="120"></Image>
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoHeaderFontSize}">Tango Firmware Upgrade</TextBlock>
+ <TextBlock Margin="20 10" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">The selected file contains a firmware upgrade package. Press 'UPGRADE' to start updating your system.</TextBlock>
+
+ <TextBlock TextAlignment="Center" HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ <Run FontWeight="SemiBold">Firmware:</Run>
+ <Run Text="{Binding Version}"></Run>
+ </TextBlock>
+ </StackPanel>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for UpdateFromFileView.xaml
+ /// </summary>
+ 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 @@
<Run>The job cannot be completed.</Run>
</TextBlock>
</StackPanel>
- <Grid>
+ <Grid VerticalAlignment="Top" Margin="0 30 0 0">
<ItemsControl ItemsSource="{Binding Exception.IdsPackLevels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
- <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" IsItemsHost="True"></StackPanel>
+ <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Orientation="Vertical" IsItemsHost="True"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
- <StackPanel Margin="15 0" Width="60">
- <TextBlock HorizontalAlignment="Center" Text="{Binding IdsPack.LiquidType.Name}" Margin="-20 0 -20 0" TextTrimming="CharacterEllipsis"></TextBlock>
- <Border Margin="0 5 0 0" Height="150" Width="50" CornerRadius="3" BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}">
+ <Grid Margin="0 0 0 4">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="40" />
+ <ColumnDefinition Width="160" />
+ <ColumnDefinition Width="1*" />
+ </Grid.ColumnDefinitions>
+ <touch:TouchIcon VerticalAlignment="Center" Width="24" Height="24">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon">
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGreenBrush}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsValid}" Value="False">
+ <Setter Property="Icon" Value="Alert"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoWarningBrush}"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding IsOverMax}" Value="True">
+ <Setter Property="Icon" Value="AlertOctagon"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoRedBrush}"></Setter>
+ </DataTrigger>
+ <MultiDataTrigger>
+ <MultiDataTrigger.Conditions>
+ <Condition Binding="{Binding IsValid}" Value="True" />
+ <Condition Binding="{Binding IsOverMax}" Value="False" />
+ </MultiDataTrigger.Conditions>
+ <Setter Property="Icon" Value="Check"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGreenBrush}"></Setter>
+ </MultiDataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+
+ <Border Grid.Column="1" Margin="5 0 0 0" Height="45" Width="150" CornerRadius="3" BorderThickness="1" BorderBrush="{StaticResource TangoLightBorderBrush}">
<Grid>
- <Border CornerRadius="3" VerticalAlignment="Bottom" Loaded="IdsPackLoaded" MinHeight="5">
+ <Border VerticalAlignment="Center" CornerRadius="3" Loaded="IdsPackLoaded" MinHeight="45" HorizontalAlignment="Left" MinWidth="5">
<Border.Background>
- <LinearGradientBrush>
- <GradientStop Offset="0" Color="#4DFFFFFF" />
+ <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.5" Color="{Binding IdsPack.LiquidType.LiquidTypeColor}" />
+ <GradientStop Offset="1" Color="#4EFFFFFF" />
</LinearGradientBrush>
</Border.Background>
</Border>
- <Rectangle Loaded="Limit_Loaded" Stroke="Red" StrokeThickness="2" VerticalAlignment="Bottom">
+ <Rectangle Loaded="Limit_Loaded" Stroke="{StaticResource TangoRedBrush}" StrokeThickness="2" HorizontalAlignment="Left">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
@@ -66,9 +97,18 @@
</Style>
</Rectangle.Style>
</Rectangle>
+
+
+ <TextBlock FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoDarkForegroundBrush}" HorizontalAlignment="Center" Text="{Binding IdsPack.LiquidType.Name}" VerticalAlignment="Center">
+ <TextBlock.Effect>
+ <DropShadowEffect ShadowDepth="1" BlurRadius="1" Color="White" />
+ </TextBlock.Effect>
+ </TextBlock>
+
</Grid>
</Border>
- </StackPanel>
+ <TextBlock Grid.Column="2" HorizontalAlignment="Left" Text="{Binding Message}" VerticalAlignment="Center" Margin="20,0,0,0" TextWrapping="Wrap" FontSize="{StaticResource TangoSmallFontSize}" Foreground="{StaticResource TangoRedBrush}"></TextBlock>
+ </Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
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 @@
+<UserControl x:Class="Tango.PPC.UI.Dialogs.PowerUpView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.UI.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="600" Height="800" d:DataContext="{d:DesignInstance Type=local:PowerUpViewVM, IsDesignTimeCreatable=False}">
+ <Grid>
+ <StackPanel Margin="0 100 0 0" HorizontalAlignment="Center">
+ <touch:TouchGifAnimation Source="../Images/powerup.gif" EnableAnimation="{Binding IsVisible}" />
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Margin="0 30 0 0">Continue getting ready for:</TextBlock>
+ <DockPanel HorizontalAlignment="Center" Margin="0 40 0 0">
+ <touch:TouchRadioButton IsChecked="{Binding IsSelectedRml}" />
+ <touch:TouchComboBox Margin="20 0 0 0" Width="300" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRml}" DisplayMemberPath="Name" Title="Select thread type"></touch:TouchComboBox>
+ </DockPanel>
+ <DockPanel HorizontalAlignment="Left" Margin="0 40 0 0">
+ <touch:TouchRadioButton IsChecked="{Binding IsMinimalTemperature}" />
+ <TextBlock VerticalAlignment="Center" Margin="20 0 0 0">Minimal temperature</TextBlock>
+ </DockPanel>
+
+ <touch:TouchButton Command="{Binding OKCommand}" Margin="0 150 0 0" Style="{StaticResource TangoHollowButton}" HorizontalAlignment="Center" Padding="60 15" CornerRadius="25">CONTINUE</touch:TouchButton>
+
+ <TextBlock HorizontalAlignment="Center" Margin="0 10 0 0" Visibility="{Binding IsTimeoutEnabled,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <Run>auto select in</Run>
+ <Run Text="{Binding RemainingSeconds}"></Run>
+ <Run>sec</Run>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerUpView.xaml
+ /// </summary>
+ 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<Rml> _rmls;
+ public List<Rml> 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<PPCSettings>().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 @@
+<UserControl x:Class="Tango.PPC.UI.Dialogs.SafetyLevelOperationsConfirmationView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:local="clr-namespace:Tango.PPC.UI.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="700" Height="900" d:DataContext="{d:DesignInstance Type=local:SafetyLevelOperationsConfirmationViewVM, IsDesignTimeCreatable=False}">
+ <Grid Margin="20">
+ <DockPanel>
+ <Grid DockPanel.Dock="Bottom">
+ <touch:TouchButton HorizontalAlignment="Left" CornerRadius="25" Command="{Binding CloseCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">DECLINE</touch:TouchButton>
+
+ <Grid HorizontalAlignment="Center">
+ <touch:TouchRingProgress Width="50" Height="50" Maximum="{Binding MaxSeconds}" Value="{Binding SecondsRemaining}" />
+ <TextBlock Text="{Binding SecondsRemaining}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
+ </Grid>
+
+ <touch:TouchButton HorizontalAlignment="Right" CornerRadius="25" Command="{Binding OKCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">APPROVE</touch:TouchButton>
+ </Grid>
+ <StackPanel DockPanel.Dock="Top">
+ <touch:TouchIcon Icon="Alert" Foreground="{StaticResource TangoWarningBrush}" Height="120"></touch:TouchIcon>
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoHeaderFontSize}">Safety Level Access Request</TextBlock>
+ <TextBlock Margin="20 10" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">
+ <Run>A remote client is requesting a safety level connection to this machine.</Run>
+ <LineBreak/>
+ <Run>Once approved, the remote user will be able to perform any mechanical operation remotely.</Run>
+ </TextBlock>
+ </StackPanel>
+ <Grid>
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <TextBlock FontSize="{StaticResource TangoTitleFontSize}">Request Information</TextBlock>
+ <controls:TableGrid Margin="0 30 0 0" HorizontalAlignment="Center" RowHeight="30" Width="280">
+ <TextBlock FontWeight="Bold">Address:</TextBlock>
+ <TextBlock Text="{Binding Connection.Address}"></TextBlock>
+
+ <TextBlock FontWeight="Bold">Host Name:</TextBlock>
+ <TextBlock Text="{Binding Connection.Request.HostName}"></TextBlock>
+
+ <TextBlock FontWeight="Bold">App ID:</TextBlock>
+ <TextBlock Text="{Binding Connection.Request.AppID}"></TextBlock>
+
+ <TextBlock FontWeight="Bold">User:</TextBlock>
+ <TextBlock Text="{Binding Connection.Request.UserName,TargetNullValue='Unknown',FallbackValue='Unknown'}"></TextBlock>
+ </controls:TableGrid>
+ </StackPanel>
+ </Grid>
+ </DockPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for SafetyLevelOperationsConfirmationView.xaml
+ /// </summary>
+ 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;
+ /// <summary>
+ /// Gets or sets the last client connection event arguments.
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.UI.Dialogs.ThreadBreakView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:commonControls="clr-namespace:Tango.PPC.Common.Controls;assembly=Tango.PPC.Common"
+ xmlns:local="clr-namespace:Tango.PPC.UI.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="700" Height="1150" d:DataContext="{d:DesignInstance Type=local:ThreadBreakViewVM, IsDesignTimeCreatable=False}">
+ <Grid>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top" Margin="0 30 0 0">
+ <Image HorizontalAlignment="Center" Source="/Images/thread_loading.png" Stretch="None"></Image>
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" Margin="0 30 0 0">Thread Break Wizard</TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="10 0 0 0" Orientation="Horizontal" DockPanel.Dock="Bottom">
+ <touch:TouchButton Command="{Binding BackCommand}">
+ <touch:TouchButton.Style>
+ <Style TargetType="touch:TouchButton" BasedOn="{StaticResource TangoFlatButton}">
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryAccentBrush}"></Setter>
+ <Style.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchButton.Style>
+ <StackPanel>
+ <touch:TouchIcon Icon="ArrowLeft" Width="24" Height="24" />
+ <TextBlock Margin="0 5 0 0" HorizontalAlignment="Center">Back</TextBlock>
+ </StackPanel>
+ </touch:TouchButton>
+ </StackPanel>
+
+ <Grid Margin="0 20 0 0">
+ <controls:NavigationControl Margin="0 5 0 0" SelectedObject="{Binding Stage}" TransitionType="Slide" TransitionAlwaysFades="False" TransitionDuration="00:00:0.1" SelectedIndex="0">
+
+ <!--Guiding Units-->
+ <Grid controls:NavigationControl.NavigationName="GuidingUnits" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="3" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Padding="30 0" HorizontalAlignment="Left" Command="{Binding GuidingUnitsFoundCantFixCommand}">Found But Can't Fix</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Padding="40 0" HorizontalAlignment="Right" Command="{Binding GuidingUnitsFoundAndFixedCommand}">Found and Fixed</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Padding="50 0" HorizontalAlignment="Right" Command="{Binding GuidingUnitsCantFindItCommand}">Can't Find It</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Please check guiding units on both sides of the system and fix/tie the thread if possible.</TextBlock>
+ </StackPanel>
+
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/GuidingUnits/1.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Feeding Units-->
+ <Grid controls:NavigationControl.NavigationName="FeedingUnits" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="2" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Left" Command="{Binding FeedingUnitsFoundAndFixedCommand}">Found and Fixed</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Right" Command="{Binding FeedingUnitsCantFixCommand}">Can't Fix</touch:TouchButton>
+ </UniformGrid>
+ <TextBlock Foreground="{StaticResource TangoErrorBrush}" DockPanel.Dock="Bottom" TextWrapping="Wrap" TextAlignment="Center" Margin="50 20">
+ 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
+ </TextBlock>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Open the covers and check the feeder and puller and fix/tie if possible.
+ </TextBlock>
+ </StackPanel>
+
+ <Grid>
+ <Grid Visibility="{Binding IsArcHead,Converter={StaticResource BooleanToVisibilityInverseConverter}}">
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/1.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/2.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/3.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/4.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </Grid>
+
+ <Grid Visibility="{Binding IsArcHead,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/arc/1.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/arc/2.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/arc/3.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/arc/4.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/FeedingUnits/arc/5.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </Grid>
+ </Grid>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--The Dryer-->
+ <Grid controls:NavigationControl.NavigationName="TheDryer" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="2" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Left" Command="{Binding TheDryerRemovedSuccessfullyCommand}">Removed Successfully</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Right" Command="{Binding TheDryerCantRemoveCommand}">Can't Remove</touch:TouchButton>
+ </UniformGrid>
+ <StackPanel DockPanel.Dock="Bottom" TextElement.Foreground="{StaticResource TangoErrorBrush}" Margin="50 20">
+ <DockPanel HorizontalAlignment="Center">
+ <touch:TouchIcon Icon="Alert" Foreground="{StaticResource TangoErrorBrush}" />
+ <TextBlock Margin="5 0 0 0" VerticalAlignment="Center">HOT SURFACE!</TextBlock>
+ </DockPanel>
+ <TextBlock Margin="0 5 0 0" Foreground="{StaticResource TangoErrorBrush}" TextWrapping="Wrap" TextAlignment="Center">
+ Recommended to cool down and/or to wear safety gloves
+ </TextBlock>
+ </StackPanel>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Open the dryer, cut the thread and remove any residue.
+ </TextBlock>
+ </StackPanel>
+
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/TheDryer/1.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/TheDryer/2.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/TheDryer/3.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/TheDryer/4.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/TheDryer/5.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Dryer Close-->
+ <Grid controls:NavigationControl.NavigationName="DryerClose" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="300" HorizontalAlignment="Center" Command="{Binding OpenThreadLoadingWizardCommand}">Open The Thread Loading Wizard</touch:TouchButton>
+ </UniformGrid>
+ <TextBlock DockPanel.Dock="Bottom" TextWrapping="Wrap" TextAlignment="Center" Margin="50 20">
+ You will be able to open the thread loading wizard once the dryer door is closed
+ </TextBlock>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Close the dryer door
+ </TextBlock>
+ </StackPanel>
+
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/DryerClose/1.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/DryerClose/2.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/DryerClose/3.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/DryerClose/4.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Contact Support-->
+ <Grid controls:NavigationControl.NavigationName="ContactSupport" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding CloseCommand}">Close</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Please Contact Twine Customer Care
+ </TextBlock>
+ </StackPanel>
+
+ <Grid>
+ <TextBlock HorizontalAlignment="Center" Margin="0 50 0 0" FontSize="40" Foreground="{StaticResource TangoPrimaryAccentBrush}">support@twine-s.com</TextBlock>
+ </Grid>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Jogging-->
+ <Grid controls:NavigationControl.NavigationName="Jogging" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Verifying thread movement
+ </TextBlock>
+ </StackPanel>
+
+ <StackPanel Margin="0 100 0 0">
+ <TextBlock HorizontalAlignment="Center" FontWeight="SemiBold">working...</TextBlock>
+ <touch:TouchBusyIndicator Foreground="{StaticResource TangoGrayBrush}" Width="130" Height="130" Margin="0 40 0 0" StrokeThickness="8" IsIndeterminate="{Binding IsVisible}" />
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Fixed-->
+ <Grid controls:NavigationControl.NavigationName="Fixed" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="20" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding CloseCommand}">Close</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" Margin="40 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">
+ Issue Resolved
+ </TextBlock>
+ </StackPanel>
+
+ <Grid>
+ <touch:TouchIcon Icon="CheckCircleOutline" Foreground="{StaticResource TangoSuccessBrush}" HorizontalAlignment="Center" VerticalAlignment="Top" Width="100" Margin="0 100 0 0" />
+ </Grid>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+ </controls:NavigationControl>
+ </Grid>
+ </DockPanel>
+
+ <touch:TouchIconButton Command="{Binding CloseCommand}" HorizontalAlignment="Right" VerticalAlignment="Top" Icon="Close" Width="45" Height="45" Padding="14" Foreground="{StaticResource TangoDarkForegroundBrush}" />
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for ThreadBreakWizard.xaml
+ /// </summary>
+ 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<BL.Entities.MachinesEvent> 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 @@
+<UserControl x:Class="Tango.PPC.UI.Dialogs.ThreadLoadingView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:commonControls="clr-namespace:Tango.PPC.Common.Controls;assembly=Tango.PPC.Common"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:local="clr-namespace:Tango.PPC.UI.Dialogs"
+ mc:Ignorable="d"
+ Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DesignHeight="555" d:DesignWidth="560" Width="700" Height="1150" d:DataContext="{d:DesignInstance Type=local:ThreadLoadingViewVM, IsDesignTimeCreatable=False}">
+ <Grid>
+ <DockPanel>
+ <StackPanel DockPanel.Dock="Top" Margin="0 30 0 0">
+ <Image HorizontalAlignment="Center" Source="/Images/thread_loading.png" Stretch="None"></Image>
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoHeaderFontSize}" Margin="0 30 0 0">Thread Loading</TextBlock>
+ </StackPanel>
+
+ <Grid Margin="0 20 0 0">
+ <controls:NavigationControl Margin="0 5 0 0" SelectedObject="{Binding Stage}" TransitionType="Slide" TransitionAlwaysFades="False" TransitionDuration="00:00:0.1" SelectedIndex="0">
+ <!--Welcome-->
+ <Grid controls:NavigationControl.NavigationName="Welcome" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding ContinueCommand}">Continue</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 50 0 0" >
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Welcome to the automatic thread loading wizard.</TextBlock>
+ <StackPanel HorizontalAlignment="Center" Margin="0 20 0 0">
+ <touch:TouchIcon Icon="Alert" VerticalAlignment="Center" Foreground="{StaticResource TangoErrorBrush}" />
+ <TextBlock TextWrapping="Wrap" TextAlignment="Center" VerticalAlignment="Center" Margin="0 10 0 0" Width="400">
+ <Run>Please ensure there are no thread residue in the system and press</Run>
+ <Run FontWeight="SemiBold">continue</Run>
+ </TextBlock>
+ </StackPanel>
+ </StackPanel>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg" VerticalAlignment="Center" Margin="50"></Image>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Preparing-->
+ <Grid controls:NavigationControl.NavigationName="Preparing" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding ContinueCommand}">Continue</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 20 0 0">
+ <StackPanel VerticalAlignment="Top" DockPanel.Dock="Top" Margin="0 40 0 0">
+ <TextBlock Margin="0 50 0 0" FontSize="{StaticResource TangoTitleFontSize}" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">
+ The system is now preparing...
+ </TextBlock>
+ <touch:TouchBusyIndicator Width="140" Height="140" StrokeThickness="8" IsIndeterminate="{Binding IsVisible}" Margin="0 50 0 0" Foreground="{StaticResource TangoGrayBrush}" />
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Ready For Loading-->
+ <Grid controls:NavigationControl.NavigationName="ReadyForLoading" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding ContinueCommand}">Continue</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 50 0 0">
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">
+ <Run>Please select the thread type you are going to load and press</Run>
+ <Run FontWeight="SemiBold">continue</Run>
+ </TextBlock>
+ <touch:TouchComboBox Margin="0 40 0 0" Width="500" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRml}" DisplayMemberPath="Name" Title="Select thread type"></touch:TouchComboBox>
+ </StackPanel>
+
+ <Grid>
+ <Grid Visibility="{Binding IsArcHead,Converter={StaticResource BooleanToVisibilityInverseConverter}}">
+ <touch:TouchGifAnimation Margin="50" Source="/Images/thread_loading.gif" VerticalAlignment="Center" Stretch="Uniform" EnableAnimation="{Binding IsVisible}" />
+ </Grid>
+
+ <Grid>
+ <commonControls:ImageGalleryControl Duration="00:00:03">
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.jpg"></Image>
+ <Image Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg"></Image>
+ </commonControls:ImageGalleryControl>
+ </Grid>
+ </Grid>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Finalizing-->
+ <Grid controls:NavigationControl.NavigationName="Finalizing" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="1" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding ContinueCommand}">Continue</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 20 0 0">
+ <StackPanel VerticalAlignment="Center" DockPanel.Dock="Top">
+ <TextBlock Margin="0 50 0 0" FontSize="{StaticResource TangoTitleFontSize}" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">
+ The system is now loading the thread...
+ </TextBlock>
+ <touch:TouchProgressBar Margin="50 40 50 0" Height="10" IsIndeterminate="{Binding IsVisible}" />
+ </StackPanel>
+
+ <Image VerticalAlignment="Center" Margin="50" Stretch="Uniform" Source="/Images/ThreadLoading/NewThread/machine_full.jpg"></Image>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Completed-->
+ <Grid controls:NavigationControl.NavigationName="Completed" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Center" Command="{Binding AbortCommand}">Close</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 50 0 0" >
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Thread loading completed successfully!</TextBlock>
+ <touch:TouchIcon Margin="0 40 0 0" Icon="CheckCircleOutline" HorizontalAlignment="Center" Foreground="{StaticResource TangoSuccessBrush}" Width="100" Height="100" />
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Preparation Error-->
+ <Grid controls:NavigationControl.NavigationName="PreparationError" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="2" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Left" Command="{Binding AbortCommand}">Close</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Right" Command="{Binding ContinueCommand}">Retry</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 50 0 0" >
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Something went wrong, press 'retry' to try again</TextBlock>
+ <touch:TouchIcon Icon="AlertCircleOutline" Margin="0 40 0 0" HorizontalAlignment="Center" Foreground="{StaticResource TangoErrorBrush}" Width="100" Height="100" />
+ <TextBlock Margin="0 10 0 0" FontSize="{StaticResource TangoSmallFontSize}" TextAlignment="Center" TextWrapping="Wrap" HorizontalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding Error}"></TextBlock>
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+
+ <!--Finalization Error-->
+ <Grid controls:NavigationControl.NavigationName="FinalizationError" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <DockPanel>
+ <UniformGrid Margin="50" Columns="2" DockPanel.Dock="Bottom" Height="55">
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Left" Command="{Binding AbortCommand}">Close</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource TangoHollowButton}" Width="250" HorizontalAlignment="Right" Command="{Binding ContinueCommand}">Retry</touch:TouchButton>
+ </UniformGrid>
+ <DockPanel Margin="0 50 0 0" >
+ <StackPanel DockPanel.Dock="Top">
+ <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}">Something went wrong, press 'retry' to try again</TextBlock>
+ <touch:TouchIcon Icon="AlertCircleOutline" Margin="0 40 0 0" HorizontalAlignment="Center" Foreground="{StaticResource TangoErrorBrush}" Width="100" Height="100" />
+ <TextBlock Margin="0 10 0 0" FontSize="{StaticResource TangoSmallFontSize}" TextAlignment="Center" TextWrapping="Wrap" HorizontalAlignment="Center" Foreground="{StaticResource TangoGrayTextBrush}" Text="{Binding Error}"></TextBlock>
+ </StackPanel>
+ </DockPanel>
+ </DockPanel>
+ </Grid>
+ </controls:NavigationControl>
+
+ </Grid>
+ </DockPanel>
+
+ <touch:TouchIconButton Command="{Binding AbortCommand}" HorizontalAlignment="Right" VerticalAlignment="Top" Icon="Close" Width="45" Height="45" Padding="14" Foreground="{StaticResource TangoDarkForegroundBrush}" />
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for PowerUpView.xaml
+ /// </summary>
+ 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<Rml> _rmls;
+ public List<Rml> 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<PPCSettings>();
+
+ 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<Rml> rmls = new List<Rml>();
+
+ 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}">
<Grid Margin="20">
<DockPanel>
- <StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
- <touch:TouchButton Command="{Binding CloseCommand}" CornerRadius="25" Style="{StaticResource TangoMessageBoxButton}" HorizontalContentAlignment="Center" DockPanel.Dock="Right" Width="120" Height="50" VerticalAlignment="Bottom">CANCEL</touch:TouchButton>
- <touch:TouchButton Command="{Binding OKCommand}" CornerRadius="25" Style="{StaticResource TangoMessageBoxButton}" Foreground="{StaticResource TangoPrimaryAccentBrush}" HorizontalContentAlignment="Center" DockPanel.Dock="Right" Width="120" Height="50" VerticalAlignment="Bottom">UPDATE</touch:TouchButton>
- </StackPanel>
+ <Grid DockPanel.Dock="Bottom">
+ <touch:TouchButton HorizontalAlignment="Left" CornerRadius="25" Command="{Binding CloseCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">CANCEL</touch:TouchButton>
+ <touch:TouchButton HorizontalAlignment="Right" CornerRadius="25" Command="{Binding OKCommand}" Style="{StaticResource TangoHollowButton}" Width="150" Height="50" VerticalAlignment="Bottom">UPDATE</touch:TouchButton>
+ </Grid>
<StackPanel>
<Image Source="../Images/update.png" Stretch="Uniform" Height="120"></Image>
- <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoHeaderFontSize}">UPDATE PACKAGE</TextBlock>
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoHeaderFontSize}">Tango Update Package</TextBlock>
<TextBlock Margin="20 10" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center">The selected file contains a software update package. Press 'UPDATE' to start updating your system.</TextBlock>
- <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
- <Run>Version</Run>
- <Run Text="{Binding Version}"></Run>
+ <TextBlock TextAlignment="Center" HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ <Run FontWeight="SemiBold">Application:</Run>
+ <Run Text="{Binding PublishInfo.ApplicationVersion}"></Run>
+ <LineBreak/>
+ <Run FontWeight="SemiBold">Firmware:</Run>
+ <Run Text="{Binding FirmwareVersion,Mode=OneWay}"></Run>
</TextBlock>
</StackPanel>
</DockPanel>
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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/error.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/getting-ready.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/service.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/GlobalStatus/shutting-down.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/Menu/backup.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/1.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/2.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/3.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/DryerClose/4.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/1.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/2.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/3.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/4.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/1.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/2.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/3.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/4.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/FeedingUnits/arc/5.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/GuidingUnits/1.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/1.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/2.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/3.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/4.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/5.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/6.JPG
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/ReadyForLoading/arc/7.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/TS1800_CloseUp_Feeder_P.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/NewThread/machine_full.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/1.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/2.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/3.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/4.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/ThreadLoading/TheDryer/5.jpg
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-big.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/backup-restore.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/firmware.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/loading_anim.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/machine-image.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/power_off_2.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/powerup.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/restore.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.gif
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/thread_loading_preview.png
Binary files 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Images/update_available.png
Binary files 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;
+ }
+
+ /// <summary>
+ /// Gets the module name.
+ /// </summary>
+ public override string Name
+ {
+ get
+ {
+ return "Internal";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module description.
+ /// </summary>
+ public override string Description
+ {
+ get
+ {
+ return "Internal Module";
+ }
+ }
+
+ /// <summary>
+ /// Gets the module cover image.
+ /// </summary>
+ public override BitmapSource Image
+ {
+ get
+ {
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets the module entry point view type.
+ /// </summary>
+ public override Type MainViewType
+ {
+ get
+ {
+ return typeof(InternalModuleView);
+ }
+ }
+
+ /// <summary>
+ /// Gets the permission required to see and load this module.
+ /// </summary>
+ public override Permissions Permission
+ {
+ get
+ {
+ return Permissions.RunPPC;
+ }
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ 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<IPPCApplicationManager>().ShutDown();
}
}
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs
index feb7e371f..bbabed225 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultStudioModuleLoader.cs
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Modules/DefaultPPCModuleLoader.cs
@@ -103,7 +103,7 @@ namespace Tango.PPC.UI.Modules
if (moduleAssembly != null)
{
- foreach (var moduleType in moduleAssembly.GetTypes().Where(x => !x.IsInterface && typeof(IPPCModule).IsAssignableFrom(x) && !x.IsAbstract))
+ foreach (var moduleType in moduleAssembly.GetLoadableTypes().Where(x => !x.IsInterface && typeof(IPPCModule).IsAssignableFrom(x) && !x.IsAbstract))
{
if (!AllModules.ToList().Exists(x => x.GetType() == moduleType))
{
@@ -131,10 +131,14 @@ namespace Tango.PPC.UI.Modules
UserModules.Clear();
- if (_authenticationProvider.CurrentUser != null)
+ 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());
}
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
/// <seealso cref="Tango.PPC.Common.Navigation.INavigationManager" />
public class DefaultNavigationManager : ExtendedObject, INavigationManager
{
- private event Action<Object, Object> NavigationCycleCompleted;
+ //private event Action<Object, Object> NavigationCycleCompleted;
+ //private event Action<Object, Object> BeforeNavigationCycleCompleted;
+ private class AwaitingVMResult
+ {
+ public PPCViewModel FromVM { get; set; }
+ public PPCViewModel ToVM { get; set; }
+ public Action Action { get; set; }
+ }
+ private List<AwaitingVMResult> _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<PPCViewModel> CurrentVMChanged;
+
private Stack<String> _navigationHistory;
+ private Object _currentVM;
/// <summary>
/// Gets the current view model.
/// </summary>
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 <see cref="DefaultNavigationManager"/> class.
/// </summary>
/// <param name="moduleLoader">The module loader.</param>
- public DefaultNavigationManager(IPPCModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider)
+ public DefaultNavigationManager(IPPCModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider, INotificationProvider notificationProvider)
{
+ IsBackEnabled = true;
+ _awaitingVMResults = new List<AwaitingVMResult>();
_navigationHistory = new Stack<String>();
_moduleLoader = moduleLoader;
+ _notificationProvider = notificationProvider;
NavigateToCommand = new RelayCommand<string>(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).
/// </summary>
/// <param name="fullPath">The full path.</param>
- public async Task<bool> NavigateTo(String fullPath, bool pushToHistory = true)
+ public async Task<bool> NavigateTo(String fullPath, bool pushToHistory = true, Action<PPCViewModel, PPCViewModel> onNavigating = null, Action<PPCViewModel, PPCViewModel> 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<NavigationControl>();
+ 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<NavigationControl>();
+
+ 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<NavigationControl>();
+ 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<NavigationControl>();
+ }
+ }
+ 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;
+ }
}
/// <summary>
@@ -267,46 +377,35 @@ namespace Tango.PPC.UI.Navigation
/// <param name="obj">The object.</param>
/// <param name="pushToHistory">if set to <c>true</c> [push to history].</param>
/// <returns></returns>
- public Task<TResult> NavigateForResult<TModule, TView, TResult, TObject>(TObject obj, bool pushToHistory = true)
+ public async Task<TResult> NavigateForResult<TModule, TView, TResult, TObject>(TObject obj, bool pushToHistory = true)
where TModule : IPPCModule
{
TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();
- var fromVM = _currentVM;
- Object toVM = null;
-
-
- Action<Object, Object> 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<TResult, TObject>)
- {
- (toVM as INavigationResultProvider<TResult, TObject>).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<TResult, TObject>)
+ if (to is INavigationResultProvider<TResult, TObject>)
{
- source.SetResult((from as INavigationResultProvider<TResult, TObject>).GetNavigationResult());
+ source.SetResult((to as INavigationResultProvider<TResult, TObject>).GetNavigationResult());
}
}
+ });
- NavigationCycleCompleted -= handler;
+ if (to is INavigationResultProvider<TResult, TObject>)
+ {
+ (to as INavigationResultProvider<TResult, TObject>).OnNavigationObjectReceived(obj);
}
- };
-
- NavigationCycleCompleted += handler;
+ });
- NavigateTo<TModule>(typeof(TView).Name, pushToHistory);
-
- return source.Task;
+ return await source.Task;
}
/// <summary>
@@ -320,25 +419,13 @@ namespace Tango.PPC.UI.Navigation
/// <returns></returns>
public Task<bool> NavigateWithObject<TModule, TView, TPass>(TPass obj, bool pushToHistory = true) where TModule : IPPCModule
{
- TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
-
- Action<Object, Object> handler = null;
-
- handler = (from, to) =>
+ return NavigateTo(typeof(TModule).Name + "." + typeof(TView).Name, pushToHistory, (fromVM, toVM) =>
{
- if (to is INavigationObjectReceiver<TPass>)
+ if (toVM is INavigationObjectReceiver<TPass>)
{
- (to as INavigationObjectReceiver<TPass>).OnNavigatedToWithObject(obj);
+ (toVM as INavigationObjectReceiver<TPass>).OnNavigatedToWithObject(obj);
}
-
- NavigationCycleCompleted -= handler;
- };
-
- NavigationCycleCompleted += handler;
-
- NavigateTo<TModule>(typeof(TView).Name, pushToHistory);
-
- return source.Task;
+ });
}
private Task<bool> 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;
+ /// <summary>
+ /// Gets a value indicating whether the back should be enabled.
+ /// </summary>
+ public bool IsBackEnabled
+ {
+ get { return _isBackEnabled; }
+ set { _isBackEnabled = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _isNavigating;
+ /// <summary>
+ /// Gets or sets a value indicating whether the navigation system is currently navigating.
+ /// </summary>
+ public bool IsNavigating
+ {
+ get { return _isNavigating; }
+ set
+ {
+ _isNavigating = value;
+ RaisePropertyChangedAuto();
+ }
+ }
+
/// <summary>
/// Navigates to the previous view if <see cref="P:Tango.PPC.Common.Navigation.INavigationManager.CanNavigateBack" /> is true.
/// </summary>
@@ -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
{
@@ -47,6 +49,16 @@ namespace Tango.PPC.UI.Notifications
public ObservableCollection<NotificationItem> NotificationItems { get; private set; }
/// <summary>
+ /// Gets the application bar items.
+ /// </summary>
+ public ObservableCollection<AppBarItem> AppBarItems { get; private set; }
+
+ /// <summary>
+ /// Gets the notification items view.
+ /// </summary>
+ public ICollectionView NotificationItemsView { get; private set; }
+
+ /// <summary>
/// Gets the collection of taskbar items.
/// </summary>
public ObservableCollection<TaskBarItem> TaskBarItems { get; private set; }
@@ -58,6 +70,10 @@ namespace Tango.PPC.UI.Notifications
{
NotificationsVisible = true;
NotificationItems = new ObservableCollection<NotificationItem>();
+
+ AppBarItems = new ObservableCollection<AppBarItem>();
+ CollectionViewSource.GetDefaultView(AppBarItems).SortDescriptions.Add(new SortDescription(nameof(AppBarItem.Priority), ListSortDirection.Ascending));
+
TaskBarItems = new ObservableCollection<TaskBarItem>();
_pendingMessageBoxes = new ConcurrentQueue<PendingNotification<MessageBoxVM, bool>>();
_pendingDialogs = new ConcurrentQueue<PendingNotification<DialogAndView, DialogViewVM>>();
@@ -66,6 +82,9 @@ namespace Tango.PPC.UI.Notifications
PopNotificationCommand = new RelayCommand<NotificationItem>((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
/// <returns></returns>
public async Task<T> ShowDialog<T>(T datacontext, FrameworkElement view) where T : DialogViewVM
{
- view.DataContext = datacontext;
-
- TangoIOC.Default.Inject(datacontext);
+ TaskCompletionSource<DialogViewVM> source = new TaskCompletionSource<DialogViewVM>();
- view.Loaded += (_, __) =>
+ InvokeUI(() =>
{
view.DataContext = datacontext;
- datacontext.OnShow();
- };
- TaskCompletionSource<DialogViewVM> source = new TaskCompletionSource<DialogViewVM>();
+ 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<DialogAndView, DialogViewVM>(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<DialogAndView, DialogViewVM>(new DialogAndView(datacontext, view), source));
+ }
+
+ });
var result = await source.Task;
return result as T;
@@ -376,23 +399,31 @@ namespace Tango.PPC.UI.Notifications
/// <returns></returns>
public Task<T> ShowDialog<T>(T datacontext) where T : DialogViewVM
{
- var callingAssembly = datacontext.GetType().Assembly;
- String viewName = datacontext.GetType().FullName.Replace("VM", "");
- var viewType = callingAssembly.GetType(viewName);
+ TaskCompletionSource<T> source = new TaskCompletionSource<T>();
- 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<T>(datacontext, view);
+ if (view == null)
+ {
+ throw new NullReferenceException("The view " + viewType.ToString() + " is not of type framework element.");
+ }
+
+ T result = await ShowDialog<T>(datacontext, view);
+ source.SetResult(result);
+ });
+
+ return source.Task;
}
/// <summary>
@@ -404,7 +435,15 @@ namespace Tango.PPC.UI.Notifications
/// <returns></returns>
public Task<T> ShowDialog<T>() where T : DialogViewVM
{
- return ShowDialog<T>(Activator.CreateInstance<T>());
+ TaskCompletionSource<T> source = new TaskCompletionSource<T>();
+
+ InvokeUI(async () =>
+ {
+ var result = await ShowDialog<T>(Activator.CreateInstance<T>());
+ source.SetResult(result);
+ });
+
+ return source.Task;
}
/// <summary>
@@ -442,22 +481,12 @@ namespace Tango.PPC.UI.Notifications
/// </summary>
public bool IsInGlobalBusyState { get; private set; }
- private AppBarItem _currentAppBarItem;
- /// <summary>
- /// Gets the current application bar item.
- /// </summary>
- public AppBarItem CurrentAppBarItem
- {
- get { return _currentAppBarItem; }
- set { _currentAppBarItem = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasAppBarItem)); }
- }
-
/// <summary>
/// Gets a value indicating whether this instance has application bar item.
/// </summary>
- public bool HasAppBarItem
+ public bool HasAppBarItems
{
- get { return CurrentAppBarItem != null; }
+ get { return AppBarItems.Count > 0; }
}
/// <summary>
@@ -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
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
- public AppBarItem PushAppBarItem<T>() where T : AppBarItem
+ public T PushAppBarItem<T>() where T : AppBarItem
{
- return PushAppBarItem(Activator.CreateInstance<T>());
+ return PushAppBarItem(Activator.CreateInstance<T>()) as T;
}
/// <summary>
@@ -489,8 +519,12 @@ namespace Tango.PPC.UI.Notifications
/// <param name="appBarItem">The application bar item.</param>
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));
+ });
}
/// <summary>
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
+{
+ /// <summary>
+ /// Represents a simple text message notification item which can be inserted into the application notifications panel.
+ /// </summary>
+ /// <seealso cref="Tango.PPC.Common.Notifications.NotificationItem" />
+ public class UpdateAvailableNotificationItem : NotificationItem
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UpdateAvailableNotificationItem"/> class.
+ /// </summary>
+ public UpdateAvailableNotificationItem()
+ {
+ CanClose = true;
+ }
+
+ private String _version;
+ /// <summary>
+ /// Gets or sets the message.
+ /// </summary>
+ public String Version
+ {
+ get { return _version; }
+ set { _version = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _isDatabaseUpdate;
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is database update.
+ /// </summary>
+ public bool IsDatabaseUpdate
+ {
+ get { return _isDatabaseUpdate; }
+ set { _isDatabaseUpdate = value; RaisePropertyChangedAuto(); }
+ }
+
+ /// <summary>
+ /// Gets or sets the view type.
+ /// </summary>
+ 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 @@
+<UserControl x:Class="Tango.PPC.UI.Notifications.NotificationItems.UpdateAvailableNotificationItemView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.UI.Notifications.NotificationItems"
+ xmlns:common="clr-namespace:Tango.PPC.Common.Converters"
+ mc:Ignorable="d"
+ x:Name="MessageNotificationItemControl"
+ d:DesignHeight="60" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:UpdateAvailableNotificationItem, IsDesignTimeCreatable=False}" MinHeight="90" Height="90" MaxHeight="150" Background="{StaticResource TangoPrimaryBackgroundBrush}">
+
+ <Grid>
+ <Border BorderThickness="0 0 0 2" BorderBrush="{StaticResource TangoPrimaryAccentBrush}" Padding="15">
+ <DockPanel>
+ <Image Source="/Images/update_available.png" MaxHeight="50" />
+
+ <Grid>
+ <TextBlock Margin="20 0 0 0" VerticalAlignment="Center" Visibility="{Binding IsDatabaseUpdate,Converter={StaticResource BooleanToVisibilityInverseConverter}}">
+ <Run>Version</Run>
+ <Run Foreground="{StaticResource TangoPrimaryAccentBrush}" FontWeight="SemiBold" Text="{Binding Version,FallbackValue='1.0.0.0',TargetNullValue='1.0.0.0'}"></Run>
+ <Run>is available!</Run>
+ <Run>Tap to start updating your system.</Run>
+ </TextBlock>
+ <TextBlock Margin="20 0 0 0" VerticalAlignment="Center" Text="Database updates are available. Tap to start updating your system." Visibility="{Binding IsDatabaseUpdate,Converter={StaticResource BooleanToVisibilityConverter}}"></TextBlock>
+ </Grid>
+ </DockPanel>
+ </Border>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Represents the <see cref="UpdateAvailableNotificationItemView"/> view.
+ /// </summary>
+ /// <seealso cref="System.Windows.Controls.UserControl" />
+ /// <seealso cref="System.Windows.Markup.IComponentConnector" />
+ 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;
@@ -59,6 +64,11 @@ namespace Tango.PPC.UI.PPCApplication
public event EventHandler SystemRestartRequired;
/// <summary>
+ /// Occurs when the updater utility has failed to perform the last update.
+ /// </summary>
+ public event EventHandler UpdaterFailed;
+
+ /// <summary>
/// Occurs when the application has started.
/// </summary>
public event EventHandler ApplicationStarted;
@@ -93,10 +103,15 @@ namespace Tango.PPC.UI.PPCApplication
/// </summary>
public bool IsShuttingDown { get; private set; }
+ private bool _isInTechnicianMode;
/// <summary>
/// Gets a value indicating whether the application is in technician mode.
/// </summary>
- public bool IsInTechnicianMode { get; private set; }
+ public bool IsInTechnicianMode
+ {
+ get { return _isInTechnicianMode; }
+ set { _isInTechnicianMode = value; RaisePropertyChangedAuto(); }
+ }
/// <summary>
/// Gets the application version.
@@ -125,6 +140,16 @@ namespace Tango.PPC.UI.PPCApplication
/// </summary>
public DateTime StartUpDate { get; private set; }
+ /// <summary>
+ /// Gets a value indicating whether an update has occurred before the application started.
+ /// </summary>
+ public bool IsAfterUpdate { get; private set; }
+
+ /// <summary>
+ /// Gets a value indicating whether the updater utility has failed to perform the last update.
+ /// </summary>
+ public bool IsUpdateFailed { get; private set; }
+
private bool _isScreenLocked;
/// <summary>
/// Gets or sets a value indicating whether the screen is currently locked.
@@ -136,15 +161,34 @@ namespace Tango.PPC.UI.PPCApplication
}
/// <summary>
+ /// Gets the firmware version.
+ /// </summary>
+ public Version FirmwareVersion
+ {
+ get
+ {
+ return Version.Parse(SettingsManager.Default.GetOrCreate<PPCSettings>().FirmwareVersion);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the application folder.
+ /// </summary>
+ public String StartPath { get; private set; }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="DefaultPPCApplicationManager"/> class.
/// </summary>
- 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<IPPCModuleLoader>((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
/// <summary>
/// Shutdown the application.
/// </summary>
- 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);
}
/// <summary>
/// Restarts the application.
/// </summary>
- 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<INavigationManager>();
+ 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<PPCViewModel>())
{
- 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
/// <summary>
/// Runs the updater utility and exits the application.
/// </summary>
- 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<INavigationManager>();
+ 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<PPCViewModel>())
{
- 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<PPCSettings>().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 @@
<SolidColorBrush x:Key="TangoMessageBoxHeaderSuccessBrush" Color="#F1FFF4" />
<SolidColorBrush x:Key="TangoMessageBoxHeaderQuestionBrush" Color="#DCE7FC" />
+ <SolidColorBrush x:Key="TangoEmergecyScreenBackgroundBrush" Color="#FFD9E4" />
+
</ResourceDictionary> \ 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 @@
<Compile Include="..\..\Versioning\GlobalVersionInfo.cs">
<Link>GlobalVersionInfo.cs</Link>
</Compile>
+ <Compile Include="AppBarItems\PowerUpAppBarItem.cs" />
+ <Compile Include="AppBarItems\PowerOffAppBarItem.cs" />
+ <Compile Include="AppBarItems\PowerUpAppBarItemView.xaml.cs">
+ <DependentUpon>PowerUpAppBarItemView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="AppBarItems\PowerOffAppBarItemView.xaml.cs">
+ <DependentUpon>PowerOffAppBarItemView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Authentication\DefaultAuthenticationProvider.cs" />
<Compile Include="Connectivity\DefaultConnectivityProvider.cs" />
<Compile Include="Connectivity\WiFiAuthenticationView.xaml.cs">
<DependentUpon>WiFiAuthenticationView.xaml</DependentUpon>
</Compile>
<Compile Include="Connectivity\WiFiAuthenticationViewVM.cs" />
+ <Compile Include="Controls\MachineStatusControl.xaml.cs">
+ <DependentUpon>MachineStatusControl.xaml</DependentUpon>
+ </Compile>
<Compile Include="Converters\AppBarItemConverter.cs" />
<Compile Include="Converters\ItemBaseConverter.cs" />
<Compile Include="Dialogs\CartridgeValidationView.xaml.cs">
@@ -129,6 +140,21 @@
<DependentUpon>InsufficientLiquidQuantityView.xaml</DependentUpon>
</Compile>
<Compile Include="Dialogs\InsufficientLiquidQuantityViewVM.cs" />
+ <Compile Include="Dialogs\SafetyLevelOperationsConfirmationView.xaml.cs">
+ <DependentUpon>SafetyLevelOperationsConfirmationView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\SafetyLevelOperationsConfirmationViewVM.cs" />
+ <Compile Include="Dialogs\ThreadBreakView.xaml.cs">
+ <DependentUpon>ThreadBreakView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\ThreadBreakViewVM.cs" />
+ <Compile Include="Dialogs\ThreadLoadingView.xaml.cs">
+ <DependentUpon>ThreadLoadingView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\PowerUpView.xaml.cs">
+ <DependentUpon>PowerUpView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Dialogs\PowerUpViewVM.cs" />
<Compile Include="Dialogs\ScreenLockView.xaml.cs">
<DependentUpon>ScreenLockView.xaml</DependentUpon>
</Compile>
@@ -138,21 +164,34 @@
</Compile>
<Compile Include="Dialogs\ScreenLockViewVM.cs" />
<Compile Include="Dialogs\TechnicianModeLoginViewVM.cs" />
+ <Compile Include="Dialogs\ThreadLoadingViewVM.cs" />
+ <Compile Include="Dialogs\FirmwareUpgradeFromFileView.xaml.cs">
+ <DependentUpon>FirmwareUpgradeFromFileView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Dialogs\UpdateFromFileView.xaml.cs">
<DependentUpon>UpdateFromFileView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Dialogs\FirmwareUpgradeFromFileViewVM.cs" />
<Compile Include="Dialogs\UpdateFromFileViewVM.cs" />
- <Compile Include="Modules\DefaultStudioModuleLoader.cs" />
+ <Compile Include="InternalModule.cs" />
+ <Compile Include="Modules\DefaultPPCModuleLoader.cs" />
<Compile Include="Navigation\DefaultNavigationManager.cs" />
<Compile Include="Notifications\DefaultNotificationProvider.cs" />
<Compile Include="Notifications\DialogAndView.cs" />
+ <Compile Include="Notifications\NotificationItems\UpdateAvailableNotificationItem.cs" />
+ <Compile Include="Notifications\NotificationItems\UpdateAvailableNotificationItemView.xaml.cs">
+ <DependentUpon>UpdateAvailableNotificationItemView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Notifications\PendingNotification.cs" />
<Compile Include="PPCApplication\DefaultPPCApplicationManager.cs" />
<Compile Include="Printing\DefaultPrintingManager.cs" />
+ <Compile Include="RemoteActions\DefaultRemoteActionsService.cs" />
<Compile Include="Threading\DefaultDispatcherProvider.cs" />
+ <Compile Include="ThreadLoading\DefaultThreadLoadingService.cs" />
<Compile Include="ViewModelLocator.cs" />
<Compile Include="ViewModels\EmergencyViewVM.cs" />
<Compile Include="ViewModels\ExternalBridgeViewVM.cs" />
+ <Compile Include="ViewModels\InternalModuleViewVM.cs" />
<Compile Include="ViewModels\LayoutViewVM.cs" />
<Compile Include="ViewModels\LoadingErrorViewVM.cs" />
<Compile Include="ViewModels\LoadingViewVM.cs" />
@@ -161,13 +200,18 @@
<Compile Include="ViewModels\MainViewVM.cs" />
<Compile Include="ViewModels\MachineUpdateViewVM.cs" />
<Compile Include="ViewModels\NoPermissionsViewVM.cs" />
+ <Compile Include="ViewModels\PowerOffViewVM.cs" />
<Compile Include="ViewModels\RestartingSystemViewVM.cs" />
+ <Compile Include="ViewModels\RestartingViewVM.cs" />
<Compile Include="ViewsContracts\ILayoutView.cs" />
<Compile Include="ViewsContracts\IMachineSetupView.cs" />
<Compile Include="ViewsContracts\IMachineUpdateView.cs" />
<Compile Include="Views\ExternalBridgeView.xaml.cs">
<DependentUpon>ExternalBridgeView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Views\InternalModuleView.xaml.cs">
+ <DependentUpon>InternalModuleView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Views\LayoutView.xaml.cs">
<DependentUpon>LayoutView.xaml</DependentUpon>
</Compile>
@@ -177,6 +221,12 @@
<Compile Include="Views\LoadingErrorView.xaml.cs">
<DependentUpon>LoadingErrorView.xaml</DependentUpon>
</Compile>
+ <Compile Include="Views\PowerOffView.xaml.cs">
+ <DependentUpon>PowerOffView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Views\RestartingView.xaml.cs">
+ <DependentUpon>RestartingView.xaml</DependentUpon>
+ </Compile>
<Compile Include="Views\LoadingView.xaml.cs">
<DependentUpon>LoadingView.xaml</DependentUpon>
</Compile>
@@ -198,15 +248,43 @@
<Compile Include="Views\RestartingSystemView.xaml.cs">
<DependentUpon>RestartingSystemView.xaml</DependentUpon>
</Compile>
+ <Page Include="AppBarItems\PowerUpAppBarItemView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="AppBarItems\PowerOffAppBarItemView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Connectivity\WiFiAuthenticationView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Controls\MachineStatusControl.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Dialogs\CartridgeValidationView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Dialogs\InsufficientLiquidQuantityView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\SafetyLevelOperationsConfirmationView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Dialogs\ThreadBreakView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ <Page Include="Dialogs\ThreadLoadingView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Dialogs\PowerUpView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@@ -218,6 +296,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Dialogs\FirmwareUpgradeFromFileView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Dialogs\UpdateFromFileView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -234,6 +316,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
+ <Page Include="Notifications\NotificationItems\UpdateAvailableNotificationItemView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Resources\Colors.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -250,6 +336,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Views\InternalModuleView.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="Views\LayoutView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -262,6 +352,14 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="Views\PowerOffView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Views\RestartingView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
<Page Include="Views\LoadingView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -327,18 +425,59 @@
<Resource Include="Images\GlobalStatus\service_Anim.gif" />
<Resource Include="Images\GlobalStatus\shutdown_icon_Anim.gif" />
<Resource Include="Images\GlobalStatus\standby_Anim.gif" />
- <Resource Include="Images\cartridge_validation.png" />
<Resource Include="Images\bug.png" />
- <Content Include="..\..\Build\ColorLib\Debug\Tango.ColorLib_v1.dll">
- <Link>Tango.ColorLib_v1.dll</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="..\..\Build\ColorLib\Debug\Tango.ColorLib_v2.dll">
- <Link>Tango.ColorLib_v2.dll</Link>
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
+ <Resource Include="Images\cartridge_validation.png" />
+ <Resource Include="Images\machine-image.png" />
+ <Resource Include="Images\Menu\backup.png" />
+ <Resource Include="Images\backup-restore.png" />
+ <Resource Include="Images\restore.png" />
+ <Resource Include="Images\backup-big.png" />
+ <Resource Include="Images\GlobalStatus\getting-ready.png" />
+ <Resource Include="Images\GlobalStatus\shutting-down.png" />
+ <Resource Include="Images\GlobalStatus\error.png" />
+ <Resource Include="Images\GlobalStatus\service.png" />
+ <Resource Include="Images\update_available.png" />
+ <Resource Include="Images\powerup.gif" />
+ <Resource Include="Images\power_off.gif" />
+ <Resource Include="Images\thread_loading.gif" />
+ <Resource Include="Images\thread_loading.png" />
+ <Resource Include="Images\firmware.png" />
+ <Resource Include="Images\power_off_2.gif" />
+ <Resource Include="Images\loading_anim.gif" />
+ <Resource Include="Images\thread_loading_preview.png" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\1.JPG" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\2.JPG" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\3.JPG" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\4.JPG" />
+ <Resource Include="Images\ThreadLoading\GuidingUnits\1.JPG" />
+ <Resource Include="Images\ThreadLoading\TheDryer\1.jpg" />
+ <Resource Include="Images\ThreadLoading\TheDryer\2.jpg" />
+ <Resource Include="Images\ThreadLoading\TheDryer\3.jpg" />
+ <Resource Include="Images\ThreadLoading\TheDryer\4.jpg" />
+ <Resource Include="Images\ThreadLoading\TheDryer\5.jpg" />
+ <Resource Include="Images\ThreadLoading\DryerClose\1.jpg" />
+ <Resource Include="Images\ThreadLoading\DryerClose\2.jpg" />
+ <Resource Include="Images\ThreadLoading\DryerClose\3.jpg" />
+ <Resource Include="Images\ThreadLoading\DryerClose\4.jpg" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\arc\1.jpg" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\arc\2.jpg" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\arc\3.jpg" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\arc\4.jpg" />
+ <Resource Include="Images\ThreadLoading\FeedingUnits\arc\5.jpg" />
+ <Resource Include="Images\ThreadLoading\NewThread\TS1800_CloseUp_Feeder_P.jpg" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\1.jpg" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\2.JPG" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\3.JPG" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\4.JPG" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\5.JPG" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\6.JPG" />
+ <Resource Include="Images\ThreadLoading\NewThread\ReadyForLoading\arc\7.jpg" />
+ <Resource Include="Images\ThreadLoading\NewThread\machine_full.jpg" />
<Content Include="Manifests\release.xml" />
<Content Include="Manifests\debug.xml" />
+ <None Include="firmware_package.tfp">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@@ -373,6 +512,10 @@
<Project>{4399af76-db52-4cfb-8020-6f85bdb29fd5}</Project>
<Name>Tango.Explorer</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\Tango.Insights\Tango.Insights.csproj">
+ <Project>{4A55C185-3F8D-41B0-8815-C15F6213A14A}</Project>
+ <Name>Tango.Insights</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\Tango.Integration\Tango.Integration.csproj">
<Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project>
<Name>Tango.Integration</Name>
@@ -421,6 +564,10 @@
<Project>{6aa425c9-ea6a-4b01-aaed-5ff122e8b663}</Project>
<Name>Tango.WiFi</Name>
</ProjectReference>
+ <ProjectReference Include="..\Modules\Tango.PPC.BackupRestore\Tango.PPC.BackupRestore.csproj">
+ <Project>{bc2753f8-c0f7-48f5-a85c-149ec7a2f8c7}</Project>
+ <Name>Tango.PPC.BackupRestore</Name>
+ </ProjectReference>
<ProjectReference Include="..\Modules\Tango.PPC.BugReporting\Tango.PPC.BugReporting.csproj">
<Project>{8146fa0a-0725-4a1a-82e6-696c58f33a2b}</Project>
<Name>Tango.PPC.BugReporting</Name>
@@ -437,6 +584,10 @@
<Project>{91b70e9b-66a7-4873-ae10-400e71cf404f}</Project>
<Name>Tango.PPC.MachineSettings</Name>
</ProjectReference>
+ <ProjectReference Include="..\Modules\Tango.PPC.Maintenance\Tango.PPC.Maintenance.csproj">
+ <Project>{011470ac-6bd6-4366-b5f2-c82c065d4a84}</Project>
+ <Name>Tango.PPC.Maintenance</Name>
+ </ProjectReference>
<ProjectReference Include="..\Modules\Tango.PPC.Storage\Tango.PPC.Storage.csproj">
<Project>{04febb02-f782-4b96-b47d-f6902afa43be}</Project>
<Name>Tango.PPC.Storage</Name>
@@ -449,6 +600,40 @@
<Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
<Name>Tango.PPC.Common</Name>
</ProjectReference>
+ <ProjectReference Include="..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ </ProjectReference>
+ <!--ColorLib-->
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v4\Tango.ColorLib_v4.vcxproj">
+ <Project>{E9528353-7D41-4AA8-BBAC-D65B7FE3A0D6}</Project>
+ <Name>Tango.ColorLib_v4</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v3\Tango.ColorLib_v3.vcxproj">
+ <Project>{A3A8ADA0-C150-4E30-A60D-11F291FDBF7A}</Project>
+ <Name>Tango.ColorLib_v3</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v2\Tango.ColorLib_v2.vcxproj">
+ <Project>{1A3FC7FB-403C-4B3D-B705-28FCE11317DD}</Project>
+ <Name>Tango.ColorLib_v2</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
+ <ProjectReference Include="..\..\ColorLib\Tango.ColorLib_v1\Tango.ColorLib_v1.vcxproj">
+ <Project>{CF4C66B0-CD13-4D31-8133-339A01E7E6F2}</Project>
+ <Name>Tango.ColorLib_v1</Name>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>Content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
+ <!--ColorLib-->
</ItemGroup>
<ItemGroup>
<Resource Include="Images\liquid.png" />
@@ -504,6 +689,7 @@
<Resource Include="Images\machine-update.png" />
<Resource Include="Images\home.png" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@@ -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</PostBuildEvent>
+if $(ConfigurationName) == Debug copy /Y "$(TargetDir)Packages" "$(TargetDir)"</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
- <PreBuildEvent>copy /Y "$(ProjectDir)Manifests\$(ConfigurationName).xml" "$(ProjectDir)app.manifest"</PreBuildEvent>
+ <PreBuildEvent>copy /Y "$(ProjectDir)Manifests\$(ConfigurationName).xml" "$(ProjectDir)app.manifest"
+</PreBuildEvent>
</PropertyGroup>
<ProjectExtensions>
<VisualStudio>
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<ThreadLoadingViewVM>(new ThreadLoadingViewVM());
+ _dialogShown = false;
+ });
+ }
+ }
+
+ public async void StartThreadLoadingWizard()
+ {
+ _dialogShown = true;
+ await _notificationsProvider.ShowDialog<ThreadLoadingViewVM>(new ThreadLoadingViewVM(true));
+ _dialogShown = false;
+ }
+
+ public async void StartThreadBreakWizard()
+ {
+ if (!_dialogShown)
+ {
+ _dialogShown = true;
+ var vm = await _notificationsProvider.ShowDialog<ThreadBreakViewVM>();
+ _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<IUnifiedWriteFilterManager>();
TangoIOC.Default.Unregister<IOperationSystemManager>();
TangoIOC.Default.Unregister<PPCWebClient>();
+ TangoIOC.Default.Unregister<IBackupManager>();
+ TangoIOC.Default.Unregister<IPackageRunner>();
+ TangoIOC.Default.Unregister<IMachineDataSynchronizer>();
+ TangoIOC.Default.Unregister<IConsoleEngineService>();
+ TangoIOC.Default.Unregister<IRemoteDesktopService>();
+ TangoIOC.Default.Unregister<IPerformanceService>();
+ TangoIOC.Default.Unregister<ISystemInfoService>();
+ TangoIOC.Default.Unregister<IFileSystemService>();
+ TangoIOC.Default.Unregister<IRemoteJobService>();
+ TangoIOC.Default.Unregister<IRemoteSqlService>();
+ TangoIOC.Default.Unregister<IInsightsService>();
+ TangoIOC.Default.Unregister<IRemoteActionsService>();
+ TangoIOC.Default.Unregister<IThreadLoadingService>();
+ TangoIOC.Default.Unregister<IDataStoreService>();
+
+ if (App.StartupArgs != null && App.StartupArgs.Contains("-webDebug"))
+ {
+ TangoIOC.Default.Register<PPCWebClient, PPCWebClient>(new PPCWebClient("http://localhost:1111", null));
+ }
+ else
+ {
+ TangoIOC.Default.Register<PPCWebClient, PPCWebClient>(new PPCWebClient());
+ }
- TangoIOC.Default.Register<PPCWebClient, PPCWebClient>(new PPCWebClient());
TangoIOC.Default.Register<IDispatcherProvider, DefaultDispatcherProvider>(new DefaultDispatcherProvider(Application.Current.Dispatcher));
TangoIOC.Default.Register<INotificationProvider, DefaultNotificationProvider>();
TangoIOC.Default.Register<IAuthenticationProvider, DefaultAuthenticationProvider>();
@@ -80,11 +119,14 @@ namespace Tango.PPC.UI
TangoIOC.Default.Register<INavigationManager, DefaultNavigationManager>();
TangoIOC.Default.Register<IMachineProvider, DefaultMachineProvider>();
TangoIOC.Default.Register<IEventLogger, DefaultEventLogger>();
+ TangoIOC.Default.Register<IMachineDataSynchronizer, DefaultMachineDataSynchronizer>();
TangoIOC.Default.Register<IPPCApplicationManager, DefaultPPCApplicationManager>();
TangoIOC.Default.Register<ExternalBridgeScanner, ExternalBridgeScanner>();
TangoIOC.Default.Register<IDiagnosticsFrameProvider, DefaultDiagnosticsFrameProvider>();
TangoIOC.Default.Register<IPPCExternalBridgeService, PPCExternalBridgeService>();
+ TangoIOC.Default.Register<IConsoleEngineService, DefaultConsoleEngineService>();
TangoIOC.Default.Register<IRemoteAssistanceProvider, DefaultRemoteAssistanceProvider>();
+ TangoIOC.Default.Register<IPackageRunner, DefaultPackageRunner>();
TangoIOC.Default.Register<IMachineSetupManager, MachineSetupManager>();
TangoIOC.Default.Register<IMachineUpdateManager, MachineUpdateManager>();
TangoIOC.Default.Register<IPrintingManager, DefaultPrintingManager>();
@@ -93,8 +135,17 @@ namespace Tango.PPC.UI
TangoIOC.Default.Register<IStorageProvider, DefaultStorageProvider>();
TangoIOC.Default.Register<IUnifiedWriteFilterManager, AlternativeUnifiedWriteFilterManager>();
TangoIOC.Default.Register<IOperationSystemManager, DefaultOperationSystemManager>();
-
- //TangoIOC.Default.Register<TeamFoundationServiceExtendedClient>(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa"));
+ TangoIOC.Default.Register<IBackupManager, DefaultBackupManager>();
+ TangoIOC.Default.Register<IPerformanceService, DefaultPerformanceService>();
+ TangoIOC.Default.Register<ISystemInfoService, DefaultSystemInfoService>();
+ TangoIOC.Default.Register<IFileSystemService, DefaultFileSystemService>();
+ TangoIOC.Default.Register<IRemoteDesktopService, DefaultRemoteDesktopService>();
+ TangoIOC.Default.Register<IRemoteJobService, DefaultRemoteJobService>();
+ TangoIOC.Default.Register<IRemoteSqlService, DefaultRemoteSqlService>();
+ TangoIOC.Default.Register<IInsightsService, DefaultInsightsService>();
+ TangoIOC.Default.Register<IRemoteActionsService, DefaultRemoteActionsService>();
+ TangoIOC.Default.Register<IThreadLoadingService, DefaultThreadLoadingService>();
+ TangoIOC.Default.Register<IDataStoreService, DefaultDataStoreService>();
TangoIOC.Default.Register<LoadingViewVM>();
TangoIOC.Default.Register<MainViewVM>();
@@ -107,6 +158,9 @@ namespace Tango.PPC.UI
TangoIOC.Default.Register<NoPermissionsViewVM>();
TangoIOC.Default.Register<RestartingSystemViewVM>();
TangoIOC.Default.Register<EmergencyViewVM>();
+ TangoIOC.Default.Register<RestartingViewVM>();
+ TangoIOC.Default.Register<InternalModuleViewVM>();
+ TangoIOC.Default.Register<PowerOffViewVM>();
TangoIOC.Default.GetInstance<IPPCApplicationManager>().ContentRendered += (_, __) =>
@@ -212,5 +266,29 @@ namespace Tango.PPC.UI
return TangoIOC.Default.GetInstance<EmergencyViewVM>();
}
}
+
+ public static RestartingViewVM RestartingViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<RestartingViewVM>();
+ }
+ }
+
+ public static InternalModuleViewVM InternalModuleViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<InternalModuleViewVM>();
+ }
+ }
+
+ public static PowerOffViewVM PowerOffViewVM
+ {
+ get
+ {
+ return TangoIOC.Default.GetInstance<PowerOffViewVM>();
+ }
+ }
}
} \ 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
/// <summary>
- /// Handles the <see cref="ExternalBridgeService.ClientDisconnected"/> event.
+ /// Handles the <see cref="ExternalBridgeService.FullControlSessionDisconnected"/> event.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
- 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
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ExternalBridgeClientConnectedEventArgs"/> instance containing the event data.</param>
- 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<ILayoutView>
{
private JobHandler _jobHandler;
+ private bool _resettingDevice;
/// <summary>
/// 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;
+ /// <summary>
+ /// Gets or sets a value indicating whether ink filling or waste emptying is active.
+ /// </summary>
+ public bool IsInkFillingOrWasteEmptying
+ {
+ get { return _isInkFillingOrWasteEmptying; }
+ set { _isInkFillingOrWasteEmptying = value; RaisePropertyChangedAuto(); }
+ }
+
+ private List<CartridgeModel> _cartridges;
+ public List<CartridgeModel> Cartridges
+ {
+ get { return _cartridges; }
+ set { _cartridges = value; RaisePropertyChangedAuto(); }
+ }
+
#endregion
#region Commands
@@ -121,6 +225,21 @@ namespace Tango.PPC.UI.ViewModels
/// </summary>
public RelayCommand RestartApplicationCommand { get; set; }
+ /// <summary>
+ /// Gets or sets the power off command.
+ /// </summary>
+ public RelayCommand PowerOffCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the reset command.
+ /// </summary>
+ public RelayCommand ResetCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the stand by command.
+ /// </summary>
+ 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<MachineUpdateViewVM>().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
}
}
+ /// <summary>
+ /// Powers off the machine.
+ /// </summary>
+ 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());
+ }
+ }
+ }
+
+ /// <summary>
+ /// Resets the machine.
+ /// </summary>
+ 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<MachineUpdateViewVM>().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);
}
/// <summary>
@@ -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
/// </summary>
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<IMachineUpdateView>
+ public class MachineUpdateViewVM : PPCViewModel<IMachineUpdateView>, 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;
+ }
+ }
+
+ /// <summary>
+ /// Called when the navigation system has navigated to this VM view.
+ /// </summary>
+ 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<ExplorerFileItem> 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 NotificationProvider.ShowError($"The selected update package (v{packageFile.Version.ToString()}) contains an older software version.");
+ 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<ExplorerFileItem> 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)
+ {
+ 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<double>()
+ {
+ 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<double>("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<double>()
+ {
+ 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<double>("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;
/// <summary>
@@ -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<PowerUpAppBarItem>();
+ _powerUpAppBar.Priority = AppBarPriority.Low;
+ }
+ });
}
+ #endregion
+
#region Event Handlers
/// <summary>
@@ -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<Rml> rmls = new List<Rml>();
+
+ 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<PowerUpViewVM>(vm);
+ _isPowerUpDialogShown = false;
+
+ await Task.Factory.StartNew(() =>
+ {
+ LogManager.Log("Power up screen closed.");
+
+ try
+ {
+ using (ObservablesContext db = ObservablesContext.CreateDefault())
+ {
+ List<ProcessParametersTable> processTables = new List<ProcessParametersTable>();
+
+ 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<InternalModule>(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<InternalModule>(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}">
- <Grid>
+ <Grid Background="{StaticResource TangoEmergecyScreenBackgroundBrush}">
<DockPanel Margin="20 60 20 20">
- <StackPanel DockPanel.Dock="Top">
- <Image Source="../Images/warning-red.png" Width="300" Stretch="Uniform" HorizontalAlignment="Center"></Image>
- <TextBlock HorizontalAlignment="Center" Margin="0 40 0 0" FontSize="{StaticResource TangoHeaderFontSize}">Emergency Switch Activated</TextBlock>
- <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoTitleFontSize}">Please release the emergency switch to exit this screen.</TextBlock>
+ <StackPanel DockPanel.Dock="Top" HorizontalAlignment="Center">
+ <touch:TouchIcon Icon="Alert" Width="120" Height="120" Foreground="{StaticResource TangoErrorBrush}" HorizontalAlignment="Center"></touch:TouchIcon>
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" Foreground="{StaticResource TangoErrorBrush}" FontSize="{StaticResource TangoHeaderFontSize}" FontWeight="SemiBold">EMERGENCY PUSH BUTTON PRESSED</TextBlock>
+ <TextBlock Margin="0 60 0 0" FontWeight="SemiBold" FontSize="24">How to handle:</TextBlock>
+ <Rectangle Margin="0 20 240 5" StrokeThickness="1" Stroke="{StaticResource TangoGrayBrush}" />
+ <TextBlock Margin="0 8 0 0" FontSize="{StaticResource TangoTitleFontSize}">1. Verify that it is safe to restart the system.</TextBlock>
+ <TextBlock Margin="0 8 0 0" FontSize="{StaticResource TangoTitleFontSize}">2. Release the emergency button.</TextBlock>
+ <TextBlock Margin="0 8 0 0" FontSize="{StaticResource TangoTitleFontSize}">3. Press the power button to power up the system.</TextBlock>
+
+ <Image Source="../Images/machine-image.png" Width="500" HorizontalAlignment="Left" Margin="0 150 0 0" />
</StackPanel>
</DockPanel>
</Grid>
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}">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
- <Grid HorizontalAlignment="Center">
- <Image Source="/Images/machine-trans.png" Stretch="None" RenderOptions.BitmapScalingMode="Fant"></Image>
- <touch:TouchIcon Icon="Wifi" Foreground="{StaticResource TangoGreenBrush}" Width="30" Height="30" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 25 30">
+ <Grid HorizontalAlignment="Center" VerticalAlignment="Center" >
+ <Ellipse Stroke="{StaticResource TangoDarkForegroundBrush}" Width="50" Height="50"/>
+ <localControls:MachineStatusControl Margin="0 0 0 -1" VerticalAlignment="Center" DataContext="{Binding MachineProvider.MachineOperator}" />
+ </Grid>
+ <Grid HorizontalAlignment="Center" Margin="0 20 0 0">
+ <Image Source="/Images/machine.png" Stretch="None" RenderOptions.BitmapScalingMode="Fant"></Image>
+ <touch:TouchIcon Icon="Wifi" Foreground="{StaticResource TangoGreenBrush}" Width="30" Height="30" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 40 45">
<touch:TouchIcon.Style>
<Style TargetType="touch:TouchIcon">
<Style.Triggers>
- <DataTrigger Binding="{Binding ExternalBridgeService.IsInSession}" Value="True">
+ <DataTrigger Binding="{Binding ExternalBridgeService.HasSessions}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Blink">
<Storyboard>
@@ -43,8 +48,8 @@
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 50 0 0" FontSize="{StaticResource TangoTitleFontSize}">This machine is currently being controlled by a remote client</TextBlock>
<controls:TableGrid Margin="0 30 0 0" HorizontalAlignment="Center" RowHeight="30" Width="280">
- <TextBlock FontWeight="Bold">IP Address:</TextBlock>
- <TextBlock Text="{Binding Connection.IpAddress}"></TextBlock>
+ <TextBlock FontWeight="Bold">Address:</TextBlock>
+ <TextBlock Text="{Binding Connection.Address}"></TextBlock>
<TextBlock FontWeight="Bold">Host Name:</TextBlock>
<TextBlock Text="{Binding Connection.Request.HostName}"></TextBlock>
@@ -57,7 +62,7 @@
<TextBlock FontWeight="Bold" Text="Transfer Rate:" />
<TextBlock>
- <Run Text="{Binding ExternalBridgeService.Adapter.TransferRate,Converter={StaticResource ByteArrayToFileSizeConverter},Mode=OneWay}"></Run>
+ <Run Text="{Binding ExternalBridgeService.FullControlSessionReceiver.Adapter.TransferRate,Converter={StaticResource ByteArrayToFileSizeConverter},Mode=OneWay}"></Run>
<Run Text="/ sec"></Run>
</TextBlock>
</controls:TableGrid>
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml
new file mode 100644
index 000000000..88981a9fa
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml
@@ -0,0 +1,18 @@
+<UserControl x:Class="Tango.PPC.UI.Views.InternalModuleView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:local="clr-namespace:Tango.PPC.UI.Views"
+ xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
+ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
+ xmlns:vm="clr-namespace:Tango.PPC.UI.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.UI"
+ mc:Ignorable="d"
+ d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:InternalModuleViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.InternalModuleViewVM}">
+ <Grid>
+ <controls:NavigationControl TransitionType="Zoom" KeepElementsAttached="True">
+ <local:PowerOffView/>
+ </controls:NavigationControl>
+ </Grid>
+</UserControl>
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.xaml.cs
new file mode 100644
index 000000000..f67d16dd9
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/InternalModuleView.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
+{
+ /// <summary>
+ /// Interaction logic for InternalModuleView.xaml
+ /// </summary>
+ public partial class InternalModuleView : UserControl
+ {
+ public InternalModuleView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml
index 890d3863b..3e1f50e41 100644
--- a/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/Views/LayoutView.xaml
@@ -14,6 +14,7 @@
xmlns:commonControls="clr-namespace:Tango.PPC.Common.Controls;assembly=Tango.PPC.Common"
xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI"
xmlns:components="clr-namespace:Tango.Touch.Components;assembly=Tango.Touch"
+ xmlns:locaControls="clr-namespace:Tango.PPC.UI.Controls"
xmlns:keyboard="clr-namespace:Tango.Touch.Keyboard;assembly=Tango.Touch"
mc:Ignorable="d"
d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:LayoutViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.LayoutViewVM}">
@@ -129,6 +130,21 @@
<Border Background="{StaticResource TangoPowerMenuOpenedBackgroundBrush}" Height="350" Padding="20" RenderTransformOrigin="0.5,1" VerticalAlignment="Bottom">
+ <Border.Resources>
+ <Style x:Key="PowerButton" TargetType="touch:TouchButton" BasedOn="{StaticResource TangoLinkButton}">
+ <Setter Property="Foreground" Value="{StaticResource TangoPrimaryBackgroundBrush}"></Setter>
+ <Setter Property="FontSize" Value="{StaticResource TangoTitleFontSize}"></Setter>
+ <Setter Property="HorizontalAlignment" Value="Left"></Setter>
+ <Setter Property="VerticalAlignment" Value="Center"></Setter>
+ <Setter Property="Padding" Value="50 20"></Setter>
+ <Setter Property="Height" Value="Auto"></Setter>
+ <Style.Triggers>
+ <Trigger Property="IsEnabled" Value="False">
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
+ </Trigger>
+ </Style.Triggers>
+ </Style>
+ </Border.Resources>
<Border.Style>
<Style TargetType="Border">
<Setter Property="RenderTransform">
@@ -158,7 +174,7 @@
</Border.Style>
<Grid>
<Grid.RowDefinitions>
- <RowDefinition Height="1*"/>
+ <RowDefinition Height="1.4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
@@ -170,9 +186,10 @@
<Image Source="/Images/power-machine.png" Margin="30" />
- <UniformGrid Grid.Column="1" Rows="2">
- <touch:TouchButton HorizontalAlignment="Left" VerticalAlignment="Center" Padding="50 20" Height="Auto" Style="{StaticResource TangoLinkButton}" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoPrimaryBackgroundBrush}">Turn Off</touch:TouchButton>
- <touch:TouchButton HorizontalAlignment="Left" VerticalAlignment="Center" Padding="50 20" Height="Auto" Style="{StaticResource TangoLinkButton}" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoPrimaryBackgroundBrush}">Stand By</touch:TouchButton>
+ <UniformGrid Grid.Column="1" Rows="3">
+ <touch:TouchButton Style="{StaticResource PowerButton}" Command="{Binding PowerOffCommand}">Turn Off</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource PowerButton}" Command="{Binding StandByCommand}">Stand By</touch:TouchButton>
+ <touch:TouchButton Style="{StaticResource PowerButton}" Command="{Binding ResetCommand}">Reset</touch:TouchButton>
</UniformGrid>
</Grid>
@@ -185,7 +202,7 @@
</Grid.ColumnDefinitions>
<Image Source="/Images/power-tablet.png" Margin="30" />
- <touch:TouchButton Command="{Binding RestartApplicationCommand}" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="50 20" Height="Auto" Style="{StaticResource TangoLinkButton}" Foreground="{StaticResource TangoPrimaryBackgroundBrush}" FontSize="{StaticResource TangoTitleFontSize}">Restart</touch:TouchButton>
+ <touch:TouchButton Command="{Binding RestartApplicationCommand}" Grid.Column="1" Style="{StaticResource PowerButton}">Restart</touch:TouchButton>
</Grid>
</Grid>
</Border>
@@ -232,20 +249,21 @@
<touch:TouchNotificationBar
NotificationBarVisibility="{Binding NotificationProvider.NotificationsVisible,Converter={StaticResource BooleanToVisibilityConverter}}"
- HasNotifications="{Binding NotificationProvider.HasNotificationItems}"
- Notifications="{Binding NotificationProvider.NotificationItems}"
- ItemExpandedPropertyPath="IsExpanded">
+ HasNotifications="{Binding NotificationProvider.HasNotificationItems}" Notifications="{Binding NotificationProvider.NotificationItems}">
<touch:TouchNotificationBar.NotificationTemplate>
<DataTemplate>
<components:Ripple Padding="0">
<Grid Background="Transparent">
- <i:Interaction.Triggers>
- <i:EventTrigger EventName="PreviewMouseUp">
- <i:InvokeCommandAction Command="{Binding PressedCommand}" />
- </i:EventTrigger>
- </i:Interaction.Triggers>
- <ContentControl Content="{Binding Converter={StaticResource ItemBaseConverter}}"/>
- <touch:TouchIconButton Visibility="{Binding CanClose,Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" Background="Transparent" Padding="35" Style="{StaticResource TangoRoundTouchIconButton}" Command="{Binding CloseCommand}" CommandParameter="{Binding}" HorizontalAlignment="Right" MaxHeight="90" Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}" Icon="Close" Foreground="{StaticResource TangoDarkForegroundBrush}" />
+ <touch:TouchClickableControl Command="{Binding PressedCommand}">
+ <ContentControl Content="{Binding Converter={StaticResource ItemBaseConverter}}"/>
+ </touch:TouchClickableControl>
+ <Grid Width="40" HorizontalAlignment="Right" VerticalAlignment="Stretch" Visibility="{Binding CanClose,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <Grid Margin="0 0 20 0" HorizontalAlignment="Right" VerticalAlignment="Center" Width="18" Height="18">
+ <!--<Ellipse Fill="Black" StrokeThickness="1" Stroke="{StaticResource TangoDarkForegroundBrush}" />-->
+ <touch:TouchIcon Icon="Close" Foreground="Black" />
+ </Grid>
+ <touch:TouchButton Opacity="0" Background="Red" Style="{StaticResource TangoFlatButton}" Command="{Binding CloseCommand}" CommandParameter="{Binding}" Foreground="{StaticResource TangoPrimaryBackgroundBrush}" Padding="5" />
+ </Grid>
</Grid>
</components:Ripple>
</DataTemplate>
@@ -254,46 +272,13 @@
<Border BorderThickness="0 0 0 1" BorderBrush="{StaticResource TangoDividerBrush}" DockPanel.Dock="Top">
<DockPanel>
<Border BorderThickness="0 0 1 0" BorderBrush="{StaticResource TangoDividerBrush}">
- <touch:TouchHamburgerButton Width="100" Height="100" Padding="15" Command="{Binding MenuOrBackCommand}" EnableDropShadow="False" Foreground="{StaticResource TangoPrimaryAccentBrush}" IsBack="{Binding NavigationManager.CanNavigateBack}">
+ <touch:TouchHamburgerButton IsHitTestVisible="{Binding NavigationManager.IsNavigating,Converter={StaticResource BooleanInverseConverter}}" IsEnabled="{Binding NavigationManager.IsBackEnabled}" Width="100" Height="100" Padding="15" Command="{Binding MenuOrBackCommand}" EnableDropShadow="False" Foreground="{StaticResource TangoPrimaryAccentBrush}" IsBack="{Binding NavigationManager.CanNavigateBack}"/>
- </touch:TouchHamburgerButton>
</Border>
<Grid DockPanel.Dock="Right" Margin="0 0 20 0">
<StackPanel Orientation="Horizontal">
<StackPanel x:Name="techPressElement" VerticalAlignment="Center" Background="Transparent">
- <touch:TouchGifAnimation Width="36" HorizontalAlignment="Center" EnableAnimation="True">
- <touch:TouchGifAnimation.Style>
- <Style TargetType="touch:TouchGifAnimation">
- <Setter Property="Source" Value="/Images/GlobalStatus/standby.png"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Disconnected}">
- <Setter Property="Source" Value="/Images/GlobalStatus/machine_off_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Standby}">
- <Setter Property="Source" Value="/Images/GlobalStatus/standby_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.ReadyToDye}">
- <Setter Property="Source" Value="/Images/GlobalStatus/Ready_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.GettingReady}">
- <Setter Property="Source" Value="/Images/GlobalStatus/getting_ready_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Printing}">
- <Setter Property="Source" Value="/Images/GlobalStatus/dyeing_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.ShuttingDown}">
- <Setter Property="Source" Value="/Images/GlobalStatus/shutdown_icon_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Error}">
- <Setter Property="Source" Value="/Images/GlobalStatus/error_Anim.gif"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Service}">
- <Setter Property="Source" Value="/Images/GlobalStatus/service_Anim.gif"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </touch:TouchGifAnimation.Style>
- </touch:TouchGifAnimation>
+ <locaControls:MachineStatusControl HorizontalAlignment="Center" DataContext="{Binding MachineProvider.MachineOperator}" />
<TextBlock Margin="0 10 0 0" Text="{Binding MachineProvider.MachineOperator.Status,Converter={StaticResource EnumToDescriptionConverter}}"></TextBlock>
</StackPanel>
@@ -302,8 +287,21 @@
</Grid>
<Grid>
- <Grid Margin="20 0 60 0" Height="80" Visibility="{Binding NotificationProvider.HasAppBarItem,Converter={StaticResource BooleanToVisibilityConverter}}">
- <ContentControl Content="{Binding NotificationProvider.CurrentAppBarItem,Converter={StaticResource AppBarItemConverter}}"></ContentControl>
+ <Grid Margin="20 0 60 0" Height="80" Visibility="{Binding NotificationProvider.HasAppBarItems,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <ItemsControl ItemsSource="{Binding NotificationProvider.AppBarItems}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <Grid IsItemsHost="True" />
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Grid Background="{StaticResource TangoPrimaryBackgroundBrush}">
+ <ContentControl Content="{Binding Converter={StaticResource AppBarItemConverter}}"></ContentControl>
+ </Grid>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
</Grid>
<!--External Header Content Here-->
@@ -330,6 +328,35 @@
</DockPanel>
</Border>
+ <Border Margin="0 0 0 0" DockPanel.Dock="Top" Visibility="{Binding IsInkFillingOrWasteEmptying,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <ItemsControl ItemsSource="{Binding Cartridges}">
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Border Margin="0 5 0 0" Visibility="{Binding InProgress,Converter={StaticResource BooleanToVisibilityConverter}}">
+ <StackPanel>
+ <DockPanel Margin="2 0 0 0">
+ <touch:TouchIcon>
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon" BasedOn="{StaticResource {x:Type touch:TouchIcon}}">
+ <Setter Property="Icon" Value="Recycle"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding Status.Cartridge.Slot}" Value="Ink">
+ <Setter Property="Icon" Value="FormatColorFill"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+ <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" Text="{Binding Message,Mode=OneWay}" FontSize="{StaticResource TangoSmallFontSize}"></TextBlock>
+ </DockPanel>
+ <touch:TouchProgressBar Foreground="{Binding Brush,Mode=OneWay}" Background="#DBDBDB" Height="3" Margin="0 2 0 0" Minimum="0" Maximum="100" Value="{Binding Status.ProgressPercentage}" />
+ </StackPanel>
+ </Border>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </Border>
+
<Grid Background="{StaticResource TangoKeyboardBackground}">
<controls:NavigationControl x:Name="NavigationControl" x:FieldModifier="public" TransitionAlwaysFades="False" TransitionType="Zoom" KeepElementsAttached="False" UseDefferedRendering="True">
<!--MODULES GOES HERE-->
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}">
<Grid>
- <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <StackPanel HorizontalAlignment="Center">
<!--<Image gif:ImageBehavior.EnableAnimation="{Binding IsLoading}" gif:ImageBehavior.AnimatedSource="/Images/Twine_Loading_GIF.gif" Margin="100 100 100 0" RenderTransformOrigin="0.5,0.5" RenderOptions.BitmapScalingMode="Fant" Height="382">
<Image.Style>
<Style TargetType="Image">
@@ -47,9 +47,10 @@
</Image.Style>
</Image>-->
- <Grid Margin="0 100 0 0">
- <Image Source="/Images/machine.png" Stretch="Uniform" Width="250" RenderOptions.BitmapScalingMode="Fant"></Image>
- <touch:TouchBusyIndicator Width="350" Height="350" IsIndeterminate="{Binding IsLoading}" />
+ <Grid Margin="0 0 0 0">
+ <!--<Image Source="/Images/machine.png" Stretch="Uniform" Width="250" RenderOptions.BitmapScalingMode="Fant"></Image>
+ <touch:TouchBusyIndicator Width="350" Height="350" IsIndeterminate="{Binding IsLoading}" />-->
+ <touch:TouchGifAnimation Source="/Images/loading_anim.gif" EnableAnimation="{Binding IsLoading}" />
</Grid>
<TextBlock Margin="0 40 0 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
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 @@
<Grid DockPanel.Dock="Bottom" Height="200" Background="{StaticResource TangoMidBackgroundBrush}">
<Border BorderThickness="0 1 0 0" BorderBrush="{StaticResource TangoGrayBrush}">
- <TextBox x:Name="txtLog" Foreground="{StaticResource TangoGrayTextBrush}" FontSize="12" SelectionBrush="Transparent" IsReadOnly="True" Padding="5" Background="Transparent" AcceptsReturn="True" TextWrapping="Wrap" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
+ <TextBox x:Name="txtLog" Foreground="{StaticResource TangoGrayTextBrush}" FontSize="12" SelectionBrush="#8BB0B0B0" IsReadOnly="True" Padding="5" Background="Transparent" AcceptsReturn="True" TextWrapping="Wrap" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
</TextBox>
</Border>
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 @@
<touch:TouchButton Padding="20" Width="300" Margin="0 0 0 130" CornerRadius="35" Command="{Binding CloseCommand}">CLOSE</touch:TouchButton>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 50 0 0">
- <touch:TouchIcon Icon="AlertOctagon" Foreground="{StaticResource TangoErrorBrush}" Width="70" Height="70" />
- <TextBlock VerticalAlignment="Center" Margin="0 10 0 0" Foreground="{StaticResource TangoErrorBrush}" FontSize="{StaticResource TangoTitleFontSize}">An error occurred while trying to update the machine.</TextBlock>
+ <touch:TouchIcon Icon="AlertOutline" Foreground="{StaticResource TangoErrorBrush}" Width="70" Height="70" />
+ <TextBlock HorizontalAlignment="Center" Margin="0 10 0 0" FontSize="{StaticResource TangoTitleFontSize}">Update Failed</TextBlock>
+ <TextBlock HorizontalAlignment="Center" Margin="0 5 0 0" Foreground="{StaticResource TangoErrorBrush}" TextAlignment="Center" Text="{Binding FailedError,FallbackValue='Unexpected error'}"></TextBlock>
</StackPanel>
</DockPanel>
</Grid>
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 @@
</touch:TouchIcon.Style>
</touch:TouchIcon>
+ <touch:TouchIcon Margin="10 0 0 0" Width="18" Height="18" VerticalAlignment="Center">
+ <touch:TouchIcon.Style>
+ <Style TargetType="touch:TouchIcon" BasedOn="{StaticResource {x:Type touch:TouchIcon}}">
+ <Setter Property="Icon" Value="LanDisconnect"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding ConnectivityProvider.IsLanConnected}" Value="True">
+ <Setter Property="Icon" Value="LanConnect"></Setter>
+ <Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </touch:TouchIcon.Style>
+ </touch:TouchIcon>
+
<touch:TouchIcon Margin="10 0 0 0" Width="18" Height="18" VerticalAlignment="Center" Foreground="{StaticResource TangoSuccessBrush}" Icon="AccessPointNetwork" Visibility="{Binding HotSpotProvider.IsEnabled,Converter={StaticResource BooleanToVisibilityConverter}}" />
<touch:TouchIcon Margin="10 0 0 0" Width="18" Height="18" VerticalAlignment="Center" Icon="Bridge" Visibility="{Binding ExternalBridgeService.Enabled,Converter={StaticResource BooleanToVisibilityConverter}}">
@@ -53,7 +69,7 @@
<Style TargetType="touch:TouchIcon">
<Setter Property="Foreground" Value="{StaticResource TangoGrayBrush}"></Setter>
<Style.Triggers>
- <DataTrigger Binding="{Binding ExternalBridgeService.IsInSession}" Value="True">
+ <DataTrigger Binding="{Binding ExternalBridgeService.HasSessions}" Value="True">
<Setter Property="Foreground" Value="{StaticResource TangoSuccessBrush}"></Setter>
</DataTrigger>
</Style.Triggers>
@@ -61,6 +77,8 @@
</touch:TouchIcon.Style>
</touch:TouchIcon>
+ <touch:TouchIcon Margin="10 0 0 0" Width="18" Height="18" VerticalAlignment="Center" Foreground="{StaticResource TangoSuccessBrush}" Icon="RemoteDesktop" Visibility="{Binding RemoteDesktopService.InSession,Converter={StaticResource BooleanToVisibilityConverter}}" />
+
<ItemsControl ItemsSource="{Binding NotificationProvider.TaskBarItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
@@ -73,6 +91,43 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
+
+ <Image Margin="10 0 0 0" Width="18" Height="18" VerticalAlignment="Center" RenderOptions.BitmapScalingMode="Fant">
+ <Image.Style>
+ <Style TargetType="Image">
+ <Setter Property="Source" Value="/Images/GlobalStatus/machine-off.png"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Disconnected}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/machine-off.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.PowerUp}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/getting-ready.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Standby}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/standby.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.ReadyToDye}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/ready-to-dye.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.GettingReady}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/getting-ready.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Printing}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/dyeing.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.ShuttingDown}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/shutting-down.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Error}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/error.png"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding MachineProvider.MachineOperator.Status}" Value="{x:Static operations:MachineStatuses.Service}">
+ <Setter Property="Source" Value="/Images/GlobalStatus/service.png"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Image.Style>
+ </Image>
<Grid></Grid>
</DockPanel>
</Border>
@@ -89,6 +144,7 @@
<local:MachineUpdateView></local:MachineUpdateView>
<local:RestartingSystemView></local:RestartingSystemView>
<local:EmergencyView></local:EmergencyView>
+ <local:RestartingView></local:RestartingView>
</controls:NavigationControl>
</touch:TouchPanel>
</Grid>
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 @@
+<UserControl x:Class="Tango.PPC.UI.Views.PowerOffView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.UI.ViewModels"
+ xmlns:global="clr-namespace:Tango.PPC.UI"
+ 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" Background="{StaticResource TangoPrimaryBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:PowerOffViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.PowerOffViewVM}">
+ <Grid>
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <touch:TouchGifAnimation Source="/Images/power_off_2.gif" EnableAnimation="{Binding IsVisible}" HorizontalAlignment="Center" />
+ <TextBlock HorizontalAlignment="Center" Margin="0 60 0 0" FontSize="{StaticResource TangoHeaderFontSize}">Machine is turning Off</TextBlock>
+ <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">Do not unplug machine while turning off</TextBlock>
+ <touch:TouchButton Command="{Binding AbortCommand}" Style="{StaticResource TangoHollowButton}" Margin="0 100 0 0" HorizontalAlignment="Center" Width="200" Height="50">ABORT</touch:TouchButton>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for LoadingView.xaml
+ /// </summary>
+ 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}">
<Grid>
-
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
- <touch:TouchBusyIndicator Width="350" Height="350" IsIndeterminate="{Binding IsVisible}" Foreground="{StaticResource TangoGrayBrush}" />
- <TextBlock Margin="0 40 0 0" TextAlignment="Center" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
- <Run>
- Setup completed.
- </Run>
- <LineBreak/>
- <Run>
- Restarting the system for the last time...
- </Run>
+ <Grid Margin="0 100 0 0">
+ <Image Source="/Images/machine.png" Stretch="Uniform" Width="250" RenderOptions.BitmapScalingMode="Fant"></Image>
+ <touch:TouchBusyIndicator Foreground="{StaticResource TangoGrayBrush}" Width="350" Height="350" IsIndeterminate="{Binding IsVisible}" />
+ </Grid>
+
+ <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Margin="0 100 0 0" HorizontalAlignment="Center" Width="250">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Restarting device"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsVisible}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard x:Name="storyRes">
+ <Storyboard>
+ <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Text" RepeatBehavior="5x">
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.2" Value="Restarting." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.6" Value="Restarting.." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.9" Value="Restarting..." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:1.4" Value="Restarting..." />
+ </ObjectAnimationUsingKeyFrames>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <RemoveStoryboard BeginStoryboardName="storyRes" />
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
</TextBlock>
</StackPanel>
</Grid>
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 @@
+<UserControl x:Class="Tango.PPC.UI.Views.RestartingView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ 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:vm="clr-namespace:Tango.PPC.UI.ViewModels"
+ xmlns:fx="clr-namespace:Tango.SharedUI.Effects;assembly=Tango.SharedUI"
+ xmlns:gif="clr-namespace:Tango.AnimatedGif;assembly=Tango.AnimatedGif"
+ xmlns:global="clr-namespace:Tango.PPC.UI"
+ 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:RestartingViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RestartingViewVM}">
+ <Grid>
+ <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <Grid Margin="0 100 0 0">
+ <Image Source="/Images/machine.png" Stretch="Uniform" Width="250" RenderOptions.BitmapScalingMode="Fant"></Image>
+ <touch:TouchBusyIndicator Foreground="{StaticResource TangoGrayBrush}" Width="350" Height="350" IsIndeterminate="{Binding IsVisible}" />
+ </Grid>
+
+ <TextBlock Margin="0 40 0 0" HorizontalAlignment="Center" FontSize="{StaticResource TangoTitleFontSize}" Foreground="{StaticResource TangoGrayTextBrush}">
+ <Run>v</Run><Run Text="{Binding ApplicationManager.Version,Mode=OneWay}"></Run>
+ </TextBlock>
+ <TextBlock FontSize="{StaticResource TangoHeaderFontSize}" Margin="0 100 0 0" HorizontalAlignment="Center" Width="170">
+ <TextBlock.Style>
+ <Style TargetType="TextBlock">
+ <Setter Property="Text" Value="Restarting"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding IsVisible}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard x:Name="storyRes">
+ <Storyboard>
+ <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Text" RepeatBehavior="5x">
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.2" Value="Restarting." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.6" Value="Restarting.." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:0.9" Value="Restarting..." />
+ <DiscreteObjectKeyFrame KeyTime="00:00:1.4" Value="Restarting..." />
+ </ObjectAnimationUsingKeyFrames>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <RemoveStoryboard BeginStoryboardName="storyRes" />
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </TextBlock.Style>
+ </TextBlock>
+ </StackPanel>
+ </Grid>
+</UserControl>
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
+{
+ /// <summary>
+ /// Interaction logic for LoadingView.xaml
+ /// </summary>
+ 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.
-->
- <!--<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />-->
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/firmware_package.tfp
Binary files 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);
+
+ /// <summary>
+ /// Passed to <see cref="GetTokenInformation"/> to specify what
+ /// information about the token to return.
+ /// </summary>
+ 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
+ }
+
+ /// <summary>
+ /// The elevation type for a user token.
+ /// </summary>
+ 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
--- /dev/null
+++ b/Software/Visual_Studio/PPC/Tango.PPC.Updater/Images/warning.png
Binary files 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">
+
+ <Window.Resources>
+ <SolidColorBrush x:Key="Foreground" Color="#1c63ea" />
+
+ <Style TargetType="Button" x:Key="Button">
+ <Setter Property="Foreground" Value="{StaticResource Foreground}"></Setter>
+ <Setter Property="FontSize" Value="18"></Setter>
+ <Setter Property="FontWeight" Value="SemiBold"></Setter>
+ <Setter Property="Margin" Value="20 0"></Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="Button">
+ <Border BorderBrush="{StaticResource Foreground}" BorderThickness="1" CornerRadius="25" Background="Transparent">
+ <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" />
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </Window.Resources>
<Grid>
- <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+ <StackPanel x:Name="stackProgress" HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="/Images/package.png" Width="200" />
<TextBlock x:Name="txtStatus" Margin="0 100 0 0" FontSize="16" Text="Updating Tango..." HorizontalAlignment="Center"></TextBlock>
- <ProgressBar x:Name="prog" Margin="0 30 0 0" Width="500" Height="10" Maximum="100" Value="0" BorderThickness="0" Foreground="#1c63ea"></ProgressBar>
+ <ProgressBar x:Name="prog" Margin="0 30 0 0" Width="500" Height="10" Maximum="100" Value="0" BorderThickness="0" Foreground="{StaticResource Foreground}"></ProgressBar>
+ </StackPanel>
+
+ <StackPanel x:Name="stackFailed" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 460 0 0" Visibility="Collapsed">
+ <Image Source="/Images/warning.png" Width="200" RenderOptions.BitmapScalingMode="Fant" />
+ <TextBlock Margin="0 100 0 0" FontSize="16" Text="Update Failed" Foreground="#FF0072" FontWeight="SemiBold" HorizontalAlignment="Center"></TextBlock>
+ <TextBlock x:Name="txtError" Margin="0 20 0 0" FontSize="16" Foreground="Gray" Text="Unexpected error" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" Height="100"></TextBlock>
+
+ <UniformGrid Width="600" Height="55" Columns="2" Margin="0 200 0 0">
+ <Button x:Name="btnAbort" Content="ABORT" Style="{StaticResource Button}"></Button>
+ <Button x:Name="btnRetry" Content="RETRY" Style="{StaticResource Button}"></Button>
+ </UniformGrid>
</StackPanel>
</Grid>
</Window>
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)
@@ -69,7 +79,32 @@ namespace Tango.PPC.Updater
{
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.");
+ }
}
/// <summary>
@@ -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 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
+ <Compile Include="IdentityUtils.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -102,6 +103,9 @@
<ItemGroup>
<Resource Include="Images\package.png" />
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="Images\warning.png" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{EA4233F1-4B7B-4CCF-A6DE-2D17612EBA90}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.PPC.Packages.Auth2</RootNamespace>
+ <AssemblyName>Tango.PPC.Packages.Auth2</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\Packages\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\Packages\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Auth2.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{F441FEEE-322A-4943-B566-110E12FD3B72}</Project>
+ <Name>Tango.BL</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</Project>
+ <Name>Tango.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Z.EntityFramework.Extensions" publicKeyToken="59b66d028979105b" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.50.0" newVersion="4.0.50.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="EntityFramework" version="6.2.0" targetFramework="net461" />
+</packages> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{DF64460A-6617-4338-872A-DC43FD994C48}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.PPC.Packages.CefInstaller</RootNamespace>
+ <AssemblyName>Tango.PPC.Packages.CefInstaller</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\Packages\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\Packages\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.IO.Compression" />
+ <Reference Include="System.IO.Compression.FileSystem" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="CefInstaller.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</Project>
+ <Name>Tango.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <configSections>
+ <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </configSections>
+ <entityFramework>
+ <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
+ <providers>
+ <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+ </providers>
+ </entityFramework>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Z.EntityFramework.Extensions" publicKeyToken="59b66d028979105b" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.50.0" newVersion="4.0.50.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{59643ABC-DF9A-497F-8A7C-4A131C7CF438}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.PPC.Packages.JobRunsStartTimePatch</RootNamespace>
+ <AssemblyName>Tango.PPC.Packages.JobRunsStartTimePatch</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\Packages\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\Packages\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.ComponentModel.DataAnnotations" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="JobRunsStartTimePatch.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{F441FEEE-322A-4943-B566-110E12FD3B72}</Project>
+ <Name>Tango.BL</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</Project>
+ <Name>Tango.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208C8BD8-72C6-4E3C-ACAA-351091A2ACC7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="EntityFramework" version="6.2.0" targetFramework="net461" />
+</packages> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{DA391B02-AE28-4EA1-A80F-D0F4C8029FFA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.PPC.Packages.SamplePostPackage</RootNamespace>
+ <AssemblyName>Tango.PPC.Packages.SamplePostPackage</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\Packages\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\Packages\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="SamplePostPackage.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{2CD12594-3522-4658-A65F-190EE58B6AFA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.PPC.Packages.SamplePrePackage</RootNamespace>
+ <AssemblyName>Tango.PPC.Packages.SamplePrePackage</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Debug\Packages\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\..\Build\PPC\Release\Packages\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="SamplePrePackage.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</Project>
+ <Name>Tango.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Common\Tango.PPC.Common.csproj">
+ <Project>{0be74eee-22cb-4dba-b896-793b9e1a3ac0}</Project>
+ <Name>Tango.PPC.Common</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.PPC.Shared\Tango.PPC.Shared.csproj">
+ <Project>{208c8bd8-72c6-4e3c-acaa-351091a2acc7}</Project>
+ <Name>Tango.PPC.Shared</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file