diff options
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules')
155 files changed, 10675 insertions, 1135 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/MachineStudio.Dispensers/Views/DispenserView.xaml b/Software/Visual_Studio/MachineStudio/Modules/MachineStudio.Dispensers/Views/DispenserView.xaml index 977ab865a..e0f93df5a 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/MachineStudio.Dispensers/Views/DispenserView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/MachineStudio.Dispensers/Views/DispenserView.xaml @@ -19,7 +19,7 @@ <Grid DockPanel.Dock="Top"> <StackPanel Orientation="Horizontal"> <Button Style="{StaticResource MaterialDesignFlatButton}" Height="Auto" Command="{Binding BackToDispensersCommand}"> - <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="#202020" ToolTip="Back to RML list" /> + <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="{StaticResource DarkGrayBrush200}" ToolTip="Back to RML list" /> </Button> <TextBlock VerticalAlignment="Center" Margin="10 0 0 0" FontSize="34"> <Run>DISPENSER</Run> @@ -51,9 +51,9 @@ <TextBox Text="{Binding ActiveDispenser.SerialNumber}"></TextBox> <TextBlock FontWeight="SemiBold">Dispenser Type:</TextBlock> - <ComboBox ItemsSource="{Binding DispenserTypes}" SelectedItem="{Binding ActiveDispenser.DispenserType}" DisplayMemberPath="Name"></ComboBox> + <ComboBox ItemsSource="{Binding DispenserTypes}" SelectedItem="{Binding ActiveDispenser.DispenserType}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}" ></ComboBox> - <TextBlock FontWeight="SemiBold">Nanoliter / Pulse:</TextBlock> + <TextBlock FontWeight="SemiBold">Nanoliter / Pulse:</TextBlock> <mahapps:NumericUpDown HorizontalContentAlignment="Left" HasDecimals="True" BorderThickness="0 0 0 1" Background="Transparent" Minimum="0" Maximum="5" Value="{Binding ActiveDispenser.NlPerPulse}"></mahapps:NumericUpDown> <TextBlock FontWeight="SemiBold">Part Number:</TextBlock> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ActionLogsModule.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ActionLogsModule.cs new file mode 100644 index 000000000..3a9dcdfaa --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ActionLogsModule.cs @@ -0,0 +1,62 @@ +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.MachineStudio.Common; +using Tango.MachineStudio.ActionLogs.Views; +using Tango.SharedUI.Helpers; + +namespace Tango.MachineStudio.ActionLogs +{ + [StudioModule(21)] + public class ActionLogsModule : StudioModuleBase + { + public override string Name + { + get + { + return "Action Logs"; + } + } + + public override string Description + { + get + { + return "Monitor and track changes made to Twine's global datasets."; + } + } + + public override BitmapSource Image + { + get + { + return ResourceHelper.GetImageFromResources("Images/action_logs.jpg"); + } + } + + public override Type MainViewType + { + get + { + return typeof(MainView); + } + } + + public override Permissions Permission + { + get + { + return Permissions.RunMachineStudio; + } + } + + public override void Dispose() + { + + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/App.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/App.xaml new file mode 100644 index 000000000..3ab646c7c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/App.xaml @@ -0,0 +1,12 @@ +<Application x:Class="Tango.MachineStudio.ActionLogs.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.MachineStudio.Common;component/Resources/MaterialDesign.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.MachineStudio.Common;component/Themes/LightThemeColors.xaml" /> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> + </Application.Resources> +</Application>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/action_logs.jpg b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/action_logs.jpg Binary files differnew file mode 100644 index 000000000..75f39c09c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/action_logs.jpg diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/actionlogs_title.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/actionlogs_title.png Binary files differnew file mode 100644 index 000000000..299c14c6d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Images/actionlogs_title.png diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/AssemblyInfo.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..072265a74 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +[assembly: AssemblyTitle("Tango - Machine Studio Action Logs Module")] +[assembly: AssemblyVersion("1.0.0.1737")] + +[assembly: ComVisible(false)] + +[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/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Resources.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Resources.Designer.cs new file mode 100644 index 000000000..796a67686 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// <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.MachineStudio.ActionLogs.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.MachineStudio.ActionLogs.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/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Resources.resx b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/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/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Settings.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Settings.Designer.cs new file mode 100644 index 000000000..507ac539d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/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.MachineStudio.ActionLogs.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/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Settings.settings b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/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/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Tango.MachineStudio.ActionLogs.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Tango.MachineStudio.ActionLogs.csproj new file mode 100644 index 000000000..de4783237 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Tango.MachineStudio.ActionLogs.csproj @@ -0,0 +1,163 @@ +<?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>{447ECB9F-F730-47D6-8DF8-D232BF4A0315}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.MachineStudio.ActionLogs</RootNamespace> + <AssemblyName>Tango.MachineStudio.ActionLogs</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\Machine Studio\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\Machine Studio\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="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="MahApps.Metro, Version=1.5.0.23, Culture=neutral, PublicKeyToken=f4fb5a3c4d1e5b4f, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignColors, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignColors.1.1.2\lib\net45\MaterialDesignColors.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignThemes.Wpf, Version=2.3.1.953, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath> + </Reference> + <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> + </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\MahApps.Metro.1.5.0\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> + <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + <Compile Include="ActionLogsModule.cs" /> + <Page Include="App.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="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> + <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> + <Resource Include="Images\actionlogs_title.png" /> + </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.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.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.Transport\Tango.Transport.csproj"> + <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> + <Name>Tango.Transport</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.MachineStudio.Common\Tango.MachineStudio.Common.csproj"> + <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project> + <Name>Tango.MachineStudio.Common</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\action_logs.jpg" /> + </ItemGroup> + <ItemGroup> + <Folder Include="Models\" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModelLocator.cs new file mode 100644 index 000000000..29540fa86 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModelLocator.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.MachineStudio.ActionLogs.ViewModels; + +namespace Tango.MachineStudio.ActionLogs +{ + public static class ViewModelLocator + { + /// <summary> + /// Initializes a new instance of the ViewModelLocator class. + /// </summary> + static ViewModelLocator() + { + TangoIOC.Default.Register<MainViewVM>(); + } + + public static MainViewVM MainViewVM + { + get + { + return TangoIOC.Default.GetInstance<MainViewVM>(); + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..3e5c59fee --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/ViewModels/MainViewVM.cs @@ -0,0 +1,290 @@ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Entity; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL; +using Tango.BL.Builders; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; +using Tango.Core.Commands; +using Tango.Core.ExtensionMethods; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Common.Notifications; +using Tango.SharedUI.Components; + +namespace Tango.MachineStudio.ActionLogs.ViewModels +{ + public class MainViewVM : StudioViewModel + { + private INotificationProvider _notification; + private List<User> _allUsers; + + #region Properties + + private DateTime _startSelectedDate; + public DateTime StartSelectedDate + { + get { return _startSelectedDate; } + set { _startSelectedDate = value; RaisePropertyChangedAuto(); } + } + + private DateTime _endSelectedDate; + public DateTime EndSelectedDate + { + get { return _endSelectedDate; } + set { _endSelectedDate = value; RaisePropertyChangedAuto(); } + } + + private string _searchFilter; + public string SearchFilter + { + get { return _searchFilter; } + set { _searchFilter = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<ActionLog> _actionLogs; + public ObservableCollection<ActionLog> ActionLogs + { + get { return _actionLogs; } + set { _actionLogs = value; RaisePropertyChanged(nameof(ActionLogs)); } + } + + private SelectedObjectCollection<ActionLogType> _selectedActionLogTypes; + public SelectedObjectCollection<ActionLogType> SelectedActionLogTypes + { + get { return _selectedActionLogTypes; } + set + { + _selectedActionLogTypes = value; + RaisePropertyChanged(nameof(SelectedActionLogTypes)); + } + } + + private ActionLog _selectedActionLog = null; + public ActionLog SelectedActionLog + { + get { return _selectedActionLog; } + set + { + _selectedActionLog = value; + SelectedItemChanged(); + RaisePropertyChangedAuto(); + InvalidateRelayCommands(); + } + } + + private ActionLogDifference _differenceObject; + public ActionLogDifference DifferenceObject + { + get { return _differenceObject; } + set { _differenceObject = value; RaisePropertyChangedAuto(); } + } + + private bool _isLoading; + + public bool IsLoading + { + get { return _isLoading; } + set { _isLoading = value; RaisePropertyChangedAuto(); } + } + + private bool _isLoadingDifferences; + + public bool IsLoadingDifferences + { + get { return _isLoadingDifferences; } + set { _isLoadingDifferences = value; RaisePropertyChangedAuto(); } + } + + + + + #endregion + + public RelayCommand SearchCommand { get; set; } + public RelayCommand CopyToClipBoardCommand { get; set; } + public RelayCommand CopyRelateObjectIDCommand { get; set; } + + public MainViewVM(INotificationProvider notification) + { + _notification = notification; + + IsLoading = false; + IsLoadingDifferences = false; + ActionLogs = new ObservableCollection<ActionLog>(); + SearchCommand = new RelayCommand(async () => await GetActionLogs(), () => IsFree); + CopyRelateObjectIDCommand = new RelayCommand(CopyRelateObjectID); + CopyToClipBoardCommand = new RelayCommand(CopyToClipBoard, () => SelectedActionLog != null && SelectedActionLog.DifferenceObject != null); + DateTime now = DateTime.Now; + StartSelectedDate = now.AddMonths(-1); + EndSelectedDate = now; + var source = Enum.GetValues(typeof(ActionLogType)).Cast<ActionLogType>().ToObservableCollection(); + var syncedSource = Enum.GetValues(typeof(ActionLogType)).Cast<ActionLogType>().ToObservableCollection(); + + SelectedActionLogTypes = new SelectedObjectCollection<ActionLogType>(source, syncedSource); + } + + public override void OnApplicationReady() + { + InitUsers(); + } + public async void InitUsers() + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + + _allUsers = await db.Users.Include(x => x.Contact).ToListAsync(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading users."); + } + finally + { + IsFree = true; + } + } + + private void CopyToClipBoard() + { + DataObject data = new DataObject(SelectedActionLog.DifferenceObject.ToJsonString()); + System.Windows.Clipboard.SetDataObject(data); + + } + private void CopyRelateObjectID() + { + DataObject data = new DataObject(SelectedActionLog.RelatedObjectGuid); + System.Windows.Clipboard.SetDataObject(data); + } + + /// <summary> + /// New Database Query with search parameters. Initialization ActionLogs property. + /// </summary> + private async Task GetActionLogs() + { + IsLoading = true; + string filter = SearchFilter?.ToLower(); + + if (String.IsNullOrWhiteSpace(filter)) filter = null; + + try + { + IsFree = false; + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + DateTime startUtc = new DateTime(StartSelectedDate.Year, StartSelectedDate.Month, StartSelectedDate.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (EndSelectedDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = EndSelectedDate.ToUniversalTime() + offsetTime; + + Debug.Write($"TEST TIME {startUtc} to {endUtc} "+ System.Environment.NewLine); + + var db_ActionLogs = db.ActionLogs.Where(x => x.LastUpdated <= endUtc && x.LastUpdated >= startUtc) + .Select(x => new + { + x.ID, + x.Guid, + x.UserGuid, + x.LastUpdated, + x.Type, + x.RelatedObjectName, + x.RelatedObjectGuid, + x.Message + }); + + int[] actionTypes = SelectedActionLogTypes.SynchedSource.ToArray().Select(x => (int)x).ToArray(); + if (actionTypes.Length > 0) + { + db_ActionLogs = db_ActionLogs.Where(x => actionTypes.Contains(x.Type)); + } + + var runs_db = await db_ActionLogs.ToListAsync(); + var runs = runs_db.Select(x => new ActionLog() + { + ID = x.ID, + Guid = x.Guid, + UserGuid = x.UserGuid, + LastUpdated = x.LastUpdated, + Type = x.Type, + RelatedObjectName = x.RelatedObjectName, + RelatedObjectGuid = x.RelatedObjectGuid, + Message = x.Message, + User = _allUsers.SingleOrDefault(y => y.Guid == x.UserGuid) + }); + + if (!String.IsNullOrEmpty(filter)) + { + runs = runs.Where(x => x.ID.ToString().ToLower().StartsWith(filter) || (x.RelatedObjectName != null && x.RelatedObjectName.ToLower().StartsWith(filter)) + || (x.RelatedObjectGuid != null && x.RelatedObjectGuid.ToLower().StartsWith(filter)) + || (x.User != null && x.User.Contact != null && x.User.Contact.FullName.ToLower().StartsWith(filter))); + } + ActionLogs = runs.ToObservableCollection(); + } + } + catch (Exception ex) + { + IsFree = true; + LogManager.Log(ex, "Error getting action logs."); + _notification.ShowError($"Error occurred while trying to retrieve the action logs.\n{ex.Message}"); + } + finally + { + IsFree = true; + IsLoading = false; + } + } + + /// <summary> + /// Update DifferenceObject on Selected item changed + /// </summary> + private async void SelectedItemChanged() + { + if (SelectedActionLog == null) + return; + if (SelectedActionLog.Difference == null) + { + await InitSelectedActionLogDifference(); + } + DifferenceObject = SelectedActionLog.DifferenceObject; + } + + /// <summary> + /// Initializes the selected action log difference. + /// </summary> + public async Task InitSelectedActionLogDifference() + { + IsLoadingDifferences = true; + try + { + using (var db = ObservablesContext.CreateDefault()) + { + var difference = await db.ActionLogs.SingleOrDefaultAsync(x => x.Guid.Equals(SelectedActionLog.Guid)); + if (difference != null) + { + SelectedActionLog.DifferenceObject = difference.DifferenceObject; + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading difference of the selected action log."); + } + finally + { + IsLoadingDifferences = false; + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.xaml new file mode 100644 index 000000000..146735eaa --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.xaml @@ -0,0 +1,317 @@ +<UserControl x:Class="Tango.MachineStudio.ActionLogs.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:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:sharedConverters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:vm="clr-namespace:Tango.MachineStudio.ActionLogs.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.ActionLogs" + xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf;assembly=MaterialDesignThemes.Wpf" + xmlns:diff="clr-namespace:Tango.BL.ValueObjects;assembly=Tango.BL" + xmlns:local="clr-namespace:Tango.MachineStudio.ActionLogs.Views" + mc:Ignorable="d" + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + <UserControl.Resources> + <sharedConverters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> + <sharedConverters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <sharedConverters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter"/> + </UserControl.Resources> + <Grid IsEnabled="{Binding IsFree}"> + <Grid.RowDefinitions> + <RowDefinition Height="200"/> + <RowDefinition Height="1*"/> + </Grid.RowDefinitions> + <Grid Margin="40"> + <StackPanel Orientation="Horizontal"> + <Image Source="../Images/actionlogs_title.png" RenderOptions.BitmapScalingMode="Fant"></Image> + <StackPanel Margin="20 0 0 0" VerticalAlignment="Center"> + <TextBlock FontSize="50">Action Logs</TextBlock> + <TextBlock>Select start/end dates and action log types to trace system changes.</TextBlock> + </StackPanel> + </StackPanel> + </Grid> + <Grid Grid.Row="1" Margin="40 0 40 40"> + <Grid.RowDefinitions> + <RowDefinition Height="70"/> + <RowDefinition Height="1*"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width ="7*"/> + <ColumnDefinition Width ="3*"/> + </Grid.ColumnDefinitions > + + <Grid x:Name ="searchButtons" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Stretch"> + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" CornerRadius="2" > + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + <DockPanel> + <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Horizontal"> + <StackPanel > + <TextBlock FontSize="10">Start Date:</TextBlock> + <DatePicker x:Name="startdatePicker" SelectedDate="{Binding StartSelectedDate}" materialDesign:HintAssist.Hint="Pick start date" Width="160" VerticalAlignment="Center" FontSize="16" /> + </StackPanel> + <StackPanel Margin="50 0 0 0"> + <TextBlock FontSize="10">End Date:</TextBlock> + <DatePicker x:Name="endDatePicker" SelectedDate="{Binding EndSelectedDate}" materialDesign:HintAssist.Hint="Pick end date" Width="160" VerticalAlignment="Center" FontSize="16" /> + </StackPanel> + <DockPanel Margin="50 0 0 0" > + <TextBlock DockPanel.Dock="Top" Text="Action Log Type:" VerticalAlignment="Center" FontSize="10"></TextBlock> + <ToggleButton Width="200" Margin="0 5 0 0" x:Name="selectActionsButton" > + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="Button_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}"> + <Run Text=" Select Actions"></Run> + <Run>(</Run><Run Text="{Binding SelectedActionLogTypes.SynchedSource.Count,Mode=OneWay}"></Run><Run>)</Run> + </TextBlock> + </DockPanel> + </Border> + <Popup StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }" Style="{x:Null}"> + <Border Padding="5" MaxHeight="600" Background="{DynamicResource ComboBox.Floating.Background}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=ActualWidth}"> + <controls:AllSelectedCheckboxList Style="{StaticResource AllSelectedCheckBoxListStyle}" MaxHeight="600" ItemsSource="{Binding SelectedActionLogTypes}" Foreground="{StaticResource MainWindow.Foreground}" Background="{DynamicResource ComboBox.Floating.Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Multiple" AllSelected="True" FontSize="11" FontFamily="{StaticResource FontName}"> + <controls:AllSelectedCheckboxList.ItemTemplate> + <DataTemplate > + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data,Converter={StaticResource EnumToDescriptionConverter}}" FontSize="11" FontFamily="{StaticResource FontName}"/> + + </DataTemplate> + </controls:AllSelectedCheckboxList.ItemTemplate> + </controls:AllSelectedCheckboxList> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + + </DockPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="50 10 0 0"> + <materialDesign:PackIcon Kind="Magnify" Width="26" Height="26"/> + <TextBox Width="Auto" materialDesign:HintAssist.Hint="Search by ID, user, related object name" Text="{Binding SearchFilter,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </StackPanel> + <Button DockPanel.Dock="Right" Width="120" HorizontalAlignment="Right" Command="{Binding SearchCommand}" Margin="10 0 10 0" VerticalAlignment="Center">Search</Button> + </DockPanel> + </Border> + </Grid> + + <Grid IsEnabled="{Binding IsFree}" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > + <DataGrid Margin="0 0 0 10" SelectionMode="Single" SelectionUnit="FullRow" RowHeight="40" BorderBrush="{StaticResource borderBrush}" IsReadOnly="True" BorderThickness="1" + Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserReorderColumns="True" + CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding ActionLogs}" + SelectedItem="{Binding SelectedActionLog}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" FontSize="11"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.CellStyle> + <DataGrid.RowStyle> + <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}"> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + <Setter Property="Cursor" Value="Hand"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + <Trigger Property="IsFocused" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.RowStyle> + + <DataGrid.Columns> + <DataGridTextColumn Header="ID" Binding="{Binding ID}" Width="40" /> + <DataGridTextColumn Header="TIME" Binding="{Binding LastUpdated, Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="Auto" /> + <DataGridTextColumn Header="ACTION" Binding="{Binding ActionType, Converter={StaticResource EnumToDescriptionConverter}}" Width="Auto"/> + <DataGridTextColumn Header="USER" Binding="{Binding User.Contact.FullName}" Width="Auto"/> + <DataGridTextColumn Header="RELATED OBJECT NAME" Binding="{Binding RelatedObjectName}" Width="Auto" /> + <DataGridTextColumn Header="RELATED OBJECT ID" Binding="{Binding RelatedObjectGuid}" Width="Auto" > + <DataGridTextColumn.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}" > + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext}"/> + <Setter Property="ContextMenu"> + <Setter.Value> + <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" Padding="0" Margin="0" > + <MenuItem Header="Copy (Ctrl+C)" Command="{Binding CopyRelateObjectIDCommand}" FontSize="12" Background="{StaticResource MainWindow.Background}"> + <MenuItem.Icon> + <materialDesign:PackIcon Width="16" Height="16" Kind="ContentCopy" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}"/> + </MenuItem.Icon> + <MenuItem.ItemContainerStyle> + <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}"> + <Setter Property="Background" Value="Transparent"></Setter> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </MenuItem.ItemContainerStyle> + </MenuItem> + <ContextMenu.Style> + <Style TargetType="{x:Type ContextMenu}" BasedOn="{StaticResource MaterialDesignMenu}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate > + <AdornerDecorator CacheMode="{Binding RelativeSource={RelativeSource Self}, Path=(wpf:ShadowAssist.CacheMode)}"> + <Border Background="{StaticResource MainWindow.Background}" Effect="{DynamicResource MaterialDesignShadowDepth1}" Margin="3" CornerRadius="2"> + <Grid RenderOptions.ClearTypeHint="Enabled" Margin="0"> + <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/> + </Grid> + </Border> + </AdornerDecorator> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + </ContextMenu.Style> + </ContextMenu> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGridTextColumn.CellStyle> + </DataGridTextColumn> + <DataGridTextColumn Header="MESSAGE" Binding="{Binding Message}" Width="1*" /> + </DataGrid.Columns> + </DataGrid> + </Grid> + <Grid Grid.Row="1" Grid.Column="0" Visibility="{Binding IsLoading,Converter={StaticResource BooleanToVisibilityConverter}}"> + <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center"> + <mahapps:ProgressRing Margin="20 60 20 40" Width="80" Height="80" IsActive="{Binding IsLoading}"></mahapps:ProgressRing> + <TextBlock Text="Loading..." HorizontalAlignment="Center" FontSize="20" FontStyle="Italic" VerticalAlignment="Center" Margin="0 20 0 0"></TextBlock> + </StackPanel> + </Grid> + + <Grid Grid.Row="0" Grid.Column="1" Margin="40 0 10 0"> + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2"> + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + <DockPanel> + <TextBlock DockPanel.Dock="Left" Margin="10 0 0 0" Foreground="{StaticResource DimGrayBrush}" FontSize="16" VerticalAlignment="Center" Width="150">Object Changes</TextBlock> + <Button Width="Auto" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Right" DockPanel.Dock="Right" Command="{Binding CopyToClipBoardCommand}" > + <StackPanel Orientation="Horizontal" > + <materialDesign:PackIcon Width="16" Height="16" Kind="ContentCopy" VerticalAlignment="Center" Margin="-5 0 10 0"/> + <TextBlock Text="Copy to Clipboard" VerticalAlignment="Center"></TextBlock> + </StackPanel> + </Button> + </DockPanel> + </Border> + </Grid> + <Border Grid.Row="1" Grid.Column="1" Margin="40 0 10 10" IsEnabled="{Binding IsFree}" BorderThickness="1 0 1 1 " BorderBrush="{StaticResource LightGrayBrush100}" Background="{StaticResource TransparentBackgroundBrush}"> + <DockPanel > + <TextBlock DockPanel.Dock="Top" Height="40" Text="{Binding DifferenceObject.Name, Mode=OneWay}" VerticalAlignment="Center" Padding="5" FontSize="18" HorizontalAlignment="Center" ></TextBlock> + <TreeView x:Name="treeView" ItemsSource="{Binding DifferenceObject.Children, Mode=OneWay}" > + <TreeView.ItemContainerStyle> + <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TreeViewItem}"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition MinWidth="19" Width="Auto"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition/> + </Grid.RowDefinitions> + <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" + Style="{StaticResource MaterialDesignExpandCollapseToggleStyle}" + Foreground="{TemplateBinding Foreground}" + Margin="8 0 8 0" + VerticalAlignment="Center" + /> + <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> + <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> + </Border> + <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsExpanded" Value="false"> + <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/> + </Trigger> + <Trigger Property="HasItems" Value="false"> + <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/> + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsSelected" Value="true"/> + <Condition Property="IsSelectionActive" Value="false"/> + </MultiTrigger.Conditions> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/> + </MultiTrigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Setter Property="IsExpanded" Value="True" /> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + <Trigger Property="IsFocused" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </TreeView.ItemContainerStyle> + <TreeView.Resources> + <HierarchicalDataTemplate DataType="{x:Type diff:ActionLogDifference}" ItemsSource="{Binding Children}"> + <TextBlock Text="{Binding Name}" Margin="5 0 0 0" Foreground ="{StaticResource MainWindow.Foreground}"/> + </HierarchicalDataTemplate> + + <DataTemplate DataType="{x:Type diff:ActionLogDifferenceValue}"> + <TextBlock Margin="5 0 0 0" Foreground ="{StaticResource MainWindow.Foreground}"> + <Run Text="{Binding Name}"/> + <Run>: </Run> + <Run Text="{Binding Before,Mode=OneWay}" Foreground="{StaticResource DimGrayBrush}"/> + <Run> | </Run> + <Run Text="{Binding After,Mode=OneWay}" Foreground="{StaticResource RedBrush100}"/> + </TextBlock> + </DataTemplate> + </TreeView.Resources> + </TreeView> + + </DockPanel> + </Border> + <mahapps:ProgressRing Grid.Row="1" Grid.Column="1" Margin="20 0 20 40" Width="80" Height="80" IsActive="{Binding IsLoadingDifferences}"></mahapps:ProgressRing> + + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.xaml.cs new file mode 100644 index 000000000..67641e3fc --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/Views/MainView.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.MachineStudio.ActionLogs.Views +{ + /// <summary> + /// Interaction logic for MainView.xaml + /// </summary> + public partial class MainView : UserControl + { + public MainView() + { + InitializeComponent(); + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + selectActionsButton.IsChecked = true; + e.Handled = true; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/app.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/app.config new file mode 100644 index 000000000..7b82e5f7c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/app.config @@ -0,0 +1,85 @@ +<?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="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="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="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="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> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/packages.config new file mode 100644 index 000000000..e57143046 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.ActionLogs/packages.config @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> + <package id="MahApps.Metro" version="1.5.0" targetFramework="net461" /> + <package id="MaterialDesignColors" version="1.1.2" targetFramework="net461" /> + <package id="MaterialDesignThemes" version="2.3.1.953" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs index 652ad3093..8a33f15ef 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs @@ -17,6 +17,10 @@ using Microsoft.Win32; using Tango.Core.Helpers; using System.IO; using Tango.MachineStudio.Catalogs.Excel; +using Tango.BL.ActionLogs; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.Enumerations; +using Tango.BL.DTO; namespace Tango.MachineStudio.Catalogs.ViewModels { @@ -25,6 +29,9 @@ namespace Tango.MachineStudio.Catalogs.ViewModels private ObservablesContext _catalogsContext; private ObservablesContext _activeCatalogContext; private INotificationProvider _notification; + private IActionLogManager _actionLogManager; + private IAuthenticationProvider _authentication; + private ColorCatalogDTO _catalogBeforeSave; #region Properties @@ -151,9 +158,11 @@ namespace Tango.MachineStudio.Catalogs.ViewModels /// Initializes a new instance of the <see cref="MainViewVM"/> class. /// </summary> /// <param name="notificationProvider">The notification provider.</param> - public MainViewVM(INotificationProvider notificationProvider) : this() + public MainViewVM(INotificationProvider notificationProvider, IActionLogManager actionLogManager, IAuthenticationProvider authenticationProvider) : this() { + _actionLogManager = actionLogManager; _notification = notificationProvider; + _authentication = authenticationProvider; } #endregion @@ -197,7 +206,7 @@ namespace Tango.MachineStudio.Catalogs.ViewModels _activeCatalogContext = ObservablesContext.CreateDefault(); - ActiveCatalog = await new ColorCatalogBuilder(_activeCatalogContext).Set(SelectedCatalog.Guid).WithGroups().WithItems().WithRecipes().BuildAsync(); + ActiveCatalog = await new CatalogBuilder(_activeCatalogContext).Set(SelectedCatalog.Guid).WithGroups().WithItems().WithRecipes().BuildAsync(); SelectedGroup = ActiveCatalog.ColorCatalogsGroups.FirstOrDefault(); RMLS = await _activeCatalogContext.Rmls.ToListAsync(); @@ -206,6 +215,8 @@ namespace Tango.MachineStudio.Catalogs.ViewModels SelectedItem = SelectedGroup.ColorCatalogsItems.FirstOrDefault(); } + _catalogBeforeSave = ColorCatalogDTO.FromObservable(ActiveCatalog); + View.NavigateTo(CatalogsNavigationView.CatalogView); } catch (Exception ex) @@ -233,6 +244,7 @@ namespace Tango.MachineStudio.Catalogs.ViewModels { IsFree = false; await SelectedCatalog.DeleteCascadeAsync(_catalogsContext); + _actionLogManager.InsertLog(ActionLogType.CatalogDeleted, _authentication.CurrentUser, SelectedCatalog.Name, SelectedCatalog, "Catalog deleted using Machine Studio.", false); SelectedCatalog = null; } catch (Exception ex) @@ -265,6 +277,7 @@ namespace Tango.MachineStudio.Catalogs.ViewModels newCatalog.Company = "Twine"; _catalogsContext.ColorCatalogs.Add(newCatalog); await _catalogsContext.SaveChangesAsync(); + _actionLogManager.InsertLog(ActionLogType.CatalogCreated, _authentication.CurrentUser, newCatalog.Name, newCatalog, "Catalog created using Machine Studio."); SelectedCatalog = newCatalog; EditSelectedCatalog(); } @@ -305,8 +318,44 @@ namespace Tango.MachineStudio.Catalogs.ViewModels try { IsFree = false; + + //Validate color codes. + var duplicateCodes = ActiveCatalog + .ColorCatalogsGroups + .SelectMany(x => x.ColorCatalogsItems) + .GroupBy(x => x.Code) + .Where(x => x.Count() > 1) + .Select(x => x.First().Code) + .ToList(); + + if (duplicateCodes.Count > 0) + { + throw new InvalidOperationException($"Duplicate color codes found:\n{String.Join(Environment.NewLine, duplicateCodes)}"); + } + + //Validate color names. + var duplicateNames = ActiveCatalog + .ColorCatalogsGroups + .SelectMany(x => x.ColorCatalogsItems) + .GroupBy(x => x.Name) + .Where(x => x.Count() > 1) + .Select(x => x.First().Name) + .ToList(); + + if (duplicateNames.Count > 0) + { + throw new InvalidOperationException($"Duplicate color names found:\n{String.Join(Environment.NewLine, duplicateNames)}"); + } + + ActiveCatalog.LastUpdated = DateTime.UtcNow; await _activeCatalogContext.SaveChangesAsync(); + + var activeCatalogDTO = ColorCatalogDTO.FromObservable(ActiveCatalog); + _actionLogManager.InsertLog(ActionLogType.CatalogSaved, _authentication.CurrentUser, _catalogBeforeSave.Name, _catalogBeforeSave, activeCatalogDTO, "Catalog saved using Machine Studio."); + _catalogBeforeSave = activeCatalogDTO; + await LoadCatalogs(); + _notification.ShowInfo("Catalog updated successfully."); } catch (Exception ex) diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/Views/CatalogView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/Views/CatalogView.xaml index ded1acb2d..5a49c93d3 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/Views/CatalogView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/Views/CatalogView.xaml @@ -13,7 +13,7 @@ xmlns:global="clr-namespace:Tango.MachineStudio.Catalogs" xmlns:local="clr-namespace:Tango.MachineStudio.Catalogs.Views" mc:Ignorable="d" - d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" Foreground="#232323" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" Foreground="{StaticResource DarkGrayBrush200}" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <UserControl.Resources> <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter" /> @@ -51,7 +51,7 @@ <Grid DockPanel.Dock="Top"> <StackPanel Orientation="Horizontal"> <Button Style="{StaticResource MaterialDesignFlatButton}" Height="Auto" Command="{Binding BackToCatalogsCommand}"> - <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="#202020" ToolTip="Back to RML list" /> + <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="{StaticResource DarkGrayBrush200}" ToolTip="Back to RML list" /> </Button> <TextBlock Text="{Binding ActiveCatalog.Name}" VerticalAlignment="Center" Margin="10 0 0 0" FontSize="34"></TextBlock> </StackPanel> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs index bbe5432e9..bb9608f6b 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs @@ -382,7 +382,7 @@ namespace Tango.MachineStudio.DataCapture.ViewModels using (_notification.PushTaskItem("Starting Recording...")) { Recorder.Start(); - _eventLogger.Log(EventTypes.RECORDING_STARTED, "Recording Started..."); + //_eventLogger.Log(EventTypes.RECORDING_STARTED, "Recording Started..."); _recordingBarItem.Push(); } @@ -398,7 +398,7 @@ namespace Tango.MachineStudio.DataCapture.ViewModels await Recorder.Stop(); _recordingBarItem.Pop(); - _eventLogger.Log(EventTypes.RECORDING_STOPPED, "Recording Stopped..."); + //_eventLogger.Log(EventTypes.RECORDING_STOPPED, "Recording Stopped..."); } String recordingName = _notification.ShowTextInput("Enter recording name", "Recording name"); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Controls/JobOutlineControl.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Controls/JobOutlineControl.cs index ee570ac34..68dc7e3bf 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Controls/JobOutlineControl.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Controls/JobOutlineControl.cs @@ -136,6 +136,34 @@ namespace Tango.MachineStudio.Developer.Controls _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, PackIconKind.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, PackIconKind.Settings); + _sizeControl.Height += NORMAL_FONT_HEIGHT; + } + } //JobTicket.Segments if (job.Segments != null) { diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs index 3a1f3fb11..fc0680d9c 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs @@ -50,6 +50,9 @@ using Tango.Core.ExtensionMethods; using Tango.ColorConversion; using Tango.PMR.Exports; using Microsoft.WindowsAPICodePack.Dialogs; +using Tango.BL.Enumerations; +using Tango.BL.DTO; +using Tango.BL.ActionLogs; namespace Tango.MachineStudio.Developer.ViewModels { @@ -85,6 +88,9 @@ namespace Tango.MachineStudio.Developer.ViewModels private TaskItem _preparingTaskItem; private IColorConverter _converter; private string _current_job_string; + private JobDTO _beforeSaveJobDTO; + private IActionLogManager _actionLogManager; + private RmlDTO _selectedRMLBeforeLiquidFactorsSaves; #region Properties @@ -747,7 +753,7 @@ namespace Tango.MachineStudio.Developer.ViewModels /// </summary> /// <param name="applicationManager">The application manager.</param> /// <param name="notificationProvider">The notification provider.</param> - public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, INavigationManager navigationManager, IAuthenticationProvider authentication, IEventLogger eventLogger, ISpeechProvider speech) + public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, INavigationManager navigationManager, IAuthenticationProvider authentication, IEventLogger eventLogger, ISpeechProvider speech, IActionLogManager actionLogManager) { _converter = new DefaultColorConverter(); @@ -756,6 +762,7 @@ namespace Tango.MachineStudio.Developer.ViewModels AuthenticationProvider = authentication; + _actionLogManager = actionLogManager; _notification = notificationProvider; _speech = speech; _navigation = navigation; @@ -873,7 +880,7 @@ namespace Tango.MachineStudio.Developer.ViewModels foreach (var stop in stops) { - if (stop.ColorSpace.Code == BL.Enumerations.ColorSpaces.Volume.ToInt32() && !stop.IsLiquidVolumesOutOfRange) + if (stop.ColorSpace.Code == BL.Enumerations.ColorSpaces.Volume.ToInt32()) { try { @@ -1034,6 +1041,11 @@ namespace Tango.MachineStudio.Developer.ViewModels { var percent = (e.Progress / e.Total * 100d); + if (_preparingTaskItem != null) + { + _preparingTaskItem.Message = $"Preparing job for printing {(e.Progress / e.Total * 100d).ToString("0.0")}%..."; + } + if (_preparingTaskItem == null && percent == 0) { _preparingTaskItem = _notification.PushTaskItem("Preparing job for printing..."); @@ -1043,13 +1055,6 @@ namespace Tango.MachineStudio.Developer.ViewModels _preparingTaskItem.Pop(); _preparingTaskItem = null; } - else - { - if (_preparingTaskItem != null) - { - _preparingTaskItem.Message = $"Preparing job for printing {(e.Progress / e.Total * 100d).ToString("0.0")}%..."; - } - } } private void MachineOperator_ResumingJob(object sender, ResumingJobEventArgs e) @@ -1252,7 +1257,7 @@ namespace Tango.MachineStudio.Developer.ViewModels || j.Name.ToLower().Contains(filter) //Job name || - j.User.Contact.FirstName.ToLower().Contains(filter) // User first name + (j.User != null && j.User.Contact.FirstName.ToLower().Contains(filter)) // User first name || j.Length.ToString().Contains(filter); //Job length }; @@ -1371,7 +1376,7 @@ namespace Tango.MachineStudio.Developer.ViewModels /// <summary> /// Starts the job. /// </summary> - private async void StartJob(Func<Job, JobHandler> resumeFunc = null) + private async void StartJob(Func<JobHandler> resumeFunc = null) { SettingsManager.Default.Save(); @@ -1436,15 +1441,13 @@ namespace Tango.MachineStudio.Developer.ViewModels } else { - JobHandler = resumeFunc(ActiveJob); + JobHandler = resumeFunc(); } _navigation.NavigateTo(DeveloperNavigationView.RunningJobView); IsJobRunning = true; ShowJobStatus = true; - _eventLogger.Log(String.Format("Job '{0}' started...", ActiveJob.Name)); - JobHandler.StatusChanged += (x, status) => { if (IsJobRunning) @@ -1464,25 +1467,21 @@ namespace Tango.MachineStudio.Developer.ViewModels if (!segment.IsInterSegment) { _speech.SpeakInfo(String.Format("Segment {0} Started.", segment.SegmentIndex)); - _eventLogger.Log(String.Format("Segment {0} Started.", segment.SegmentIndex) + Environment.NewLine + segment.ToJsonString()); } else { _speech.SpeakInfo(String.Format("Inter Segment Started.")); - _eventLogger.Log("Inter Segment Started."); } }; JobHandler.UnitCompleted += (x, unit) => { _speech.SpeakInfo(String.Format("{0} Units Completed.", unit + 1)); - _eventLogger.Log(String.Format("{0} Units Completed.", unit + 1)); }; JobHandler.Failed += (x, ex) => { LogManager.Log(ex, String.Format("Job {0} has failed.", RunningJob.Name)); - _eventLogger.Log(ex, String.Format("Job {0} has failed.", RunningJob.Name)); SetJobFailed(); InvokeUI(() => @@ -1496,13 +1495,11 @@ namespace Tango.MachineStudio.Developer.ViewModels { _speech.SpeakInfo("Finalizing job..."); LogManager.Log(String.Format("Finalizing job {0}.", RunningJob.Name)); - _eventLogger.Log(String.Format("Finalizing job {0}.", RunningJob.Name)); }; JobHandler.Completed += (x, e) => { LogManager.Log(String.Format("Job {0} has completed.", RunningJob.Name)); - _eventLogger.Log(String.Format("Job {0} has completed.", RunningJob.Name)); SetJobCompleted(); StopRecordingIfInProgress(); }; @@ -1516,7 +1513,6 @@ namespace Tango.MachineStudio.Developer.ViewModels } LogManager.Log(String.Format("Job {0} has been canceled.", RunningJob.Name)); - _eventLogger.Log(String.Format("Job {0} has been canceled.", RunningJob.Name)); StopRecordingIfInProgress(); //Finally Canceled.. }; @@ -1534,7 +1530,6 @@ namespace Tango.MachineStudio.Developer.ViewModels catch (Exception ex) { LogManager.Log(ex); - _eventLogger.Log(ex, "An error occurred while starting the job."); _notification.ShowError("An error occurred while starting the job. " + Environment.NewLine + ex.Message); SetJobFailed(); StopRecordingIfInProgress(); @@ -1594,8 +1589,12 @@ namespace Tango.MachineStudio.Developer.ViewModels { LogManager.Log(String.Format("Saving liquid factors for RML {0}...", SelectedRML.Name)); await SelectedRML.SaveAsync(_activeJobDbContext); + var rmlAfterChange = RmlDTO.FromObservable(SelectedRML); + _actionLogManager.InsertLog(ActionLogType.RmlSaved, AuthenticationProvider.CurrentUser, SelectedRML.Name, _selectedRMLBeforeLiquidFactorsSaves, rmlAfterChange, "RML liquid factors changed from Machine Studio Research module."); + _selectedRMLBeforeLiquidFactorsSaves = rmlAfterChange; LiquidTypesRmls = ActiveJob.Machine.Configuration.GetSupportedIdsPacks(SelectedRML).Select(x => x.LiquidType).SelectMany(x => x.LiquidTypesRmls).Where(x => x.Rml.Guid == SelectedRML.Guid).ToList(); + foreach (var segment in ActiveJob.Segments) { SetSegmentBrushStopsLiquidVolumes(segment); @@ -1623,7 +1622,9 @@ namespace Tango.MachineStudio.Developer.ViewModels { LogManager.Log("Invalidating liquid factors, process parameters and process group history..."); - _selectedRML = new RmlBuilder(_activeJobDbContext).Set(SelectedRML.Guid).WithAllParametersGroup().WithCAT(SelectedMachine.Guid).WithCCT().WithLiquidFactors().Build(); + _selectedRML = new RmlBuilder(_activeJobDbContext).Set(SelectedRML.Guid).WithAllParametersGroup().WithCAT(SelectedMachine.Guid).WithCCT().WithLiquidFactors().WithSpools().Build(); + + _selectedRMLBeforeLiquidFactorsSaves = RmlDTO.FromObservable(_selectedRML); if (_selectedRML.Cct == null) { @@ -1672,7 +1673,17 @@ namespace Tango.MachineStudio.Developer.ViewModels { await Task.Factory.StartNew(() => { - InvalidateLiquidFactorsAndProcessTables(); + try + { + IsFree = false; + InvalidateLiquidFactorsAndProcessTables(); + } + catch + {} + finally + { + IsFree = true; + } }); } } @@ -1680,6 +1691,23 @@ namespace Tango.MachineStudio.Developer.ViewModels #endregion + #region Color Space + + public void OnBrushStopColorSpaceChanged(BrushStop stop) + { + if (stop != null && stop.ColorSpace != null && stop.BrushColorSpace != BL.Enumerations.ColorSpaces.Volume) + { + var lubricant = stop.LiquidVolumes.SingleOrDefault(x => x.LiquidType == LiquidTypes.Lubricant); + + if (lubricant != null) + { + lubricant.Volume = 100; + } + } + } + + #endregion + #region Process Parameters Management /// <summary> @@ -1691,12 +1719,12 @@ namespace Tango.MachineStudio.Developer.ViewModels { try { - LogManager.Log(String.Format("Uploading process parameters table {0}...", SelectedProcessParametersTable.Name)); + LogManager.Log($"Uploading process parameters table {SelectedProcessParametersTable.Name}..."); await MachineOperator.UploadProcessParameters(SelectedProcessParametersTable); } catch (Exception ex) { - LogManager.LogFormat(ex, "Failed to upload process parameters table {0}", SelectedProcessParametersTable.Name); + LogManager.Log(ex, $"Failed to upload process parameters table {SelectedProcessParametersTable.Name}"); _notification.ShowError("Failed to upload the selected process parameters." + Environment.NewLine + ex.Message); } } @@ -1715,6 +1743,8 @@ namespace Tango.MachineStudio.Developer.ViewModels using (_notification.PushTaskItem("Saving Parameters Group...")) { + var processGroupBefore = ProcessParametersTablesGroupDTO.FromObservable(SelectedRML.GetActiveProcessGroup()); + using (var db = ObservablesContext.CreateDefault()) { var active_groups = db.ProcessParametersTablesGroups.Where(x => x.RmlGuid == SelectedRML.Guid && x.Active).ToList(); @@ -1756,6 +1786,8 @@ namespace Tango.MachineStudio.Developer.ViewModels SelectedRML.ProcessParametersTablesGroups.Add(group); await SelectedRML.SaveAsync(_activeJobDbContext); + _actionLogManager.InsertLog(ActionLogType.RmlActiveProcessParametersChanged, AuthenticationProvider.CurrentUser, SelectedRML.Name, processGroupBefore, ProcessParametersTablesGroupDTO.FromObservable(SelectedRML.GetActiveProcessGroup()), "RML Active process parameters changed from Machine Studio Research module."); + InvalidateLiquidFactorsAndProcessTables(); } @@ -1800,97 +1832,110 @@ namespace Tango.MachineStudio.Developer.ViewModels using (_notification.PushTaskItem("Loading job details...")) { - await Task.Factory.StartNew(() => + try { - _disable_gamut_check = true; + await Task.Factory.StartNew(() => + { + _disable_gamut_check = true; - LogManager.Log(String.Format("Loading job {0}...", SelectedMachineJob.Name)); - SelectedSegments = new ObservableCollection<Segment>(); - SelectedBrushStops = new ObservableCollection<BrushStop>(); - SelectedRML = null; - SelectedSegment = null; - SelectedGroupHistory = null; - SelectedBrushStop = null; - SelectedProcessParametersTable = null; - RmlProcessParametersTableGroup = null; + LogManager.Log(String.Format("Loading job {0}...", SelectedMachineJob.Name)); + SelectedSegments = new ObservableCollection<Segment>(); + SelectedBrushStops = new ObservableCollection<BrushStop>(); + SelectedRML = null; + SelectedSegment = null; + SelectedGroupHistory = null; + SelectedBrushStop = null; + SelectedProcessParametersTable = null; + RmlProcessParametersTableGroup = null; - _blockInvalidateCommands = false; + _blockInvalidateCommands = false; - LogManager.Log("Creating active job DB context..."); - _activeJobDbContext = ObservablesContext.CreateDefault(); + LogManager.Log("Creating active job DB context..."); + _activeJobDbContext = ObservablesContext.CreateDefault(); - LogManager.Log("Initializing available color spaces, RMLs & Winding methods..."); + LogManager.Log("Initializing available color spaces, RMLs & Winding methods..."); - //var processParamsGroups = _activeJobDbContext.ProcessParametersTablesGroups.ToList(); - //var processParams = _activeJobDbContext.ProcessParametersTables.ToList(); + //var processParamsGroups = _activeJobDbContext.ProcessParametersTablesGroups.ToList(); + //var processParams = _activeJobDbContext.ProcessParametersTables.ToList(); - ColorSpaces = _activeJobDbContext.ColorSpaces.ToObservableCollection(); - Rmls = _activeJobDbContext.Rmls.ToObservableCollection(); - WindingMethods = _activeJobDbContext.WindingMethods.ToObservableCollection(); - SpoolTypes = _activeJobDbContext.SpoolTypes.ToObservableCollection(); + ColorSpaces = _activeJobDbContext.ColorSpaces.ToObservableCollection(); + Rmls = _activeJobDbContext.Rmls.OrderBy(i => i.Name).ToObservableCollection(); + WindingMethods = _activeJobDbContext.WindingMethods.ToObservableCollection(); + SpoolTypes = _activeJobDbContext.SpoolTypes.ToObservableCollection(); - LogManager.Log("Loading machine spools..."); - _activeJobDbContext.Spools.Where(x => x.MachineGuid == SelectedMachine.Guid).Load(); + LogManager.Log("Loading machine spools..."); + _activeJobDbContext.Spools.Where(x => x.MachineGuid == SelectedMachine.Guid).Load(); - LogManager.Log("Setting active job..."); - ActiveJob = new JobBuilder(_activeJobDbContext).Set(SelectedMachineJob.Guid).WithUser().WithSegments().WithBrushStops().WithConfiguration().WithRML().Build(); + LogManager.Log("Setting active job..."); + ActiveJob = new JobBuilder(_activeJobDbContext).Set(SelectedMachineJob.Guid).WithUser().WithSegments().WithBrushStops().WithConfiguration().WithRML().Build(); - //_activeJobDbContext.Ccts.Where(x => x.RmlGuid == ActiveJob.RmlGuid).ToList(); - //_activeJobDbContext.Cats.Where(x => x.RmlGuid == ActiveJob.RmlGuid).ToList(); - //_activeJobDbContext.Machines.SingleOrDefault(x => x.Guid == ActiveJob.MachineGuid); - //_activeJobDbContext.Configurations.SingleOrDefault(x => x.Guid == ActiveJob.Machine.ConfigurationGuid); + //_activeJobDbContext.Ccts.Where(x => x.RmlGuid == ActiveJob.RmlGuid).ToList(); + //_activeJobDbContext.Cats.Where(x => x.RmlGuid == ActiveJob.RmlGuid).ToList(); + //_activeJobDbContext.Machines.SingleOrDefault(x => x.Guid == ActiveJob.MachineGuid); + //_activeJobDbContext.Configurations.SingleOrDefault(x => x.Guid == ActiveJob.Machine.ConfigurationGuid); - //_activeJobDbContext.LiquidTypesRmls.ToList(); + //_activeJobDbContext.LiquidTypesRmls.ToList(); - //_activeJobDbContext.IdsPackFormulas.ToList(); - //_activeJobDbContext.LiquidTypes.ToList(); - //_activeJobDbContext.MidTankTypes.ToList(); - //_activeJobDbContext.DispenserTypes.ToList(); + //_activeJobDbContext.IdsPackFormulas.ToList(); + //_activeJobDbContext.LiquidTypes.ToList(); + //_activeJobDbContext.MidTankTypes.ToList(); + //_activeJobDbContext.DispenserTypes.ToList(); - //_activeJobDbContext.IdsPacks.Where(x => x.ConfigurationGuid == ActiveJob.Machine.ConfigurationGuid).ToList(); + //_activeJobDbContext.IdsPacks.Where(x => x.ConfigurationGuid == ActiveJob.Machine.ConfigurationGuid).ToList(); + _beforeSaveJobDTO = JobDTO.FromObservable(ActiveJob); - LogManager.Log("Setting selected segment..."); - _selectedSegment = ActiveJob.OrderedSegments.FirstOrDefault(); + LogManager.Log("Setting selected segment..."); + _selectedSegment = ActiveJob.OrderedSegments.FirstOrDefault(); - ActiveJob.LengthChanged -= ActiveJob_LengthChanged; - ActiveJob.LengthChanged += ActiveJob_LengthChanged; + ActiveJob.LengthChanged -= ActiveJob_LengthChanged; + ActiveJob.LengthChanged += ActiveJob_LengthChanged; - _selectedRML = ActiveJob.Rml; - InvalidateLiquidFactorsAndProcessTables(); - RaisePropertyChanged(nameof(SelectedRML)); + _selectedRML = ActiveJob.Rml; + InvalidateLiquidFactorsAndProcessTables(); + RaisePropertyChanged(nameof(SelectedRML)); - UpdateEstimatedDuration(); + UpdateEstimatedDuration(); - _blockInvalidateCommands = false; - InvalidateRelayCommands(); + _blockInvalidateCommands = false; + InvalidateRelayCommands(); - _disable_gamut_check = false; + _disable_gamut_check = false; - _settings.LastSelectedMachineGuid = SelectedMachine != null ? SelectedMachine.Guid : null; - _settings.LastSelectedJobGuid = SelectedMachineJob != null ? SelectedMachineJob.Guid : null; + _settings.LastSelectedMachineGuid = SelectedMachine != null ? SelectedMachine.Guid : null; + _settings.LastSelectedJobGuid = SelectedMachineJob != null ? SelectedMachineJob.Guid : null; - _settings.Save(); - }); + _settings.Save(); + }); - SegmentsCollectionView = CollectionViewSource.GetDefaultView(ActiveJob.Segments); - SegmentsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Segment.SegmentIndex), ListSortDirection.Ascending)); + SegmentsCollectionView = CollectionViewSource.GetDefaultView(ActiveJob.Segments); + SegmentsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Segment.SegmentIndex), ListSortDirection.Ascending)); - foreach (var segment in ActiveJob.Segments) - { - SetSegmentBrushStopsLiquidVolumes(segment); - } + foreach (var segment in ActiveJob.Segments) + { + SetSegmentBrushStopsLiquidVolumes(segment); + } - SelectedSegment = _selectedSegment; + SelectedSegment = _selectedSegment; + + if (ActiveJob != null) + { + _current_job_string = ActiveJob.ToJobFileWhenLoaded().ToString(); + } - if (ActiveJob != null) + UIHelper.DoEvents(); + _navigation.NavigateTo(DeveloperNavigationView.JobView); + } + catch (Exception ex) { - _current_job_string = ActiveJob.ToJobFileWhenLoaded().ToString(); + LogManager.Log(ex, "Error loading job."); + _notification.ShowError($"An error occurred while trying to load the selected job.\n{ex.FlattenMessage()}"); + } + finally + { + CanWork = true; } - - UIHelper.DoEvents(); - _navigation.NavigateTo(DeveloperNavigationView.JobView); } CanWork = true; @@ -1908,50 +1953,65 @@ namespace Tango.MachineStudio.Developer.ViewModels { CanWork = false; - using (_notification.PushTaskItem("Saving job details...")) + try { - await Task.Factory.StartNew(() => + using (_notification.PushTaskItem("Saving job details...")) { - LogManager.Log(String.Format("Saving the active job {0}...", ActiveJob.Name)); - ActiveJob.LastUpdated = DateTime.UtcNow; - ActiveJob.Rml = SelectedRML; - ActiveJob.EstimatedDurationMili = (int)EstimatedDuration.TotalMilliseconds; - _activeJobDbContext.SaveChanges(); - - _machineDbContext.Entry(SelectedMachineJob).Reload(); + await Task.Factory.StartNew(() => + { + LogManager.Log(String.Format("Saving the active job {0}...", ActiveJob.Name)); + ActiveJob.LastUpdated = DateTime.UtcNow; + ActiveJob.IsSynchronized = false; + ActiveJob.Rml = SelectedRML; + ActiveJob.EstimatedDurationMili = (int)EstimatedDuration.TotalMilliseconds; + ActiveJob.MarkModified(_activeJobDbContext); + _activeJobDbContext.SaveChanges(); + var afterJobDTO = JobDTO.FromObservable(ActiveJob); + _actionLogManager.InsertLog(ActionLogType.JobSaved, AuthenticationProvider.CurrentUser, _beforeSaveJobDTO.Name, _beforeSaveJobDTO, afterJobDTO, "Job saved from research module in Machine Studio."); + _beforeSaveJobDTO = afterJobDTO; - _machineDbContext.Entry(SelectedMachineJob).Collection(x => x.Segments).Load(); + _machineDbContext.Entry(SelectedMachineJob).Reload(); - foreach (var segment in SelectedMachineJob.Segments.ToList()) - { - _machineDbContext.Entry(segment).Collection(x => x.BrushStops).Load(); + _machineDbContext.Entry(SelectedMachineJob).Collection(x => x.Segments).Load(); - foreach (var brushStop in segment.BrushStops.ToList()) + foreach (var segment in SelectedMachineJob.Segments.ToList()) { - _machineDbContext.Entry(brushStop).Reload(); - } + _machineDbContext.Entry(segment).Collection(x => x.BrushStops).Load(); - _machineDbContext.Entry(segment).Reload(); - } + foreach (var brushStop in segment.BrushStops.ToList()) + { + _machineDbContext.Entry(brushStop).Reload(); + } - InvokeUI(() => - { - SelectedMachineJob.Segments = SelectedMachineJob.Segments; - }); + _machineDbContext.Entry(segment).Reload(); + } - var settings = SettingsManager.Default.GetOrCreate<DeveloperModuleSettings>(); - settings.DefaultJobRmlGuid = ActiveJob.RmlGuid; - settings.Save(); + InvokeUI(() => + { + SelectedMachineJob.Segments = SelectedMachineJob.Segments; + }); - if (ActiveJob != null) - { - _current_job_string = ActiveJob.ToJobFileWhenLoaded().ToString(); - } - }); - } + var settings = SettingsManager.Default.GetOrCreate<DeveloperModuleSettings>(); + settings.DefaultJobRmlGuid = ActiveJob.RmlGuid; + settings.Save(); - CanWork = true; + if (ActiveJob != null) + { + _current_job_string = ActiveJob.ToJobFileWhenLoaded().ToString(); + } + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving active job."); + _notification.ShowError($"An error occurred while trying to save the current job.\n{ex.FlattenMessage()}"); + } + finally + { + CanWork = true; + } } } @@ -2139,7 +2199,7 @@ namespace Tango.MachineStudio.Developer.ViewModels { if (ActiveJob != null) { - LogManager.LogFormat("Adding new segment to job {0}...", ActiveJob.Name); + LogManager.Log($"Adding new segment to job {ActiveJob.Name}..."); Segment seg = new Segment(); seg.Job = ActiveJob; seg.Name = "SEGMENT"; @@ -2171,6 +2231,8 @@ namespace Tango.MachineStudio.Developer.ViewModels { if (_notification.ShowQuestion("Are you sure you want to delete the selected jobs?")) { + var jobsToReport = SelectedJobs.Select(x => JobDTO.FromObservable(x)).ToList(); + LogManager.Log(String.Format("Removing {0} jobs...", SelectedJobs.Count)); SelectedJobs.ToList().ForEach(x => { @@ -2182,6 +2244,11 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); } + + foreach (var job in jobsToReport) + { + _actionLogManager.InsertLog(ActionLogType.JobDeleted, AuthenticationProvider.CurrentUser, job.Name, job, "Job deleted using Machine Studio.", true); + } } } } @@ -2202,6 +2269,8 @@ namespace Tango.MachineStudio.Developer.ViewModels var settings = SettingsManager.Default.GetOrCreate<DeveloperModuleSettings>(); Job newJob = new Job(); + newJob.LastUpdated = DateTime.UtcNow; + newJob.JobSource = JobSource.Remote; newJob.Name = jobName; newJob.CreationDate = DateTime.UtcNow; newJob.UserGuid = AuthenticationProvider.CurrentUser.Guid; @@ -2236,6 +2305,7 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); + _actionLogManager.InsertLog(ActionLogType.JobCreated, AuthenticationProvider.CurrentUser, newJob.Name, newJob, "Job created using Machine Studio."); SelectedMachineJob = newJob; LoadSelectedJob(); } @@ -2261,6 +2331,13 @@ namespace Tango.MachineStudio.Developer.ViewModels return; } SelectedSegment.BrushStops.Remove(x); + var existingBrushStop = _activeJobDbContext.BrushStops.FirstOrDefault(y => y.Guid == x.Guid); + if(existingBrushStop != null) + { + _activeJobDbContext.BrushStops.Remove(existingBrushStop); + } + + }); ArrangeBrushStopsIndices(); @@ -2275,7 +2352,7 @@ namespace Tango.MachineStudio.Developer.ViewModels { if (SelectedSegment != null) { - LogManager.LogFormat("Adding new brush stop to segment...", SelectedSegment.SegmentIndex.ToString()); + LogManager.Log($"Adding new brush stop to segment '{SelectedSegment.SegmentIndex}'..."); var stop = new BrushStop(); @@ -2295,6 +2372,7 @@ namespace Tango.MachineStudio.Developer.ViewModels stop.SetAllDispensingStepDivisions(BL.Dispensing.DispenserStepDivisions.D8); stop.SetLiquidVolumes(SelectedMachine.Configuration, SelectedRML, SelectedProcessParametersTable); SelectedSegment.BrushStops.Add(stop); + // _activeJobDbContext.BrushStops.Add(stop); SelectedSegment.BrushStops.ToList().ForEach(x => x.RaiseOffsetChanged()); ArrangeBrushStopsIndices(); } @@ -2305,7 +2383,7 @@ namespace Tango.MachineStudio.Developer.ViewModels /// </summary> private void DuplicateSelectedBrushStops() { - LogManager.LogFormat("Duplicating {0} brush stops...", SelectedBrushStops.Count); + LogManager.Log($"Duplicating {SelectedBrushStops.Count} brush stops..."); foreach (var stop in SelectedBrushStops.OrderBy(x => x.StopIndex)) { @@ -2323,7 +2401,7 @@ namespace Tango.MachineStudio.Developer.ViewModels /// </summary> private void DuplicateSelectedSegments() { - LogManager.LogFormat("Duplicating {0} segments...", SelectedSegments.Count); + LogManager.Log($"Duplicating {SelectedSegments.Count} segments..."); int start_index = SelectedSegments.Max(x => x.SegmentIndex); @@ -2351,7 +2429,7 @@ namespace Tango.MachineStudio.Developer.ViewModels { CanWork = false; - LogManager.LogFormat("Duplicating {0} jobs...", SelectedJobs.Count); + LogManager.Log($"Duplicating {SelectedJobs.Count} jobs..."); int index = SelectedMachine.Jobs.Max(x => x.JobIndex); @@ -2365,6 +2443,11 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); + foreach (var job in SelectedJobs) + { + _actionLogManager.InsertLog(ActionLogType.JobCreated, AuthenticationProvider.CurrentUser, job.Name, job, "Job cloned using Machine Studio."); + } + CanWork = true; } } @@ -2588,17 +2671,26 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log($"Importing job files..."); + List<Job> jobsToReport = new List<Job>(); + foreach (var file in dlg.FileNames) { var bytes = File.ReadAllBytes(file); var jobFile = JobFile.Parser.ParseFrom(bytes); var job = await Job.FromJobFile(jobFile, SelectedMachine.Guid, AuthenticationProvider.CurrentUser.Guid); + job.JobSource = JobSource.Remote; _machineDbContext.Jobs.Add(job); + jobsToReport.Add(job); } await _machineDbContext.SaveChangesAsync(); + foreach (var job in jobsToReport) + { + _actionLogManager.InsertLog(ActionLogType.JobImported, AuthenticationProvider.CurrentUser, job.Name, job, "Job imported using Machine Studio."); + } + IsFree = true; _notification.ShowInfo($"Jobs imported successfully."); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml index f0e9dc29c..c0cb963e7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml @@ -5,8 +5,10 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:Tango.MachineStudio.Developer.ViewModels" xmlns:local="clr-namespace:Tango.MachineStudio.Developer.Views" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" - Height="450" Width="800" Background="{StaticResource WhiteBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:InsufficientLiquidQuantityViewVM, IsDesignTimeCreatable=False}"> + Height="590" Width="800" d:DataContext="{d:DesignInstance Type=vm:InsufficientLiquidQuantityViewVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource Dialog.Foreground}" + Background="{StaticResource Dialog.Background}"> <Grid Margin="10"> <DockPanel> <StackPanel DockPanel.Dock="Top"> @@ -23,28 +25,60 @@ <Button HorizontalAlignment="Right" DockPanel.Dock="Bottom" Height="40" Width="140" Command="{Binding CloseCommand}" Margin="10 0 0 0">CLOSE</Button> </Grid> - <Border Margin="0 40 0 0" BorderThickness="1" BorderBrush="{StaticResource BorderBrushGainsboro}" CornerRadius="3"> - <ItemsControl ItemsSource="{Binding Exception.IdsPackLevels}"> + <Border Margin="0 20 0 0" Padding="10" BorderThickness="1" BorderBrush="{StaticResource BorderBrushGainsboro}" CornerRadius="3"> + <ItemsControl ItemsSource="{Binding Exception.IdsPackLevels}" VerticalAlignment="Top"> <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"> - <TextBlock HorizontalAlignment="Center" Text="{Binding IdsPack.LiquidType.Name}"></TextBlock> - <Border Margin="0 5 0 0" Height="150" Width="50" CornerRadius="3" BorderThickness="1" BorderBrush="{StaticResource BorderBrushGainsboro}"> + <Grid Margin="0 0 0 4"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="40" /> + <ColumnDefinition Width="160" /> + <ColumnDefinition Width="1*" /> + </Grid.ColumnDefinitions> + <material:PackIcon VerticalAlignment="Center" Width="24" Height="24"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="Kind" Value="Check"></Setter> + <Setter Property="Foreground" Value="{StaticResource GreenBrush100}"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsValid}" Value="False"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource OrangeBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsOverMax}" Value="True"> + <Setter Property="Kind" Value="AlertOctagon"></Setter> + <Setter Property="Foreground" Value="{StaticResource RedBrush100}"></Setter> + </DataTrigger> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding IsValid}" Value="True" /> + <Condition Binding="{Binding IsOverMax}" Value="False" /> + </MultiDataTrigger.Conditions> + <Setter Property="Kind" Value="Check"></Setter> + <Setter Property="Foreground" Value="{StaticResource GreenBrush100}"></Setter> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + <!--<material:PackIcon Kind="AlertOctagon" VerticalAlignment="Center" Width="24" Height="24" Visibility="{Binding IsValid,Converter={StaticResource BoolToVisConverter}}" />--> + + <Border Grid.Column="1" Margin="5 0 0 0" Height="45" Width="150" CornerRadius="3" BorderThickness="1" BorderBrush="{StaticResource BorderBrushGainsboro}"> <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="Red" StrokeThickness="2" HorizontalAlignment="Left"> <Rectangle.Style> <Style TargetType="Rectangle"> <Style.Triggers> @@ -69,9 +103,18 @@ </Style> </Rectangle.Style> </Rectangle> + + + <TextBlock Foreground="#3B3B3B" 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" Foreground="{StaticResource RedBrush100}"></TextBlock> + </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml.cs index 171cb754e..51cfb1e73 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/InsufficientLiquidQuantityView.xaml.cs @@ -33,7 +33,7 @@ namespace Tango.MachineStudio.Developer.Views 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 = ((double)packLevel.Current / (double)MachineOperator.MAX_DISPENSER_NANOLITER) * parent.ActualWidth; } private void Limit_Loaded(object sender, RoutedEventArgs e) @@ -42,8 +42,8 @@ namespace Tango.MachineStudio.Developer.Views 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/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml index 3bda86036..32b7ccd86 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml @@ -28,7 +28,8 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Tango.MachineStudio.Developer.Views" mc:Ignorable="d" - d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}" x:Name="control"> + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" + DataContext="{x:Static global:ViewModelLocator.MainViewVM}" x:Name="control"> <UserControl.Resources> @@ -241,91 +242,93 @@ </Style> <DataTemplate x:Key="Volume_Template"> - <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> - <StackPanel VerticalAlignment="Center"> - <ItemsControl VerticalAlignment="Center"> - <ItemsControl.Style> - <Style TargetType="ItemsControl"> - <Setter Property="ItemsSource" Value="{Binding LiquidVolumes}"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.Settings.UsePreferredLiquidVolumeIndex}" Value="True"> - <Setter Property="ItemsSource" Value="{Binding LiquidVolumesOrdered}"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </ItemsControl.Style> - <ItemsControl.ItemsPanel> - <ItemsPanelTemplate> - <StackPanel VerticalAlignment="Center" Orientation="Horizontal" IsItemsHost="True"></StackPanel> - </ItemsPanelTemplate> - </ItemsControl.ItemsPanel> - <ItemsControl.ItemTemplate> - <DataTemplate> - <Border> - <Border.Style> - <Style TargetType="Border"> - <Setter Property="Visibility" Value="Visible"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding IdsPack.IdsPackFormula.Name}" Value="Lubricant"> - <Setter Property="Visibility" Value="Collapsed"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </Border.Style> - <ContentControl Focusable="False" Style="{StaticResource numberBorder}" Margin="10 0 0 0" Width="60" Height="60"> - <ContentControl.Foreground> - <SolidColorBrush Color="{Binding IdsPack.LiquidType.Color,Converter={StaticResource ColorToIntegerConverter}}"></SolidColorBrush> - </ContentControl.Foreground> - <mahapps:NumericUpDown ValueChanged="OnBrushStopFieldValueChanged" FontSize="{StaticResource NumbersFontSize}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Value="{Binding Volume, Mode=TwoWay}" Background="Transparent" Width="40" HideUpDownButtons="True" Minimum="0" Maximum="1000" InterceptArrowKeys="True" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" HorizontalContentAlignment="Center"> - <mahapps:NumericUpDown.Resources> - <StaticResource ResourceKey="SelectAllTextBoxResource"></StaticResource> - </mahapps:NumericUpDown.Resources> - </mahapps:NumericUpDown> - </ContentControl> - </Border> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - - <StackPanel Orientation="Horizontal" Margin="30 10 0 0" Height="16" Visibility="{Binding IsLiquidVolumesOutOfRange,Converter={StaticResource BooleanToVisibilityConverter}}"> - <materialDesign:PackIcon Kind="Alert" Foreground="{StaticResource OrangeBrush}" /> - <TextBlock Margin="5 0 0 0" Foreground="{StaticResource OrangeBrush}">Liquid volumes exceeds the maximum range for color conversion!</TextBlock> + <StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> + <StackPanel VerticalAlignment="Center"> + <ItemsControl VerticalAlignment="Center"> + <ItemsControl.Style> + <Style TargetType="ItemsControl"> + <Setter Property="ItemsSource" Value="{Binding LiquidVolumes}"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.Settings.UsePreferredLiquidVolumeIndex}" Value="True"> + <Setter Property="ItemsSource" Value="{Binding LiquidVolumesOrdered}"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ItemsControl.Style> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <StackPanel VerticalAlignment="Center" Orientation="Horizontal" IsItemsHost="True"></StackPanel> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Visibility" Value="Visible"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IdsPack.IdsPackFormula.Name}" Value="Lubricant"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <ContentControl Focusable="False" Style="{StaticResource numberBorder}" Margin="10 0 0 0" Width="60" Height="60"> + <ContentControl.Foreground> + <SolidColorBrush Color="{Binding IdsPack.LiquidType.Color,Converter={StaticResource ColorToIntegerConverter}}"></SolidColorBrush> + </ContentControl.Foreground> + <mahapps:NumericUpDown ValueChanged="OnBrushStopFieldValueChanged" FontSize="{StaticResource NumbersFontSize}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Value="{Binding Volume, Mode=TwoWay}" Background="Transparent" Width="40" HideUpDownButtons="True" Minimum="0" Maximum="1000" InterceptArrowKeys="True" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" HorizontalContentAlignment="Center"> + <mahapps:NumericUpDown.Resources> + <StaticResource ResourceKey="SelectAllTextBoxResource"></StaticResource> + </mahapps:NumericUpDown.Resources> + </mahapps:NumericUpDown> + </ContentControl> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> </StackPanel> - </StackPanel> - <materialDesign:PackIcon Kind="ChevronDoubleLeft" Margin="40 2 0 0" VerticalAlignment="Center" Foreground="Gray" /> + <materialDesign:PackIcon Kind="ChevronDoubleLeft" Margin="40 2 0 0" VerticalAlignment="Center" Foreground="Gray" /> - <TextBlock VerticalAlignment="Center" FontSize="16" Margin="5 0 0 0" FontStyle="Italic" Foreground="Gray"> + <TextBlock VerticalAlignment="Center" FontSize="16" Margin="5 0 0 0" FontStyle="Italic" Foreground="Gray"> <Run>Total:</Run> <Run Text="{Binding TotalLiquidVolume,Mode=OneWay,StringFormat=0}"></Run><Run>%</Run> <Run>(</Run> <Run FontSize="10" Text="{Binding TotalLiquidNanoliterPerCentimeter,Mode=OneWay,StringFormat=0.00}"></Run> <Run FontSize="12">nl</Run> <Run>)</Run> - </TextBlock> + </TextBlock> - <Border Margin="60 0 0 0" DataContext="{Binding LiquidVolumes,Converter={StaticResource LiquidVolumesToLubricantLiquidVolume}}" BorderBrush="{StaticResource WhiteBrush100}" BorderThickness="1 0 0 0"> - <Border.Style> - <Style TargetType="Border"> - <Setter Property="Visibility" Value="Collapsed"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding Converter={StaticResource NullObjectToBooleanConverter}}" Value="True"> - <Setter Property="Visibility" Value="Visible"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </Border.Style> - <ContentControl Focusable="False" Style="{StaticResource numberBorder}" Margin="10 0 0 0" Width="55" Height="55"> - <ContentControl.Foreground> - <SolidColorBrush Color="{Binding IdsPack.LiquidType.Color,Converter={StaticResource ColorToIntegerConverter}}"></SolidColorBrush> - </ContentControl.Foreground> - <mahapps:NumericUpDown Foreground="{StaticResource GrayBrush250}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" FontSize="20" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Value="{Binding Volume, Mode=TwoWay}" Background="Transparent" Width="40" HideUpDownButtons="True" Minimum="0" Maximum="1000" InterceptArrowKeys="True" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" HorizontalContentAlignment="Center"> - <mahapps:NumericUpDown.Resources> - <StaticResource ResourceKey="SelectAllTextBoxResource"></StaticResource> - </mahapps:NumericUpDown.Resources> - </mahapps:NumericUpDown> - </ContentControl> - </Border> + <Border Margin="60 0 0 0" DataContext="{Binding LiquidVolumes,Converter={StaticResource LiquidVolumesToLubricantLiquidVolume}}" BorderBrush="{StaticResource WhiteBrush100}" BorderThickness="1 0 0 0"> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Converter={StaticResource NullObjectToBooleanConverter}}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <ContentControl Focusable="False" Style="{StaticResource numberBorder}" Margin="10 0 0 0" Width="55" Height="55"> + <ContentControl.Foreground> + <SolidColorBrush Color="{Binding IdsPack.LiquidType.Color,Converter={StaticResource ColorToIntegerConverter}}"></SolidColorBrush> + </ContentControl.Foreground> + <mahapps:NumericUpDown Foreground="{StaticResource GrayBrush250}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" FontSize="20" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Value="{Binding Volume, Mode=TwoWay}" Background="Transparent" Width="40" HideUpDownButtons="True" Minimum="0" Maximum="1000" InterceptArrowKeys="True" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" HorizontalContentAlignment="Center"> + <mahapps:NumericUpDown.Resources> + <StaticResource ResourceKey="SelectAllTextBoxResource"></StaticResource> + </mahapps:NumericUpDown.Resources> + </mahapps:NumericUpDown> + </ContentControl> + </Border> + </StackPanel> + + <StackPanel Orientation="Horizontal" Margin="30 10 0 0" Height="16" Visibility="{Binding IsLiquidVolumesOutOfRange,Converter={StaticResource BooleanToVisibilityConverter}}"> + <materialDesign:PackIcon Kind="Alert" Foreground="{StaticResource OrangeBrush}" /> + <TextBlock Margin="5 0 0 0" Foreground="{StaticResource OrangeBrush}">Liquid volumes exceeds the maximum range for color conversion!</TextBlock> + </StackPanel> </StackPanel> </DataTemplate> @@ -677,7 +680,7 @@ </StackPanel> </Border> - <Border Style="{StaticResource JobFieldBorder}"> + <Border Style="{StaticResource JobFieldBorder}" Visibility="{Binding IsSideBarOpened,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> <StackPanel Margin="20 5 5 5" Width="140"> <StackPanel Orientation="Horizontal"> <Image Source="../Images/repeat.png" Width="32"></Image> @@ -753,7 +756,7 @@ <StackPanel> <TextBlock>MEDIA</TextBlock> <StackPanel Orientation="Horizontal" DockPanel.Dock="Left"> - <ComboBox Width="250" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRML}" Style="{StaticResource TransparentComboBoxStyle}" HorizontalContentAlignment="Stretch"> + <controls:SearchComboBox Width="250" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRML}" HorizontalContentAlignment="Stretch" SearchProperty="Name"> <ComboBox.ItemTemplate> <DataTemplate> <DockPanel> @@ -768,7 +771,7 @@ </DockPanel> </DataTemplate> </ComboBox.ItemTemplate> - </ComboBox> + </controls:SearchComboBox> <!--<Button Margin="20 30 0 0" Command="{Binding EditRMLCommand}" HorizontalAlignment="Right" Style="{StaticResource MaterialDesignFlatButton}"> <StackPanel Orientation="Horizontal"> @@ -789,9 +792,9 @@ </StackPanel> - <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 40 180 0"> + <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="60 40 180 0" Visibility="{Binding IsSideBarOpened,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> <materialDesign:PackIcon Kind="ChevronLeft" Width="24" Height="24" /> - <TextBlock Margin="0 -2 0 0" VerticalAlignment="Center"><Run>SUPPORTED MEDIA LIQUID</Run> <Run FontSize="10" Foreground="{StaticResource DimGrayBrush}">( Max Nanolitter/CM )</Run></TextBlock> + <TextBlock Margin="0 -2 0 0" VerticalAlignment="Center"><Run>MEDIA LIQUIDS</Run> <Run FontSize="10" Foreground="{StaticResource DimGrayBrush}">( Max Nanolitter/CM )</Run></TextBlock> <materialDesign:PackIcon Kind="ChevronRight" Width="24" Height="24" /> </StackPanel> @@ -895,7 +898,7 @@ </DockPanel> </Grid> <Grid Margin="0 10 10 0"> - <controls:MultiSelectListBox x:Name="listStops" AutomationProperties.AutomationId="{x:Static automation:Developer.BrushStopsListBox}" SelectionMode="Extended" Style="{x:Null}" Background="Transparent" ScrollViewer.CanContentScroll="False" BorderThickness="0" ItemsSource="{Binding BrushStopsCollectionView}" SelectedItem="{Binding SelectedBrushStop}" SelectedItemsList="{Binding SelectedBrushStops,Mode=TwoWay}" HorizontalContentAlignment="Stretch"> + <controls:MultiSelectListBox x:Name="listStops" ScrollViewer.HorizontalScrollBarVisibility="Disabled" AutomationProperties.AutomationId="{x:Static automation:Developer.BrushStopsListBox}" SelectionMode="Extended" Style="{x:Null}" Background="Transparent" ScrollViewer.CanContentScroll="False" BorderThickness="0" ItemsSource="{Binding BrushStopsCollectionView}" SelectedItem="{Binding SelectedBrushStop}" SelectedItemsList="{Binding SelectedBrushStops,Mode=TwoWay}" HorizontalContentAlignment="Stretch"> <ListBox.Template> <ControlTemplate TargetType="{x:Type ListBox}"> <Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" @@ -973,7 +976,8 @@ <Image Source="../Images/colorspace.png" Width="24"></Image> <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontSize="10">Color Space</TextBlock> </StackPanel> - <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.ColorSpaces}" SelectedItem="{Binding ColorSpace}" DisplayMemberPath="Name" Width="100" HorizontalAlignment="Left"> + <ComboBox SelectionChanged="OnBrushStopColorSpace_SelectionChanged" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.ColorSpaces}" SelectedItem="{Binding ColorSpace}" DisplayMemberPath="Name" Width="100" HorizontalAlignment="Left" + Style="{StaticResource TransparentComboBoxStyle}" > <ComboBox.ItemContainerStyle> <Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}"> <Setter Property="Background" Value="{StaticResource WhiteBrush100}"></Setter> @@ -1187,6 +1191,41 @@ <Setter Property="Content"> <Setter.Value> <TextBlock> + <Run Text="{Binding PulsePerSecondFull,Mode=OneWay,StringFormat='0.0'}"></Run> + <Run Text="(pulse)" FontSize="9" Foreground="{StaticResource GrayBrush250}"></Run> + </TextBlock> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding DispenserStepDivision}" Value="{x:Static dispensing:DispenserStepDivisions.Auto}"> + <Setter Property="Content" Value="Auto"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding DispenserStepDivision,Converter={StaticResource IsNotConverter},ConverterParameter={x:Static dispensing:DispenserStepDivisions.Auto}}" Value="True"> + <Setter Property="Content"> + <Setter.Value> + <TextBlock> + <Run Text="{Binding PulsePerSecondFull,Mode=OneWay,StringFormat='0.0'}"></Run> + <Run Text="(pulse)" FontSize="9" Foreground="{StaticResource GrayBrush250}"></Run> + </TextBlock> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Label.Style> + </Label> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTemplateColumn Header="PULSE / SEC (full step)"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <Label VerticalAlignment="Center"> + <Label.Style> + <Style TargetType="Label"> + <Setter Property="Content"> + <Setter.Value> + <TextBlock> <Run Text="{Binding PulsePerSecond,Mode=OneWay,StringFormat='0.0'}"></Run> <Run Text="(pulse)" FontSize="9" Foreground="{StaticResource GrayBrush250}"></Run> </TextBlock> @@ -1366,7 +1405,7 @@ <Grid Background="{StaticResource TransparentBackgroundBrush100}"> <Grid.Style> <Style TargetType="Grid"> - <Setter Property="Width" Value="520"></Setter> + <Setter Property="Width" Value="640"></Setter> <Setter Property="LayoutTransform"> <Setter.Value> <ScaleTransform ScaleY="1" ScaleX="0"></ScaleTransform> @@ -1481,7 +1520,7 @@ <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> - <Grid Width="97"> + <Grid Width="97" ToolTip="{Binding Name}" Background="Transparent" ToolTipService.InitialShowDelay="1000" ToolTipService.BetweenShowDelay="1000"> <Border> <Border.Style> <Style TargetType="Border"> @@ -1504,7 +1543,7 @@ </WrapPanel.Resources> - <editors:ParameterizedEditor ParameterizedObject="{Binding}" GeneratingItems="ParameterizedEditor_GeneratingItems"> + <editors:ParameterizedEditor ParameterizedObject="{Binding}"> <editors:ParameterizedEditor.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True" Orientation="Horizontal" /> @@ -1512,11 +1551,11 @@ </editors:ParameterizedEditor.ItemsPanel> <editors:ParameterizedEditor.DoubleTemplate> <DataTemplate> - <Grid Background="Transparent" Style="{StaticResource draggableDroppableGrid}" dragAndDrop:DragAndDropService.Drop="OnProcessParameterDropped" dragAndDrop:DragAndDropService.DraggingSurface="{Binding RelativeSource={RelativeSource AncestorType=editors:ParameterizedEditor},Path=DraggingSurface}"> + <Grid Background="Transparent"> <ContentControl> <StackPanel> - <TextBlock IsHitTestVisible="False" Margin="0 5 0 5" Text="{Binding Name}" FontSize="11" Foreground="{StaticResource MainWindow.Foreground}"></TextBlock> - <mahapps:NumericUpDown FontSize="20" Minimum="0" Margin="0 0 5 0" HideUpDownButtons="True" HorizontalContentAlignment="Center" Maximum="10000" StringFormat="0.0" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}" Foreground="{StaticResource MainWindow.Foreground}"></mahapps:NumericUpDown> + <TextBlock ToolTip="{Binding Name}" IsHitTestVisible="False" Margin="0 5 0 5" Text="{Binding Name}" FontSize="11" Foreground="{StaticResource MainWindow.Foreground}"></TextBlock> + <mahapps:NumericUpDown FontSize="20" Minimum="0" Margin="0 0 5 0" HideUpDownButtons="True" HorizontalContentAlignment="Center" Maximum="10000" StringFormat="{Binding StringFormat}" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}" Foreground="{StaticResource MainWindow.Foreground}"></mahapps:NumericUpDown> </StackPanel> </ContentControl> </Grid> @@ -1572,16 +1611,17 @@ <StackPanel Orientation="Horizontal"> <ToggleButton IsChecked="{Binding AutoProcessSelection}" /> - <TextBlock Margin="5 0 0 0">Use Recommended Process Parameters (auto)</TextBlock> + <TextBlock Margin="5 3 0 0">Use Recommended Process Parameters (auto)</TextBlock> </StackPanel> - <StackPanel Margin="0 40 0 0" Orientation="Horizontal" HorizontalAlignment="Right"> - <Button Height="40" Width="105" Command="{Binding ResetProcessParametersCommand}" Background="Transparent" BorderBrush="{StaticResource DarkGrayBrush200}" Foreground="{StaticResource DarkGrayBrush200}" Margin="0 2 10 0" ToolTip="Resets the current process parameters in the embedded device"> + <Grid Margin="0 40 0 0" > + <Button HorizontalAlignment="Left" Height="40" Width="105" Command="{Binding ResetProcessParametersCommand}" Background="Transparent" BorderBrush="{StaticResource DarkGrayBrush200}" Foreground="{StaticResource DarkGrayBrush200}" Margin="0 2 10 0" ToolTip="Resets the current process parameters in the embedded device"> <TextBlock TextWrapping="Wrap" TextAlignment="Center"> TEMP OFF </TextBlock> </Button> - <Button Height="40" Command="{Binding SaveProcessParametersCommand}" HorizontalAlignment="Left" IsEnabled="{Binding AuthenticationProvider.CurrentUser,Converter={StaticResource UserRoleToBooleanConverter},ConverterParameter='Researcher'}"> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> + <Button Height="40" Command="{Binding SaveProcessParametersCommand}" HorizontalAlignment="Left" IsEnabled="{Binding AuthenticationProvider.CurrentUser,Converter={StaticResource UserRoleToBooleanConverter},ConverterParameter='Researcher'}"> <StackPanel Orientation="Horizontal"> <materialDesign:PackIcon VerticalAlignment="Center" Kind="ContentSave"></materialDesign:PackIcon> <TextBlock Margin="10 0 0 0">SAVE PARAMETERS</TextBlock> @@ -1594,6 +1634,7 @@ </StackPanel> </Button> </StackPanel> + </Grid> </StackPanel> </StackPanel> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs index 28e488aae..94c1ed802 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs @@ -159,46 +159,6 @@ namespace Tango.MachineStudio.Developer.Views e.Handled = true; } - private void ParameterizedEditor_GeneratingItems(object sender, SharedUI.Editors.ParameterizedEditor.GeneratingItemsEventArgs e) - { - var settings = SettingsManager.Default.GetOrCreate<DeveloperModuleSettings>(); - - List<ParameterItem> items = e.Result.ToList(); - - if (settings.ProcessParametersIndices.Count > 0) - { - items.Clear(); - - foreach (var item in settings.ProcessParametersIndices.OrderBy(x => x.Index)) - { - var p = e.Source.SingleOrDefault(x => x.Name == item.Name); - - if (p != null) - { - items.Add(p); - } - } - } - else - { - ProcessParametersTable p = new ProcessParametersTable(); - var pp = p.CreateParametersCollection(Core.ParameterItemMode.Binding); - - foreach (var item in pp) - { - settings.ProcessParametersIndices.Add(new ParameterIndex() - { - Index = pp.IndexOf(item), - Name = item.Name - }); - } - - settings.Save(); - } - - e.Result = items; - } - private void OnProcessParameterDropped(object sender, DropEventArgs e) { ParameterItem draggedItem = e.Draggable.DataContext as ParameterItem; @@ -321,5 +281,10 @@ namespace Tango.MachineStudio.Developer.Views { listStops.SelectedItem = (sender as ListBoxItem).DataContext; } + + private void OnBrushStopColorSpace_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + _vm.OnBrushStopColorSpaceChanged((sender as ComboBox).DataContext as BrushStop); + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MachineJobSelectionView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MachineJobSelectionView.xaml index f8a10e7c4..a3d2dbd68 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MachineJobSelectionView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MachineJobSelectionView.xaml @@ -64,7 +64,7 @@ <Grid DockPanel.Dock="Top"> <StackPanel> <StackPanel Orientation="Horizontal"> - <Image Source="../Images/machine-trans.png" RenderOptions.BitmapScalingMode="Fant" Width="50"></Image> + <Image Source="{StaticResource MachineSmall}" RenderOptions.BitmapScalingMode="Fant" Width="50"></Image> <TextBlock VerticalAlignment="Center" FontWeight="SemiBold" Margin="30 0 0 0" FontSize="30" FontStyle="Italic">MACHINE JOBS</TextBlock> </StackPanel> <Rectangle HorizontalAlignment="Stretch" Margin="0 10 0 0" VerticalAlignment="Bottom" StrokeThickness="1" Height="3"> @@ -125,7 +125,7 @@ <Grid Margin="0 20 0 0"> <commonControls:LoadingPanel IsLoading="{Binding CanWork,Converter={StaticResource BooleanInverseConverter}}"> - <controls:MultiSelectDataGrid MouseDoubleClick="MultiSelectDataGrid_MouseDoubleClick" AutomationProperties.AutomationId="{x:Static automation:Developer.JobsDataGrid}" Style="{StaticResource {x:Type DataGrid}}" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" AutoGenerateColumns="False" Background="Transparent" ItemsSource="{Binding JobsCollectionView}" SelectedItem="{Binding SelectedMachineJob}" SelectedItemsList="{Binding SelectedJobs,Mode=TwoWay}"> + <controls:MultiSelectDataGrid DoubleClickCommand="{Binding LoadJobCommand}" AutomationProperties.AutomationId="{x:Static automation:Developer.JobsDataGrid}" Style="{StaticResource {x:Type DataGrid}}" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" AutoGenerateColumns="False" Background="Transparent" ItemsSource="{Binding JobsCollectionView}" SelectedItem="{Binding SelectedMachineJob}" SelectedItemsList="{Binding SelectedJobs,Mode=TwoWay}"> <DataGrid.CellStyle> <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> <Setter Property="BorderThickness" Value="0"/> @@ -190,10 +190,10 @@ </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> - <DataGridTemplateColumn Header="CREATED BY" Width="100" CanUserSort="True" SortMemberPath="User"> + <DataGridTemplateColumn Header="CREATED BY" Width="100" CanUserSort="True" SortMemberPath="User.Contact.FirstName"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> - <TextBlock Text="{Binding User.Contact.FirstName}" VerticalAlignment="Center" FontSize="14"></TextBlock> + <TextBlock Text="{Binding User.Contact.FirstName,TargetNullValue='PPC',FallbackValue='PPC'}" VerticalAlignment="Center" FontSize="14"></TextBlock> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MainView.xaml index abea6aec9..d0caa2447 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/MainView.xaml @@ -330,31 +330,36 @@ <Rectangle Height="30" Margin="0 10 0 0" VerticalAlignment="Center" Fill="{Binding SegmentBrush}"> </Rectangle> - <Canvas Height="30" HorizontalAlignment="Center" Width="80"> - <Label Padding="0" Margin="0"> - <Label.Style> - <Style TargetType="Label"> - <Setter Property="Content" Value="{x:Null}"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding Started}" Value="True"> - <Setter Property="Content"> - <Setter.Value> - <TextBlock Text="{Binding RemainingTime,StringFormat=hh\\:mm\\:ss}" Foreground="{StaticResource RedBrush300}" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Margin="10" FontSize="20"></TextBlock> - </Setter.Value> - </Setter> - </DataTrigger> - <DataTrigger Binding="{Binding Completed}" Value="True"> - <Setter Property="Content"> - <Setter.Value> - <materialDesign:PackIcon Margin="30 10 0 0" HorizontalAlignment="Center" Width="24" Height="24" Kind="Check" Foreground="#47FF00" /> - </Setter.Value> - </Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </Label.Style> - </Label> - </Canvas> + + <Grid Height="30"> + <TextBlock Visibility="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.RunningJobStatus.IsFinalizing, Converter={StaticResource BooleanToVisibilityConverter}}" VerticalAlignment="Center" Background="Transparent" FontSize="12" Foreground="{StaticResource RedBrush100}">Finalizing...</TextBlock> + <Canvas Height="30" HorizontalAlignment="Center" Width="80"> + <Label Padding="0" Margin="0"> + <Label.Style> + <Style TargetType="Label"> + <Setter Property="Content" Value="{x:Null}"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Started}" Value="True"> + <Setter Property="Content"> + <Setter.Value> + <TextBlock Text="{Binding RemainingTime,StringFormat=hh\\:mm\\:ss}" Foreground="{StaticResource RedBrush300}" FontFamily="{StaticResource digital-7}" HorizontalAlignment="Center" Margin="10" FontSize="20"></TextBlock> + </Setter.Value> + </Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Completed}" Value="True"> + <Setter Property="Content"> + <Setter.Value> + <materialDesign:PackIcon Margin="30 10 0 0" HorizontalAlignment="Center" Width="24" Height="24" Kind="Check" Foreground="#47FF00" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Label.Style> + </Label> + </Canvas> + </Grid> + </StackPanel> <Rectangle HorizontalAlignment="Right" Stroke="White" Margin="0 35 0 25" ></Rectangle> @@ -408,8 +413,7 @@ </Grid> </DockPanel> - <TextBlock Visibility="{Binding RunningJobStatus.IsFinalizing,Converter={StaticResource BooleanToVisibilityConverter}}" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="-170 0 0 0" Background="{StaticResource DarkGrayBrush}" FontSize="14" Height="30" Foreground="{StaticResource RedBrush100}">Finalizing...</TextBlock> - </Grid> + </Grid> </Border> <ProgressBar IsIndeterminate="True" VerticalAlignment="Bottom" Height="3" Visibility="{Binding IsJobRunning,Converter={StaticResource BooleanToVisibilityConverter}}"></ProgressBar> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/RunningJobView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/RunningJobView.xaml index e7f16146b..0400ee7e6 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/RunningJobView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/RunningJobView.xaml @@ -208,7 +208,7 @@ </Grid> </Grid> - <Grid HorizontalAlignment="Right"> + <Grid HorizontalAlignment="Right" Margin="0 0 0 82"> <ContentControl Content="{Binding}"> <ContentControl.Style> <Style TargetType="ContentControl"> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Tango.MachineStudio.HardwareDesigner_ijdp5tm3_wpftmp.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Tango.MachineStudio.HardwareDesigner_ijdp5tm3_wpftmp.csproj new file mode 100644 index 000000000..0ef643858 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Tango.MachineStudio.HardwareDesigner_ijdp5tm3_wpftmp.csproj @@ -0,0 +1,184 @@ +<?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>{69DB0564-268C-4B3C-B5D6-A3CDC7D14EAE}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.MachineStudio.HardwareDesigner</RootNamespace> + <AssemblyName>Tango.MachineStudio.HardwareDesigner</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\..\Build\Machine Studio\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\Machine Studio\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="Comparison\HardwareCompareResult.cs" /> + <Compile Include="Comparison\HardwareComponentCollectionCompareResult.cs" /> + <Compile Include="Comparison\HardwareComponentCompareResult.cs" /> + <Compile Include="Comparison\HardwareComponentPropertyResult.cs" /> + <Compile Include="Comparison\IHasDifference.cs" /> + <Compile Include="Report\ReportModel.cs" /> + <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\ComparisonWizardViewVM.cs" /> + <Compile Include="Views\ComparisonWizardView.xaml.cs"> + <DependentUpon>ComparisonWizardView.xaml</DependentUpon> + </Compile> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + <Compile Include="HardwareDesignerModule.cs" /> + </ItemGroup> + <ItemGroup> + <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> + <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.CSV\Tango.CSV.csproj"> + <Project>{58e8825f-0c96-449c-b320-1e82b0aa876b}</Project> + <Name>Tango.CSV</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.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.MachineStudio.Common\Tango.MachineStudio.Common.csproj"> + <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project> + <Name>Tango.MachineStudio.Common</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </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.2.0\lib\net45\EntityFramework.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MaterialDesignColors.1.1.2\lib\net45\MaterialDesignColors.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.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.Core.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.CSV.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\Machine Studio\Debug\Tango.MachineStudio.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:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\WindowsBase.dll" /> + </ItemGroup> + <ItemGroup> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.HardwareDesigner\obj\Debug\App.g.cs" /> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.HardwareDesigner\obj\Debug\Views\ComparisonWizardView.g.cs" /> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.HardwareDesigner\obj\Debug\Views\MainView.g.cs" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/ComparisonWizardViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/ComparisonWizardViewVM.cs index 47a40ade4..a58d69a93 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/ComparisonWizardViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/ComparisonWizardViewVM.cs @@ -281,6 +281,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -303,6 +304,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -325,6 +327,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -347,6 +350,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -369,6 +373,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -391,6 +396,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -413,6 +419,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels collection.Components.Add(componentResult); } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.ComponentName).ToSynchronizedObservableCollection(); return collection; } @@ -432,7 +439,6 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels result.Properties.Add(hProp); } - return result; } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/MainViewVM.cs index 40dc82d29..47fe19a05 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/ViewModels/MainViewVM.cs @@ -16,6 +16,9 @@ using Tango.Core.ExtensionMethods; using Tango.MachineStudio.HardwareDesigner.Views; using Microsoft.Win32; using System.IO; +using Tango.BL.ActionLogs; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.DTO; namespace Tango.MachineStudio.HardwareDesigner.ViewModels { @@ -24,6 +27,9 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels private INotificationProvider _notification; private bool _isNew; private ObservablesContext _db; + private IActionLogManager _actionLogManager; + private IAuthenticationProvider _authentication; + private HardwareVersionDTO _hwBeforeSave; private HardwareVersion _selectedVersion; public HardwareVersion SelectedVersion @@ -45,6 +51,8 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels get { return _selectedHardwareObject; } set { + _selectedHardwareObject = null; + RaisePropertyChangedAuto(); _selectedHardwareObject = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(SelectedHardwareObjectTypeName)); @@ -113,9 +121,11 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels public RelayCommand ImportHardwareVersionCommand { get; set; } - public MainViewVM(INotificationProvider notification) + public MainViewVM(INotificationProvider notification, IActionLogManager actionLogManager, IAuthenticationProvider authentication) { _notification = notification; + _actionLogManager = actionLogManager; + _authentication = authentication; CurrentVersion = new HardwareVersion(); @@ -183,6 +193,8 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels _db.HardwareVersions.Add(hv); await _db.SaveChangesAsync(); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.HardwareVersionImported, _authentication.CurrentUser, CurrentVersion.Name, CurrentVersion, "New hardware version imported using Machine Studio."); + RefreshVersions(); InvokeUI(() => @@ -221,7 +233,7 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels private void CopyParameters(object obj) { - obj.MapPrimitivesTo(SelectedHardwareObject, + obj.MapPropertiesTo(SelectedHardwareObject, MappingFlags.ValueTypesOnly, (prop) => !prop.PropertyType.IsEnum && @@ -236,20 +248,20 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels _db = ObservablesContext.CreateDefault(); - CurrentVersion.HardwareMotors = _db.HardwareMotorTypes.ToList().Select(x => new HardwareMotor() { HardwareMotorType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwareDancers = _db.HardwareDancerTypes.ToList().Select(x => new HardwareDancer() { HardwareDancerType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwarePidControls = _db.HardwarePidControlTypes.ToList().Select(x => new HardwarePidControl() { HardwarePidControlType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwareWinders = _db.HardwareWinderTypes.ToList().Select(x => new HardwareWinder() { HardwareWinderType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwareSpeedSensors = _db.HardwareSpeedSensorTypes.ToList().Select(x => new HardwareSpeedSensor() { HardwareSpeedSensorType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwareBlowers = _db.HardwareBlowerTypes.ToList().Select(x => new HardwareBlower() { HardwareBlowerType = x }).ToSynchronizedObservableCollection(); - CurrentVersion.HardwareBreakSensors = _db.HardwareBreakSensorTypes.ToList().Select(x => new HardwareBreakSensor() { HardwareBreakSensorType = x }).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareMotors = _db.HardwareMotorTypes.ToList().Select(x => new HardwareMotor() { HardwareMotorType = x }).OrderByAlphaNumeric(x => x.HardwareMotorType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareDancers = _db.HardwareDancerTypes.ToList().Select(x => new HardwareDancer() { HardwareDancerType = x }).OrderByAlphaNumeric(x => x.HardwareDancerType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwarePidControls = _db.HardwarePidControlTypes.ToList().Select(x => new HardwarePidControl() { HardwarePidControlType = x }).OrderByAlphaNumeric(x => x.HardwarePidControlType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareWinders = _db.HardwareWinderTypes.ToList().Select(x => new HardwareWinder() { HardwareWinderType = x }).OrderByAlphaNumeric(x => x.HardwareWinderType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareSpeedSensors = _db.HardwareSpeedSensorTypes.ToList().Select(x => new HardwareSpeedSensor() { HardwareSpeedSensorType = x }).OrderByAlphaNumeric(x => x.HardwareSpeedSensorType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareBlowers = _db.HardwareBlowerTypes.ToList().Select(x => new HardwareBlower() { HardwareBlowerType = x }).OrderByAlphaNumeric(x => x.HardwareBlowerType.Description).ToSynchronizedObservableCollection(); + CurrentVersion.HardwareBreakSensors = _db.HardwareBreakSensorTypes.ToList().Select(x => new HardwareBreakSensor() { HardwareBreakSensorType = x }).OrderByAlphaNumeric(x => x.HardwareBreakSensorType.Description).ToSynchronizedObservableCollection(); } private void RefreshVersions() { using (var db = ObservablesContext.CreateDefault()) { - _hardwareVersions = db.HardwareVersions.ToObservableCollection(); + _hardwareVersions = db.HardwareVersions.OrderByDescending(x => x.Version).ToObservableCollection(); InvokeUI(() => { RaisePropertyChanged(nameof(HardwareVersions)); @@ -337,6 +349,8 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels }); CurrentVersion.HardwareBreakSensors = CurrentVersion.HardwareBreakSensors.OrderBy(x => x.HardwareBreakSensorType.Code).ToSynchronizedObservableCollection(); + + _hwBeforeSave = HardwareVersionDTO.FromObservable(CurrentVersion); }); } @@ -346,24 +360,34 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels { using (_notification.PushTaskItem("Loading hardware version...")) { - IsFree = false; - - await Task.Factory.StartNew(() => + try { - _isNew = false; - var selectedVersion = SelectedVersion; - RefreshVersions(); - var version = _hardwareVersions.SingleOrDefault(X => X.Guid == selectedVersion.Guid); - CreateVersionView(SelectedVersion); + IsFree = false; - InvokeUI(() => + await Task.Factory.StartNew(() => { - _selectedVersion = version; - RaisePropertyChanged(nameof(SelectedVersion)); - }); - }); + _isNew = false; + var selectedVersion = SelectedVersion; + RefreshVersions(); + var version = _hardwareVersions.SingleOrDefault(X => X.Guid == selectedVersion.Guid); + CreateVersionView(SelectedVersion); - IsFree = true; + InvokeUI(() => + { + _selectedVersion = version; + RaisePropertyChanged(nameof(SelectedVersion)); + }); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading hardware version."); + _notification.ShowError($"Error loading the selected hardware version.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } } } @@ -391,6 +415,8 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels _db.HardwareVersions.Add(CurrentVersion); _db.SaveChanges(); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.HardwareVersionCreated, _authentication.CurrentUser, CurrentVersion.Name, CurrentVersion, "New hardware version created using Machine Studio."); + RefreshVersions(); InvokeUI(() => @@ -418,7 +444,13 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels await Task.Factory.StartNew(() => { + CurrentVersion.LastUpdated = DateTime.UtcNow; _db.SaveChanges(); + + var dtoAfter = HardwareVersionDTO.FromObservable(CurrentVersion); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.HardwareVersionSaved, _authentication.CurrentUser, _hwBeforeSave.Name, _hwBeforeSave, dtoAfter, "Hardware Version saved using Machine Studio."); + _hwBeforeSave = dtoAfter; + RefreshVersions(); InvokeUI(() => @@ -460,6 +492,9 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels cloned.Version = HardwareVersions.Max(x => x.Version) + 1; _db.HardwareVersions.Add(cloned); _db.SaveChanges(); + + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.HardwareVersionCreated, _authentication.CurrentUser, cloned.Name, cloned, "New hardware version cloned using Machine Studio."); + RefreshVersions(); InvokeUI(() => @@ -495,6 +530,8 @@ namespace Tango.MachineStudio.HardwareDesigner.ViewModels await CurrentVersion.DeleteCascadeAsync(_db); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.HardwareVersionDeleted, _authentication.CurrentUser, CurrentVersion.Name, _hwBeforeSave, "Hardware version deleted using Machine Studio.", true); + await Task.Factory.StartNew(() => { SelectedVersion = null; diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Views/MainView.xaml index 1c00397aa..9ee2ffee7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.HardwareDesigner/Views/MainView.xaml @@ -9,6 +9,7 @@ xmlns:editors="clr-namespace:Tango.SharedUI.Editors;assembly=Tango.SharedUI" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:local="clr-namespace:Tango.MachineStudio.HardwareDesigner.Views" xmlns:vm="clr-namespace:Tango.MachineStudio.HardwareDesigner.ViewModels" xmlns:observables="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" @@ -57,14 +58,14 @@ <TextBlock FontSize="30" FontStyle="Italic" VerticalAlignment="Center" Margin="50 10 10 0" Foreground="Silver" FontWeight="Bold">HARDWARE DESIGNER</TextBlock> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10 10 0 0"> <materialDesign:PackIcon Kind="Pencil" Width="32" Height="32" Foreground="Silver" /> - <ComboBox IsEnabled="{Binding IsFree}" ItemsSource="{Binding HardwareVersions}" SelectedItem="{Binding SelectedVersion}" Width="300" FontSize="16" FontWeight="Bold" Margin="5 0 0 0" materialDesign:HintAssist.Hint="Hardware Version"> + <controls:SearchComboBox IsEnabled="{Binding IsFree}" ItemsSource="{Binding HardwareVersions}" SelectedItem="{Binding SelectedVersion}" Width="300" SearchProperty="FullName" FontSize="16" FontWeight="Bold" Margin="5 0 0 0" materialDesign:HintAssist.Hint="Hardware Version"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock><Run Text="{Binding Name}"></Run> <Run></Run> <Run Foreground="{StaticResource MainWindow.Foreground}" FontSize="14">v</Run><Run Foreground="{StaticResource MainWindow.Foreground}" FontSize="14" Text="{Binding Version}"></Run></TextBlock> </DataTemplate> </ComboBox.ItemTemplate> - </ComboBox> - + </controls:SearchComboBox> + </StackPanel> <Button Margin="100 10 0 0" Cursor="Hand" Height="40" FontSize="12" ToolTip="Open Comparison Wizard" Command="{Binding OpenComparisonWizardCommand}"> <StackPanel Orientation="Horizontal"> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/ViewModels/ApplicationLogsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/ViewModels/ApplicationLogsViewVM.cs index 91cc677e0..a384c133d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/ViewModels/ApplicationLogsViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/ViewModels/ApplicationLogsViewVM.cs @@ -59,14 +59,14 @@ namespace Tango.MachineStudio.Logging.ViewModels } } - private bool _displayDebug; + private bool _processDebugLogs; /// <summary> /// Gets or sets a value indicating whether display debug logs. /// </summary> - public bool DisplayDebug + public bool ProcessDebugLogs { - get { return _displayDebug; } - set { _displayDebug = value; RaisePropertyChangedAuto(); } + get { return _processDebugLogs; } + set { _processDebugLogs = value; RaisePropertyChangedAuto(); OnProcessDebugLogsChanged(); } } private LogItemBase _selectedLog; @@ -184,6 +184,18 @@ namespace Tango.MachineStudio.Logging.ViewModels _is_debug = LogManager.Categories.Contains(LogCategory.Debug); } + private void OnProcessDebugLogsChanged() + { + if (ProcessDebugLogs) + { + LogManager.Categories.Add(LogCategory.Debug); + } + else + { + LogManager.Categories.RemoveAll(x => x == LogCategory.Debug); + } + } + private void ApplyLogsFilter() { if ((_realTimePaused && _isRealTime) || !_isRealTime) @@ -204,8 +216,6 @@ namespace Tango.MachineStudio.Logging.ViewModels private void LogManager_NewLog(object sender, LogItemBase log) { - if (log.Category == LogCategory.Debug && !DisplayDebug) return; - if (!RealTimePaused) { InvokeUI(() => diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/ApplicationLogsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/ApplicationLogsView.xaml index 4c291d0df..486c0751d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/ApplicationLogsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/ApplicationLogsView.xaml @@ -114,7 +114,7 @@ </StackPanel> </Border> - <CheckBox VerticalAlignment="Center" Margin="20 0 0 0" IsChecked="{Binding DisplayDebug}" IsEnabled="{Binding IsRealTime}" ToolTip="Hide/Display debug logs (applies only when debug logs are enabled in the settings file)">Process Debug Logs</CheckBox> + <CheckBox VerticalAlignment="Center" Margin="20 0 0 0" IsChecked="{Binding ProcessDebugLogs}" IsEnabled="{Binding IsRealTime}" ToolTip="Allow incoming real-time debug logs">Enable Debug Logs</CheckBox> </StackPanel> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 30 0"> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/EmbeddedLogDetailsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/EmbeddedLogDetailsView.xaml index e79fd0ad2..e87609b88 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/EmbeddedLogDetailsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/EmbeddedLogDetailsView.xaml @@ -10,7 +10,7 @@ xmlns:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" xmlns:local="clr-namespace:Tango.MachineStudio.Logging.Views" mc:Ignorable="d" - Height="500" Width="800" Background="{StaticResource MainWindow.Background}" d:DataContext="{d:DesignInstance Type=vm:LogDetailsViewVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource MainWindow.Foreground}"> + Height="500" Width="800" Background="{StaticResource Dialog.Background}" d:DataContext="{d:DesignInstance Type=vm:LogDetailsViewVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource MainWindow.Foreground}"> <UserControl.Resources> <converters:DateTimeUTCToStringConverter x:Key="DateTimeUTCToStringConverter" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/TimelineView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/TimelineView.xaml index 9eb099a9e..f720a0237 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/TimelineView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Logging/Views/TimelineView.xaml @@ -22,24 +22,19 @@ <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <localConverters:StringToFirstLineConverter x:Key="StringToFirstLineConverter" /> - <LinearGradientBrush x:Key="infoBrush" StartPoint="0.5,0" EndPoint="0.5,1"> - <GradientStop Color="White"/> - <GradientStop Color="#FFBFBFBF" Offset="1"/> - </LinearGradientBrush> - <LinearGradientBrush x:Key="warningBrush" StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="#FFFF8C57"/> - <GradientStop Color="White" Offset="1"/> + <GradientStop Color="{StaticResource whiteColor}" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="errorBrush" StartPoint="0.5,0" EndPoint="0.5,1"> - <GradientStop Color="{StaticResource RedBrush100}"/> + <GradientStop Color="#FFFF5151"/> <GradientStop Color="#FFD9D9" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="criticalBrush" StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="Red"/> - <GradientStop Color="White" Offset="1"/> + <GradientStop Color="{StaticResource whiteColor}" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="hoverBrush" StartPoint="0.5,0" EndPoint="0.5,1"> @@ -69,7 +64,7 @@ </Grid> <ScrollViewer x:Name="scroll_channels" Grid.Column="0" Grid.Row="1" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"> - <ItemsControl ItemsSource="{Binding TimelineEventGroups}" Margin="0 0 0 0" Background="#FCFCFC" VerticalAlignment="Top"> + <ItemsControl ItemsSource="{Binding TimelineEventGroups}" Margin="0 0 0 0" Background="{StaticResource MainWindow.Background}" VerticalAlignment="Top"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel /> @@ -148,7 +143,7 @@ </Border.Style> <StackPanel Orientation="Horizontal"> <TextBlock FontWeight="SemiBold" Text="{Binding EventType.Name}" Height="14" FontSize="11"></TextBlock> - <TextBlock Margin="10 0 0 0" Text="{Binding Description,Converter={StaticResource StringToFirstLineConverter}}" Height="14" FontSize="11"></TextBlock> + <TextBlock Margin="10 0 0 0" Text="{Binding Description,Converter={StaticResource StringToFirstLineConverter}}" Height="14" FontSize="11" Foreground="{StaticResource Dialog.Foreground}"></TextBlock> </StackPanel> </Border> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Tango.MachineStudio.MachineDesigner.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Tango.MachineStudio.MachineDesigner.csproj index d80060831..69cc75461 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Tango.MachineStudio.MachineDesigner.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Tango.MachineStudio.MachineDesigner.csproj @@ -89,14 +89,20 @@ <Compile Include="ViewModels\ColorCalibrationViewVM.cs" /> <Compile Include="ViewModels\HardwareConfigurationViewVM.cs" /> <Compile Include="ViewModels\MachineCreationDialogVM.cs" /> + <Compile Include="ViewModels\MachineUpdateDetailsDialogVM.cs" /> + <Compile Include="ViewModels\MachineUpdatesViewVM.cs" /> <Compile Include="ViewModels\MachineVersionDialogVM.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="ViewModels\TupViewVM.cs" /> <Compile Include="Views\ColorCalibrationView.xaml.cs"> <DependentUpon>ColorCalibrationView.xaml</DependentUpon> </Compile> <Compile Include="Views\HardwareConfigurationView.xaml.cs"> <DependentUpon>HardwareConfigurationView.xaml</DependentUpon> </Compile> + <Compile Include="Views\MachineUpdateDetailsDialog.xaml.cs"> + <DependentUpon>MachineUpdateDetailsDialog.xaml</DependentUpon> + </Compile> <Compile Include="Views\MachineCreationDialog.xaml.cs"> <DependentUpon>MachineCreationDialog.xaml</DependentUpon> </Compile> @@ -122,6 +128,12 @@ <Compile Include="Views\MainView.xaml.cs"> <DependentUpon>MainView.xaml</DependentUpon> </Compile> + <Compile Include="Views\MachineUpdatesView.xaml.cs"> + <DependentUpon>MachineUpdatesView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\TupView.xaml.cs"> + <DependentUpon>TupView.xaml</DependentUpon> + </Compile> <Compile Include="Views\SpoolsView.xaml.cs"> <DependentUpon>SpoolsView.xaml</DependentUpon> </Compile> @@ -137,6 +149,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\MachineUpdateDetailsDialog.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Views\MachineCreationDialog.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -169,6 +185,14 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\MachineUpdatesView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Views\TupView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Views\SpoolsView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -308,7 +332,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/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/ColorCalibrationViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/ColorCalibrationViewVM.cs index b75fe7e03..d37fe1aaa 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/ColorCalibrationViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/ColorCalibrationViewVM.cs @@ -180,6 +180,16 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels public void Save() { + //Remove cats with deleted RMLS. (Can only happen when creating new machine from prototype) + foreach (var cat in Machine.Cats.ToList()) + { + if (!Rmls.Any(x => x.Guid == cat.RmlGuid)) + { + Machine.Cats.Remove(cat); + _dbContext.Cats.Remove(cat); + } + } + foreach (var calDataVM in ColorConversionViewVM.LiquidsCalibrationData) { var cat = calDataVM.IdsPack.LiquidType.Cats.FirstOrDefault(x => x.Machine == Machine && x.Rml == SelectedRML); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/HardwareConfigurationViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/HardwareConfigurationViewVM.cs index f7ae88f68..e29ba3b6f 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/HardwareConfigurationViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/HardwareConfigurationViewVM.cs @@ -92,16 +92,19 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels { HardwareVersion hardwareVersion = configuration.HardwareVersion; - _hwConfig = configuration.GetHardwareConfiguration(); + if (hardwareVersion != null) + { + _hwConfig = configuration.GetHardwareConfiguration(); - Collections.Clear(); - Collections.Add(CreateMotorsCollection(hardwareVersion)); - Collections.Add(CreateDancerCollection(hardwareVersion)); - Collections.Add(CreatePidCollection(hardwareVersion)); - Collections.Add(CreateWindersCollection(hardwareVersion)); - Collections.Add(CreateSpeedSensorsCollection(hardwareVersion)); - Collections.Add(CreateBlowersCollection(hardwareVersion)); - Collections.Add(CreateBreakSensorCollection(hardwareVersion)); + Collections.Clear(); + Collections.Add(CreateMotorsCollection(hardwareVersion)); + Collections.Add(CreateDancerCollection(hardwareVersion)); + Collections.Add(CreatePidCollection(hardwareVersion)); + Collections.Add(CreateWindersCollection(hardwareVersion)); + Collections.Add(CreateSpeedSensorsCollection(hardwareVersion)); + Collections.Add(CreateBlowersCollection(hardwareVersion)); + Collections.Add(CreateBreakSensorCollection(hardwareVersion)); + } } private HardwareCollection CreateMotorsCollection(HardwareVersion hardwareVersion) @@ -124,6 +127,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreateDancerCollection(HardwareVersion hardwareVersion) @@ -146,6 +150,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreatePidCollection(HardwareVersion hardwareVersion) @@ -168,6 +173,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreateWindersCollection(HardwareVersion hardwareVersion) @@ -190,6 +196,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreateSpeedSensorsCollection(HardwareVersion hardwareVersion) @@ -212,6 +219,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreateBlowersCollection(HardwareVersion hardwareVersion) @@ -234,6 +242,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components= collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareCollection CreateBreakSensorCollection(HardwareVersion hardwareVersion) @@ -256,6 +265,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels collection.Components.Add(componentResult); } } + collection.Components = collection.Components.OrderByAlphaNumeric(x => x.Description).ToSynchronizedObservableCollection(); return collection; } private HardwareComponent CreateComponent(String name, String description, List<PropertyInfo> properties, Object component) @@ -265,7 +275,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels Description = description, ComponentName = name }; - + foreach (var prop in properties) { var hProp = new HardwareParameter(); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineCreationDialogVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineCreationDialogVM.cs index 0f6ab3314..4584d3508 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineCreationDialogVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineCreationDialogVM.cs @@ -13,5 +13,50 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels public List<MachineVersion> MachineVersions { get; set; } public MachineVersion SelectedMachineVersion { get; set; } + + private bool _isNewMachine; + public bool IsNewMachine + { + get { return _isNewMachine; } + set { _isNewMachine = value; RaisePropertyChangedAuto(); } + } + + private String _serialNumber; + public String SerialNumber + { + get { return _serialNumber; } + set { _serialNumber = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _name; + public String Name + { + get { return _name; } + set { _name = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private bool _generateDispensers; + public bool GenerateDispensers + { + get { return _generateDispensers; } + set { _generateDispensers = value; RaisePropertyChangedAuto(); } + } + + private double _dispenserFactor; + public double DispenserFactor + { + get { return _dispenserFactor; } + set { _dispenserFactor = value; RaisePropertyChangedAuto(); } + } + + public MachineCreationDialogVM() : base() + { + DispenserFactor = 2.34; + } + + protected override bool CanOK() + { + return base.CanOK() && !String.IsNullOrWhiteSpace(SerialNumber) && !String.IsNullOrWhiteSpace(Name); + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdateDetailsDialogVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdateDetailsDialogVM.cs new file mode 100644 index 000000000..49d410cdf --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdateDetailsDialogVM.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.SharedUI; + +namespace Tango.MachineStudio.MachineDesigner.ViewModels +{ + public class MachineUpdateDetailsDialogVM : DialogViewVM + { + private TangoUpdate _update; + public TangoUpdate Update + { + get { return _update; } + set { _update = value; RaisePropertyChangedAuto(); } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdatesViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdatesViewVM.cs new file mode 100644 index 000000000..6004dbe6e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MachineUpdatesViewVM.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.BL; +using Tango.BL.Builders; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.MachineDesigner.Views; +using Tango.SharedUI; + +namespace Tango.MachineStudio.MachineDesigner.ViewModels +{ + public class MachineUpdatesViewVM : ViewModel + { + private INotificationProvider _notification; + private ObservablesContext _context; + private const int MAX_UPDATE_ITEMS = 200; + + #region Properties + + private Machine _machine; + public Machine Machine + { + get { return _machine; } + set { _machine = value; RaisePropertyChangedAuto(); } + } + + private List<TangoUpdate> _updates; + public List<TangoUpdate> Updates + { + get { return _updates; } + set { _updates = value; RaisePropertyChangedAuto(); } + } + + private ICollectionView _updatesView; + public ICollectionView UpdatesView + { + get { return _updatesView; } + set { _updatesView = value; RaisePropertyChangedAuto(); } + } + + + private TangoUpdate _selectedUpdate; + public TangoUpdate SelectedUpdate + { + get { return _selectedUpdate; } + set { _selectedUpdate = value; RaisePropertyChangedAuto(); OnSelectedUpdateChanged(); } + } + + private bool _displayMachineSetups; + public bool DisplayMachineSetups + { + get { return _displayMachineSetups; } + set { _displayMachineSetups = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _displayApplicationUpdates; + public bool DisplayApplicationUpdates + { + get { return _displayApplicationUpdates; } + set { _displayApplicationUpdates = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _displayDatabaseUpdates; + public bool DisplayDatabaseUpdates + { + get { return _displayDatabaseUpdates; } + set { _displayDatabaseUpdates = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _displaySynchronizations; + public bool DisplaySynchronizations + { + get { return _displaySynchronizations; } + set { _displaySynchronizations = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _displayOfflineUpdates; + public bool DisplayOfflineUpdates + { + get { return _displayOfflineUpdates; } + set { _displayOfflineUpdates = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _displayFirmwareUpgrades; + public bool DisplayFirmwareUpgrades + { + get { return _displayFirmwareUpgrades; } + set { _displayFirmwareUpgrades = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + #endregion + + #region Commands + + public RelayCommand RefreshCommand { get; set; } + + #endregion + + #region Constructors + + public MachineUpdatesViewVM() + { + DisplayApplicationUpdates = true; + DisplayMachineSetups = true; + DisplayDatabaseUpdates = true; + DisplaySynchronizations = true; + DisplayOfflineUpdates = true; + DisplayFirmwareUpgrades = true; + + RefreshCommand = new RelayCommand(Refresh, () => IsFree); + } + + public MachineUpdatesViewVM(INotificationProvider notificationProvider) : this() + { + _notification = notificationProvider; + } + + #endregion + + #region Public Methods + + public async Task Init(Machine machine, ObservablesContext context) + { + try + { + _context = context; + Machine = machine; + Updates = (await new TangoUpdatesCollectionBuilder(context).Set(x => x.MachineGuid == machine.Guid).Query(x => x.OrderByDescending(y => y.StartDate).Take(MAX_UPDATE_ITEMS)).BuildAsync()).ToList(); + UpdatesView = CollectionViewSource.GetDefaultView(Updates); + UpdatesView.Filter = UpdatesFilter; + OnFilterChanged(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading machine updates."); + _notification.ShowError($"An error occurred while loading the history of machine updates.\n{ex.FlattenMessage()}"); + } + } + + #endregion + + #region Private Methods + + private async void Refresh() + { + IsFree = false; + using (_notification.PushTaskItem("Refreshing machine updates...")) + { + await Init(Machine, _context); + } + IsFree = true; + } + + private void OnFilterChanged() + { + if (UpdatesView != null) + { + UpdatesView.Refresh(); + } + } + + private bool UpdatesFilter(object obj) + { + TangoUpdate update = obj as TangoUpdate; + if (update != null) + { + if (!DisplayMachineSetups && update.IsSetup) return false; + if (!DisplayApplicationUpdates && update.IsUpdate) return false; + if (!DisplayDatabaseUpdates && update.IsDataBase) return false; + if (!DisplaySynchronizations && update.IsSynchronization) return false; + if (!DisplayOfflineUpdates && update.IsOfflineUpdate) return false; + if (!DisplayFirmwareUpgrades && update.IsOfflineFirmwareUpgrade) return false; + return true; + } + else + { + return false; + } + } + + private void OnSelectedUpdateChanged() + { + if (SelectedUpdate != null && SelectedUpdate.ApplicationVersion != "Fake") + { + _notification.ShowModalDialog<MachineUpdateDetailsDialogVM, MachineUpdateDetailsDialog>(new MachineUpdateDetailsDialogVM() { Update = SelectedUpdate }, (vm) => { }, () => { }); + SelectedUpdate = new TangoUpdate() { ApplicationVersion = "Fake"}; + } + } + + #endregion + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MainViewVM.cs index 5f2dcd00d..0f439c83d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/MainViewVM.cs @@ -25,17 +25,32 @@ using Tango.Core.Threading; using Tango.MachineStudio.RML.ViewModels; using Tango.Settings; using Tango.MachineStudio.RML.Models; +using Tango.BL.ActionLogs; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.DTO; +using Tango.Core.Cryptography; namespace Tango.MachineStudio.MachineDesigner.ViewModels { public class MainViewVM : StudioViewModel<IMainView> { private INotificationProvider _notification; + private IActionLogManager _actionLogManager; + private IAuthenticationProvider _authentication; private ActionTimer _machines_action_timer; private ActionTimer _dispensers_action_timer; + private MachineDTO _machineBeforeSave; + private List<Site> _all_sites; #region Properties + private bool _isNewMachine; + public bool IsNewMachine + { + get { return _isNewMachine; } + set { _isNewMachine = value; RaisePropertyChangedAuto(); } + } + private ObservablesStaticCollections _machinesAdapter; public ObservablesStaticCollections MachinesAdapter { @@ -115,6 +130,21 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels set { _selectedSpool = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } + private Site _selectedSite; + public Site SelectedSite + { + get { return _selectedSite; } + set { _selectedSite = value; RaisePropertyChangedAuto(); } + } + + private List<Site> _sites; + public List<Site> Sites + { + get { return _sites; } + set { _sites = value; RaisePropertyChangedAuto(); } + } + + private ColorCalibrationViewVM _colorCalibrationViewVM; public ColorCalibrationViewVM ColorCalibrationViewVM { @@ -123,7 +153,6 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels } private HardwareConfigurationViewVM _hardwareConfigurationViewVM; - public HardwareConfigurationViewVM HardwareConfigurationViewVM { get { return _hardwareConfigurationViewVM; } @@ -134,6 +163,19 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels } } + private MachineUpdatesViewVM _machineUpdatesViewVM; + public MachineUpdatesViewVM MachineUpdatesViewVM + { + get { return _machineUpdatesViewVM; } + set { _machineUpdatesViewVM = value; RaisePropertyChangedAuto(); } + } + + private TupViewVM _tupViewVM; + public TupViewVM TupViewVM + { + get { return _tupViewVM; } + set { _tupViewVM = value; RaisePropertyChangedAuto(); } + } #endregion @@ -188,6 +230,17 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels /// Gets or sets the clone machine command. /// </summary> public RelayCommand CloneMachineCommand { get; set; } + + /// <summary> + /// Gets or sets the reset device registration command. + /// </summary> + public RelayCommand ResetDeviceRegistrationCommand { get; set; } + + /// <summary> + /// Gets or sets the make prototype command. + /// </summary> + public RelayCommand MakePrototypeCommand { get; set; } + #endregion #region Constructors @@ -200,10 +253,12 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels /// <summary> /// Initializes a new instance of the <see cref="MainViewVM"/> class. /// </summary> - public MainViewVM(INotificationProvider notification) + public MainViewVM(INotificationProvider notification, IAuthenticationProvider authentication, IActionLogManager actionLogManager) { MachinesAdapter = new ObservablesStaticCollections(ObservablesContext.CreateDefault()); _notification = notification; + _authentication = authentication; + _actionLogManager = actionLogManager; _machines_action_timer = new ActionTimer(TimeSpan.FromMilliseconds(200)); _dispensers_action_timer = new ActionTimer(TimeSpan.FromMilliseconds(200)); @@ -218,7 +273,13 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels AddSpoolCommand = new RelayCommand(AddNewSpool); RemoveSpoolCommand = new RelayCommand(RemoveSpool, () => SelectedSpool != null); CloneMachineCommand = new RelayCommand(CloneMachine, () => SelectedMachine != null); + ResetDeviceRegistrationCommand = new RelayCommand(ResetDeviceRegistration); + MakePrototypeCommand = new RelayCommand(MakePrototype); + + MachineUpdatesViewVM = new MachineUpdatesViewVM(_notification); + TupViewVM = new TupViewVM(_notification); } + #endregion #region Application Ready @@ -239,7 +300,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels { Task.Factory.StartNew(() => { - ActiveMachineAdapter.Dispensers = ActiveMachineAdapter.Context.Dispensers.Where(x => x.SerialNumber.ToLower().StartsWith(DispensersFilter.ToLower())).ToSynchronizedObservableCollection(); + ActiveMachineAdapter.Dispensers = ActiveMachineAdapter.Context.Dispensers.Where(x => x.SerialNumber.ToLower().StartsWith(DispensersFilter.ToLower())).OrderBy(x => x.SerialNumber).ToSynchronizedObservableCollection(); }); }); } @@ -388,8 +449,10 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels InvalidateRelayCommands(); } - private async void LoadSelectedMachine(bool newMachine = false, bool clone = false, MachineVersion selectedVersion = null) + private async void LoadSelectedMachine(bool newMachine = false, bool clone = false, MachineCreationDialogVM machineCreationDialogVM = null) { + IsNewMachine = false; + using (_notification.PushTaskItem("Loading machine details...")) { try @@ -413,7 +476,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels ActiveMachineAdapter.ApplicationOsVersions = (await ActiveMachineAdapter.Context.ApplicationOsVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.EmbeddedFirmwareVersions = (await ActiveMachineAdapter.Context.EmbeddedFirmwareVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.DispenserTypes = (await ActiveMachineAdapter.Context.DispenserTypes.ToListAsync()).ToObservableCollection(); - ActiveMachineAdapter.LiquidTypes = (await ActiveMachineAdapter.Context.LiquidTypes.ToListAsync()).ToObservableCollection(); + ActiveMachineAdapter.LiquidTypes = (await ActiveMachineAdapter.Context.LiquidTypes.ToListAsync()).OrderBy(x => x.PreferredIndex).ToObservableCollection(); ActiveMachineAdapter.MidTankTypes = (await ActiveMachineAdapter.Context.MidTankTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.CartridgeTypes = (await ActiveMachineAdapter.Context.CartridgeTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.IdsPackFormulas = (await ActiveMachineAdapter.Context.IdsPackFormulas.ToListAsync()).ToObservableCollection(); @@ -421,32 +484,144 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels ActiveMachineAdapter.MachineVersions = (await ActiveMachineAdapter.Context.MachineVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.Organizations = (await ActiveMachineAdapter.Context.Organizations.ToListAsync()).ToObservableCollection(); + bool initHwConfig = true; + + Configuration machineConfigBeforeClone = null; + if (!newMachine) { ActiveMachine = (await new MachineBuilder(ActiveMachineAdapter.Context).Set(SelectedMachine.Guid).WithOrganization().WithConfiguration().WithSpools().BuildAsync()); + _machineBeforeSave = MachineDTO.FromObservable(ActiveMachine); + if (clone) { + machineConfigBeforeClone = ActiveMachine.Configuration; + + IsNewMachine = true; ActiveMachine = ActiveMachine.Clone(); - ActiveMachine.Name = ""; - ActiveMachine.SerialNumber = ""; + ActiveMachine.Name = machineCreationDialogVM.Name; + ActiveMachine.SerialNumber = machineCreationDialogVM.SerialNumber; + ActiveMachine.IsDeviceRegistered = false; + ActiveMachine.DeviceId = null; + ActiveMachine.DeviceName = null; + ActiveMachine.ActivationKey = null; ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } } else { - if (selectedVersion == null) + IsNewMachine = true; + + if (machineCreationDialogVM.SelectedMachineVersion == null) { ActiveMachine = new Machine(); ActiveMachine.Configuration = new Configuration(); + ActiveMachine.SerialNumber = machineCreationDialogVM.SerialNumber; + ActiveMachine.Name = machineCreationDialogVM.Name; ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } else { - ActiveMachine = selectedVersion.CreatePrototypeMachine(ActiveMachineAdapter.Context); - ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); + try + { + initHwConfig = false; + ActiveMachine = await machineCreationDialogVM.SelectedMachineVersion.CreatePrototypeMachine(ActiveMachineAdapter.Context); + ActiveMachine.SerialNumber = machineCreationDialogVM.SerialNumber; + ActiveMachine.Name = machineCreationDialogVM.Name; + ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); + + HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); + var version = await new HardwareVersionBuilder(ActiveMachineAdapter.Context).Set(ActiveMachine.Configuration.HardwareVersionGuid).WithHardwareComponents().BuildAsync(); + HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); + } + catch (Exception ex) + { + _notification.ShowError($"Invalid machine version prototype.\n{ex.FlattenMessage()}"); + View.NavigateTo(MachineDesignerNavigationView.MachinesView); + return; + } + } + } + + if ((newMachine || clone) && machineCreationDialogVM.GenerateDispensers) + { + for (int i = 0; i < 8; i++) + { + var serial = machineCreationDialogVM.SerialNumber + "-" + (i + 1); + + var existingDispenser = await ActiveMachineAdapter.Context.Dispensers.Include(x => x.IdsPacks).SingleOrDefaultAsync(x => x.SerialNumber == serial); + + if (existingDispenser != null) + { + if (existingDispenser.IsInstalled) + { + _notification.ShowError($"Dispenser '{serial}' already exists. Cannot create machine."); + return; + } + else + { + if (!_notification.ShowErrorQuestion($"Dispenser '{serial}' already exists and is not installed. Do you wish to assign the existing dispenser to this machine?")) + { + return; + } + } + } + + Dispenser dispenser = new Dispenser(); + + if (existingDispenser == null) + { + dispenser.SerialNumber = serial; + + if (newMachine) + { + dispenser.NlPerPulse = machineCreationDialogVM.DispenserFactor; + dispenser.DispenserTypeGuid = ActiveMachineAdapter.DispenserTypes.First().Guid; + } + else + { + var packBefore = machineConfigBeforeClone.NoneEmptyIdsPacks.SingleOrDefault(x => x.PackIndex == i); + + if (packBefore != null) + { + dispenser.NlPerPulse = packBefore.Dispenser.NlPerPulse; + dispenser.DispenserTypeGuid = packBefore.Dispenser.DispenserType.Guid; + } + else + { + continue; + } + } + + dispenser.ProductionDate = DateTime.UtcNow; + + ActiveMachineAdapter.Context.Dispensers.Add(dispenser); + } + else + { + dispenser = existingDispenser; + } + + var idsPack = ActiveMachine.Configuration.NoneEmptyIdsPacks.SingleOrDefault(x => x.PackIndex == i); + + if (idsPack != null) + { + idsPack.Dispenser = dispenser; + idsPack.DispenserGuid = dispenser.Guid; + } } } + ActiveMachine.OrganizationChanged -= ActiveMachine_OrganizationChanged; + ActiveMachine.OrganizationChanged += ActiveMachine_OrganizationChanged; + + _all_sites = await ActiveMachineAdapter.Context.Sites.ToListAsync(); + + var sites = ActiveMachine.Organization != null ? _all_sites.Where(x => x.OrganizationGuid == ActiveMachine.OrganizationGuid).ToList() : new List<Site>(); + sites.Insert(0, new Site() { Name = "NONE", ID = -1 }); + Sites = sites; + + SelectedSite = Sites.SingleOrDefault(x => x.Guid == ActiveMachine.SiteGuid); ColorCalibrationViewVM = new ColorCalibrationViewVM(_notification, ActiveMachine, _activeMachineAdapter.Context) { @@ -455,11 +630,31 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels SelectedRML = ActiveMachineAdapter.Rmls.FirstOrDefault(), }; - HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); - HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); + if (initHwConfig) + { + HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); + HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); + } + + if (!IsNewMachine) + { + await MachineUpdatesViewVM.Init(ActiveMachine, ActiveMachineAdapter.Context); + TupViewVM.Init(ActiveMachine); + } ActiveMachine.Configuration.HardwareVersionChanged += Configuration_HardwareVersionChanged; + while (ActiveMachine.ActivationKey == null) //Generate a random password and make sure no machine matches it. + { + ActiveMachine.ActivationKey = PasswordGenerator.Generate(8, PasswordGenerator.PasswordType.Alpha, PasswordGenerator.PasswordCasing.Upper); + if (await ActiveMachineAdapter.Context.Machines.Where(x => x.ActivationKey == ActiveMachine.ActivationKey).CountAsync() == 0) + { + break; + } + + ActiveMachine.ActivationKey = null; + } + View.NavigateTo(MachineDesignerNavigationView.MachineDetailsView); } catch (Exception ex) @@ -485,6 +680,11 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels { try { + if (HardwareConfigurationViewVM == null) + { + HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); + } + version = await new HardwareVersionBuilder(ActiveMachineAdapter.Context).Set(version.Guid).WithHardwareComponents().BuildAsync(); HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); } @@ -620,15 +820,25 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels ActiveMachine.ConfigurationGuid = ActiveMachine.Configuration.Guid; ActiveMachine.LastUpdated = DateTime.UtcNow; - ActiveMachine.ProductionDate = DateTime.UtcNow; + ActiveMachine.SiteGuid = SelectedSite == null ? null : (SelectedSite.ID == -1 ? null : SelectedSite.Guid); ColorCalibrationViewVM.Save(); var hwConfig = HardwareConfigurationViewVM.GetResultingHardwareConfiguration(); ActiveMachine.Configuration.SetHardwareConfiguration(hwConfig); - await ActiveMachineAdapter.Context.SaveChangesAsync(); + if (IsNewMachine) + { + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.MachineCreated, _authentication.CurrentUser, ActiveMachine.Name, ActiveMachine, "New machine created using Machine Studio."); + } + else + { + var machineAfterDTO = MachineDTO.FromObservable(ActiveMachine); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.MachineSaved, _authentication.CurrentUser, _machineBeforeSave.Name, _machineBeforeSave, machineAfterDTO, "Machine saved using Machine Studio."); + _machineBeforeSave = machineAfterDTO; + } + if (SelectedMachine != null) { await SelectedMachine.Reload(MachinesAdapter.Context); @@ -652,16 +862,23 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels private void AddNewMachine() { MachineCreationDialogVM vm = new MachineCreationDialogVM(); + vm.IsNewMachine = true; vm.MachineVersions = MachinesAdapter.MachineVersions.ToList(); _notification.ShowModalDialog<MachineCreationDialogVM, Views.MachineCreationDialog>(vm, (x) => { + if (MachinesAdapter.Context.Machines.Any(y => y.SerialNumber == vm.SerialNumber || y.Name.ToLower() == vm.Name.ToLower())) + { + _notification.ShowError("Machine serial number or name already exists."); + return; + } + if (vm.SelectedMachineVersion != null && String.IsNullOrWhiteSpace(vm.SelectedMachineVersion.PrototypeMachineData)) { _notification.ShowError("The selected version does not contain any prototype machine data."); return; } - LoadSelectedMachine(true, false, vm.SelectedMachineVersion); + LoadSelectedMachine(true, false, vm); }, () => { }); } @@ -675,7 +892,9 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels { IsFree = false; await SelectedMachine.DeleteCascadeAsync(MachinesAdapter.Context); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.MachineDeleted, _authentication.CurrentUser, SelectedMachine.Name, SelectedMachine, "Machine deleted using Machine Studio."); MachinesAdapter.Context.Machines.Remove(SelectedMachine); + MachinesAdapter.Machines.Remove(SelectedMachine); } catch (Exception ex) { @@ -690,11 +909,68 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels } } + private void ResetDeviceRegistration() + { + if (_notification.ShowQuestion("Are you sure you wish to reset this machine device registration?")) + { + ActiveMachine.IsDeviceRegistered = false; + ActiveMachine.DeviceId = null; + ActiveMachine.DeviceName = null; + } + } + + private async void MakePrototype() + { + if (ActiveMachine.MachineVersion == null) + { + _notification.ShowError("Machine version must be selected in order to make a prototype."); + return; + } + + if (_notification.ShowQuestion($"Are you sure you wish to make this machine configuration as a prototype for version '{ActiveMachine.MachineVersion.Name}' ?")) + { + using (_notification.PushTaskItem($"Making prototype machine for '{ActiveMachine.MachineVersion.Name}'...")) + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + var machineVersion = await db.MachineVersions.SingleOrDefaultAsync(x => x.Guid == ActiveMachine.MachineVersionGuid); + await machineVersion.ApplyPrototypeMachine(ActiveMachine, db); + await db.SaveChangesAsync(); + } + } + catch (Exception ex) + { + _notification.ShowError($"Error making machine version prototype\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + } + } + #endregion private void CloneMachine() { - LoadSelectedMachine(false, true); + MachineCreationDialogVM vm = new MachineCreationDialogVM(); + vm.IsNewMachine = false; + vm.MachineVersions = MachinesAdapter.MachineVersions.ToList(); + _notification.ShowModalDialog<MachineCreationDialogVM, Views.MachineCreationDialog>(vm, (x) => + { + if (MachinesAdapter.Context.Machines.Any(y => y.SerialNumber == vm.SerialNumber || y.Name.ToLower() == vm.Name.ToLower())) + { + _notification.ShowError("Machine serial number or name already exists."); + return; + } + + LoadSelectedMachine(false, true, vm); + }, () => { }); } private void AddNewSpool() @@ -725,7 +1001,7 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels try { IsFree = false; - MachinesAdapter.Machines = MachinesAdapter.Context.Machines.Where(x => x.SerialNumber.StartsWith(Filter)).Include(x => x.Organization).Include(x => x.MachineVersion).ToSynchronizedObservableCollection(); + MachinesAdapter.Machines = MachinesAdapter.Context.Machines.Where(x => x.SerialNumber.StartsWith(Filter)).Include(x => x.Organization).Include(x => x.MachineVersion).OrderBy(x => x.SerialNumber).ToSynchronizedObservableCollection(); } catch { @@ -739,5 +1015,14 @@ namespace Tango.MachineStudio.MachineDesigner.ViewModels }); } } + + private void ActiveMachine_OrganizationChanged(object sender, Organization e) + { + var sites = ActiveMachine.Organization != null ? _all_sites.Where(x => x.OrganizationGuid == ActiveMachine.OrganizationGuid).ToList() : new List<Site>(); + sites.Insert(0, new Site() { Name = "NONE", ID = -1 }); + Sites = sites; + + SelectedSite = Sites.SingleOrDefault(x => x.Guid == ActiveMachine.SiteGuid); + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/TupViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/TupViewVM.cs new file mode 100644 index 000000000..5d1703dc3 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/ViewModels/TupViewVM.cs @@ -0,0 +1,129 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Common.Tup; +using Tango.SharedUI; + +namespace Tango.MachineStudio.MachineDesigner.ViewModels +{ + public class TupViewVM : ViewModel + { + private INotificationProvider _notification; + + private String _latestVersion; + public String LatestVersion + { + get { return _latestVersion; } + set { _latestVersion = value; RaisePropertyChangedAuto(); } + } + + private Machine _machine; + public Machine Machine + { + get { return _machine; } + set { _machine = value; RaisePropertyChangedAuto(); } + } + + private String _filePath; + public String FilePath + { + get { return _filePath; } + set { _filePath = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private TupFileBuilderProgressEventArgs _progress; + public TupFileBuilderProgressEventArgs Progress + { + get { return _progress; } + set { _progress = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand CreateTupFileCommand { get; set; } + + public RelayCommand SelectFileCommand { get; set; } + + public TupViewVM() + { + + } + + public TupViewVM(INotificationProvider notification) : this() + { + _notification = notification; + CreateTupFileCommand = new RelayCommand(CreateTupFile, () => FilePath != null && IsFree); + SelectFileCommand = new RelayCommand(SelectFile); + } + + public void Init(Machine machine) + { + Machine = machine; + DisplayLatestPPCVersion(); + } + + private async void DisplayLatestPPCVersion() + { + TupFileBuilder builder = new TupFileBuilder(); + + try + { + LatestVersion = await builder.GetLatestPPCVersion(Machine.SerialNumber); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error retrieving latest PPC version."); + await Task.Delay(5000); + DisplayLatestPPCVersion(); + } + } + + private void SelectFile() + { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Title = "Select package location"; + dlg.Filter = "Tango Update Package Files|*.tup"; + dlg.DefaultExt = ".tup"; + dlg.FileName = LatestVersion == null ? $"{Machine.SerialNumber}_Update_{DateTime.Now.Date.ToFileName()}.tup" : $"{Machine.SerialNumber}_Update_{DateTime.Now.Date.ToFileName()}_v{LatestVersion}.tup"; + + if (dlg.ShowDialog().Value) + { + FilePath = dlg.FileName; + } + } + + private async void CreateTupFile() + { + try + { + LogManager.Log($"Generating TUP file to '{FilePath}'..."); + + IsFree = false; + TupFileBuilder builder = new TupFileBuilder(); + builder.Progress += Builder_Progress; + await builder.Build(Machine.SerialNumber, FilePath); + + LogManager.Log("TUP file generated successfully."); + _notification.ShowInfo("Tango update package created successfuly."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating tup file."); + _notification.ShowError($"An error occurred while generating the .tup file.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private void Builder_Progress(object sender, TupFileBuilderProgressEventArgs e) + { + Progress = e; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineCreationDialog.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineCreationDialog.xaml index e3ba1bff4..0640b846e 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineCreationDialog.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineCreationDialog.xaml @@ -6,9 +6,15 @@ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:vm="clr-namespace:Tango.MachineStudio.MachineDesigner.ViewModels" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" mc:Ignorable="d" - d:DesignHeight="400" d:DesignWidth="700" Height="400" Width="700" Background="White" d:DataContext="{d:DesignInstance Type=vm:MachineCreationDialogVM, IsDesignTimeCreatable=False}"> + d:DesignHeight="400" d:DesignWidth="700" Height="460" Width="750" Background="{StaticResource Dialog.Background}" d:DataContext="{d:DesignInstance Type=vm:MachineCreationDialogVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource Dialog.Foreground}"> + + <UserControl.Resources> + <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></converters:BooleanToVisibilityConverter> + </UserControl.Resources> + <Grid Margin="10"> <DockPanel> <Grid DockPanel.Dock="Top"> @@ -17,7 +23,18 @@ <Image Source="../Images/machine-full-fx.png" Width="120" RenderOptions.BitmapScalingMode="Fant"></Image> <materialDesign:PackIcon HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 -10 -10" Kind="PlusCircle" Foreground="#15C315" Width="42" Height="42" /> </Grid> - <TextBlock Margin="30 0 0 0" VerticalAlignment="Bottom" FontSize="22">NEW MACHINE</TextBlock> + <TextBlock Margin="30 0 0 0" VerticalAlignment="Bottom" FontSize="22"> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Text" Value="CLONE MACHINE"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsNewMachine}" Value="True"> + <Setter Property="Text" Value="NEW MACHINE"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> </StackPanel> </Grid> @@ -33,12 +50,30 @@ </Grid> <Grid> - <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Width="400"> - <TextBlock TextWrapping="Wrap" TextAlignment="Center"> - <Run>Please specify the machine version in order to prototype the new machine with default machine settings and configuartion.</Run> + <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 20 0 0" Width="400"> + <TextBlock TextWrapping="Wrap" Visibility="{Binding IsNewMachine,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Run>Please specify the machine version in order to prototype the new machine with default machine settings and configuration.</Run> </TextBlock> - <ComboBox ItemsSource="{Binding MachineVersions}" SelectedItem="{Binding SelectedMachineVersion}" DisplayMemberPath="Name" Margin="0 10 0 0" FontSize="16" materialDesign:HintAssist.Hint="NONE"></ComboBox> + <ComboBox Visibility="{Binding IsNewMachine,Converter={StaticResource BooleanToVisibilityConverter}}" ItemsSource="{Binding MachineVersions}" SelectedItem="{Binding SelectedMachineVersion}" DisplayMemberPath="Name" Margin="0 10 0 0" FontSize="16" materialDesign:HintAssist.Hint="NONE"></ComboBox> + + <TextBlock Margin="0 20 0 0" FontSize="10">Serial Number</TextBlock> + <TextBox Margin="0 2 0 0" Text="{Binding SerialNumber,UpdateSourceTrigger=PropertyChanged}"></TextBox> + + <TextBlock Margin="0 20 0 0" FontSize="10">Name</TextBlock> + <TextBox Margin="0 2 0 0" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}"></TextBox> + + <CheckBox Margin="0 30 0 0" IsChecked="{Binding GenerateDispensers}"> + <TextBlock> + <Run>Automatically generate 8 dispensers for this machine</Run> + <Run>(</Run><Run Foreground="{StaticResource GrayBrush}" FontSize="10" Text="{Binding SerialNumber}"></Run><Run Foreground="{StaticResource GrayBrush}" FontSize="10">-1-8</Run><Run>)</Run> + </TextBlock> + </CheckBox> + + <StackPanel Margin="20 10 0 0" Visibility="{Binding IsNewMachine,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBlock FontSize="10">Dispenser max nl/cm</TextBlock> + <mahapps:NumericUpDown Minimum="0" StringFormat="0.00" Maximum="10" InterceptMouseWheel="True" Value="{Binding DispenserFactor,Mode=TwoWay}" HorizontalContentAlignment="Left" Width="95" HorizontalAlignment="Left" BorderThickness="0 0 0 1" Margin="0 2 0 0" HideUpDownButtons="True" HasDecimals="True" Background="Transparent"></mahapps:NumericUpDown> + </StackPanel> </StackPanel> </Grid> </DockPanel> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineDetailsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineDetailsView.xaml index 1f748fe9f..b2b770698 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineDetailsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineDetailsView.xaml @@ -5,11 +5,17 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" xmlns:global="clr-namespace:Tango.MachineStudio.MachineDesigner" - xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:vm="clr-namespace:Tango.MachineStudio.MachineDesigner.ViewModels" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:BooleanToVisibilityInverseConverter x:Key="BooleanToVisibilityInverseConverter" /> + </UserControl.Resources> + <Grid Margin="20"> <DockPanel> <Grid DockPanel.Dock="Top"> @@ -23,7 +29,7 @@ </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 0 20 0"> - <Button Width="170" Height="45" VerticalAlignment="Center" Command="{Binding SaveCommand}"> + <Button Width="170" Height="45" VerticalAlignment="Center" Command="{Binding SaveCommand}"> <StackPanel Orientation="Horizontal"> <materialDesign:PackIcon Kind="ContentSaveAll" Width="24" Height="24" /> <TextBlock VerticalAlignment="Center" Margin="10 0 0 0">SAVE</TextBlock> @@ -61,6 +67,12 @@ <TabItem Header="HW CONFIGURATION"> <local:HardwareConfigurationView/> </TabItem> + <TabItem Header="UPDATES" Visibility="{Binding IsNewMachine,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> + <local:MachineUpdatesView/> + </TabItem> + <TabItem Header="TUP" Visibility="{Binding IsNewMachine,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> + <local:TupView/> + </TabItem> </TabControl> </Grid> </DockPanel> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineSettingsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineSettingsView.xaml index 40ce9ea08..76517ec37 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineSettingsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineSettingsView.xaml @@ -6,6 +6,7 @@ xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" xmlns:global="clr-namespace:Tango.MachineStudio.MachineDesigner" xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" xmlns:observables="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" xmlns:vm="clr-namespace:Tango.MachineStudio.MachineDesigner.ViewModels" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" @@ -13,6 +14,11 @@ xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter"/> + </UserControl.Resources> + <Grid Margin="20"> <DockPanel> <Grid DockPanel.Dock="Bottom"> @@ -27,84 +33,106 @@ <local:MachineView DataContext="{Binding ActiveMachine}" IsHitTestVisible="False" /> - <Border Grid.Column="1" Margin="100 70" CornerRadius="5" Background="{StaticResource TransparentBackgroundBrush600}" Padding="10" BorderBrush="{StaticResource borderBrush}" BorderThickness="1"> - <Grid TextElement.Foreground="{StaticResource GrayBrush280}"> - <Grid.ColumnDefinitions> - <ColumnDefinition/> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition/> - </Grid.ColumnDefinitions> - <controls:TableGrid RowHeight="50" Margin="10"> - <TextBlock FontWeight="SemiBold">Serial Number</TextBlock> - <TextBox Text="{Binding ActiveMachine.SerialNumber}"></TextBox> + <StackPanel Grid.Column="1" Margin="100 30"> + <Border CornerRadius="5" Background="{StaticResource TransparentBackgroundBrush600}" Padding="10" BorderBrush="{StaticResource borderBrush}" BorderThickness="1"> + <Grid TextElement.Foreground="{StaticResource GrayBrush280}"> + <Grid.ColumnDefinitions> + <ColumnDefinition/> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition/> + </Grid.ColumnDefinitions> + + <StackPanel> + <controls:TableGrid RowHeight="50" Margin="10"> + <TextBlock FontWeight="SemiBold">Serial Number</TextBlock> + <TextBox Text="{Binding ActiveMachine.SerialNumber}"></TextBox> + + <TextBlock FontWeight="SemiBold">Name</TextBlock> + <TextBox Text="{Binding ActiveMachine.Name}"></TextBox> - <TextBlock FontWeight="SemiBold">Name</TextBlock> - <TextBox Text="{Binding ActiveMachine.Name}"></TextBox> + <TextBlock FontWeight="SemiBold">Head Type</TextBlock> + <ComboBox ItemsSource="{Binding Source={x:Type enumerations:HeadTypes},Converter={StaticResource EnumToItemsSourceConverter}}" SelectedValue="{Binding ActiveMachine.MachineHeadType}" SelectedValuePath="Value" DisplayMemberPath="DisplayName" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> - <TextBlock FontWeight="SemiBold">Machine Version</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.MachineVersions}" SelectedItem="{Binding ActiveMachine.MachineVersion}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <TextBlock FontWeight="SemiBold">Machine Version</TextBlock> + <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.MachineVersions}" SelectedItem="{Binding ActiveMachine.MachineVersion}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}" ></ComboBox> - <TextBlock FontWeight="SemiBold">Organization</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.Organizations}" SelectedItem="{Binding ActiveMachine.Organization}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <TextBlock FontWeight="SemiBold">Organization</TextBlock> + <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.Organizations}" SelectedItem="{Binding ActiveMachine.Organization}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> - <TextBlock FontWeight="SemiBold">Default RML</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.Rmls}" SelectedItem="{Binding ActiveMachine.DefaultRml}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <TextBlock FontWeight="SemiBold">Site</TextBlock> + <ComboBox Background="Transparent" ItemsSource="{Binding Sites}" SelectedItem="{Binding SelectedSite}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> - <TextBlock FontWeight="SemiBold">Loaded RML</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.Rmls}" SelectedValue="{Binding ActiveMachine.LoadedRmlGuid}" SelectedValuePath="Guid" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <TextBlock FontWeight="SemiBold">OS Key</TextBlock> + <TextBox Text="{Binding ActiveMachine.OsKey}"></TextBox> - <TextBlock FontWeight="SemiBold">Default Color Space</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.ColorSpaces}" SelectedItem="{Binding ActiveMachine.DefaultColorSpace}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <TextBlock FontWeight="SemiBold">Device COM Port</TextBlock> + <TextBox Text="{Binding ActiveMachine.DeviceComPort}"></TextBox> + </controls:TableGrid> - <TextBlock FontWeight="SemiBold">Default Segment Length</TextBlock> - <mahapps:NumericUpDown HideUpDownButtons="True" BorderThickness="0 0 0 1" Background="Transparent" Minimum="0" Maximum="1000" Value="{Binding ActiveMachine.DefaultSegmentLength}" HasDecimals="False"></mahapps:NumericUpDown> + <Button Margin="0 20 0 0" Background="{StaticResource RedBrush300}" ToolTip="Make this machine configuration as a prototype for the selected machine version" BorderBrush="{StaticResource RedBrush300}" Width="200" Height="45" VerticalAlignment="Bottom" Command="{Binding MakePrototypeCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Copyright" Width="24" Height="24" /> + <TextBlock VerticalAlignment="Center" Margin="10 0 0 0">MAKE PROTOTYPE</TextBlock> + </StackPanel> + </Button> + </StackPanel> - <TextBlock FontWeight="SemiBold">Default Spool Type</TextBlock> - <ComboBox Background="Transparent" ItemsSource="{Binding ActiveMachineAdapter.SpoolTypes}" SelectedItem="{Binding ActiveMachine.DefaultSpoolType}" DisplayMemberPath="Name" Style="{StaticResource TransparentComboBoxStyle}"></ComboBox> + <Rectangle Grid.Column="1" StrokeThickness="1" Stroke="{StaticResource borderBrush}" HorizontalAlignment="Center" Margin="50 50" /> + <controls:TableGrid RowHeight="50" Margin="10" Grid.Column="2"> + <TextBlock FontWeight="SemiBold">Auto Login</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.AutoLogin}"></ToggleButton> - <TextBlock FontWeight="SemiBold">OS Key</TextBlock> - <TextBox Text="{Binding ActiveMachine.OsKey}"></TextBox> + <!--<TextBlock FontWeight="SemiBold">Auto Check For Updates</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.AutoCheckForUpdates}"></ToggleButton>--> - <TextBlock FontWeight="SemiBold">Device COM Port</TextBlock> - <TextBox Text="{Binding ActiveMachine.DeviceComPort}"></TextBox> - </controls:TableGrid> - <Rectangle Grid.Column="1" StrokeThickness="1" Stroke="{StaticResource borderBrush}" HorizontalAlignment="Center" Margin="50 50" /> - <controls:TableGrid RowHeight="50" Margin="10" Grid.Column="2"> - <TextBlock FontWeight="SemiBold">Auto Login</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.AutoLogin}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Setup Activation</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupActivation}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Auto Check For Updates</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.AutoCheckForUpdates}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Setup Remote Assistance</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupRemoteAssistance}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Setup Activation</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupActivation}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Setup UWF</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupUwf}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Setup Remote Assistance</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupRemoteAssistance}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Setup Firmware</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupFirmware}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Setup UWF</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupUwf}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Setup FPGA</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupFpga}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Setup Firmware</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupFirmware}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Is Demo Machine</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.IsDemo}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Setup FPGA</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SetupFpga}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Suspend Version Update</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SuspendVersionUpdate}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Is Demo Machine</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.IsDemo}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Force Version Update</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.ForceVersionUpdate}"></ToggleButton> - <TextBlock FontWeight="SemiBold">Suspend Version Update</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.SuspendVersionUpdate}"></ToggleButton> + <TextBlock FontWeight="SemiBold">Update Schema on Update</TextBlock> + <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.PerformSchemaUpdateOnDataUpdate}"></ToggleButton> + </controls:TableGrid> + </Grid> + </Border> - <TextBlock FontWeight="SemiBold">Force Version Update</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.ForceVersionUpdate}"></ToggleButton> + <Border Visibility="{Binding ActiveMachine.IsDeviceRegistered,Converter={StaticResource BoolToVisConverter}}" Margin="0 10 0 0" CornerRadius="5" Background="{StaticResource TransparentBackgroundBrush600}" Padding="20" BorderBrush="{StaticResource borderBrush}" BorderThickness="1"> + <DockPanel> + <StackPanel DockPanel.Dock="Left"> + <TextBlock FontSize="16" FontWeight="SemiBold">Device Registration</TextBlock> + <TextBlock Margin="0 10 0 0"> + <Run FontWeight="SemiBold">Device ID:</Run> + <Run Text="{Binding ActiveMachine.DeviceId}"></Run> + </TextBlock> + <TextBlock Margin="0 5 0 0"> + <Run FontWeight="SemiBold">Device Name:</Run> + <Run Text="{Binding ActiveMachine.DeviceName}"></Run> + </TextBlock> + </StackPanel> - <TextBlock FontWeight="SemiBold">Update Schema on Update</TextBlock> - <ToggleButton HorizontalAlignment="Left" IsChecked="{Binding ActiveMachine.PerformSchemaUpdateOnDataUpdate}"></ToggleButton> - </controls:TableGrid> - </Grid> - </Border> + <Button Command="{Binding ResetDeviceRegistrationCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource RedBrush300}" BorderBrush="{StaticResource RedBrush300}" Padding="10" Height="45" Width="240">RESET DEVICE REGISTRATION</Button> + </DockPanel> + </Border> + </StackPanel> </Grid> </DockPanel> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.xaml new file mode 100644 index 000000000..0e793dc6a --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.xaml @@ -0,0 +1,94 @@ +<UserControl x:Class="Tango.MachineStudio.MachineDesigner.Views.MachineUpdateDetailsDialog" + 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:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:vm="clr-namespace:Tango.MachineStudio.MachineDesigner.ViewModels" + xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" + mc:Ignorable="d" + d:DesignHeight="400" d:DesignWidth="700" Height="700" Width="1280" Background="White" d:DataContext="{d:DesignInstance Type=vm:MachineUpdateDetailsDialogVM, IsDesignTimeCreatable=False}"> + <UserControl.Resources> + <converters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <converters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter" /> + <converters:StringToOneLineConverter x:Key="StringToOneLineConverter" /> + </UserControl.Resources> + + <Grid> + <Grid Grid.RowSpan="2"> + <Grid.RowDefinitions> + <RowDefinition Height="60"/> + <RowDefinition Height="31*"/> + <RowDefinition Height="50"/> + </Grid.RowDefinitions> + + <StackPanel Orientation="Horizontal" DataContext="{Binding Update}"> + <materialDesign:PackIcon Width="42" Height="42" VerticalAlignment="Center"> + <materialDesign:PackIcon.Style> + <Style TargetType="materialDesign:PackIcon"> + <Setter Property="Kind" Value="Information"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsSetup}" Value="True"> + <Setter Property="Kind" Value="Settings"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsUpdate}" Value="True"> + <Setter Property="Kind" Value="CloudDownload"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsDataBase}" Value="True"> + <Setter Property="Kind" Value="Database"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsSynchronization}" Value="True"> + <Setter Property="Kind" Value="Sync"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsOfflineUpdate}" Value="True"> + <Setter Property="Kind" Value="Sd"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsOfflineFirmwareUpgrade}" Value="True"> + <Setter Property="Kind" Value="Chip"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsStarted}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource OrangeBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsCompleted}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource GreenBrush }"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsFailed}" Value="True"> + <Setter Property="Foreground" Value="Red"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </materialDesign:PackIcon.Style> + </materialDesign:PackIcon> + <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 DateTimeUTCToShortDateTimeConverter}}"></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 DateTimeUTCToShortDateTimeConverter}}"></TextBlock> + </controls:TableGrid> + </Grid> + + <Border Padding="5" BorderThickness="1" BorderBrush="{StaticResource BorderBrushGainsboro}"> + <TextBox BorderThickness="0" Text="{Binding Update.FailedLog,TargetNullValue='No further Information available.'}" Style="{x:Null}" TextWrapping="NoWrap" IsReadOnly="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="Transparent" /> + </Border> + </DockPanel> + </Grid> + + <Grid Grid.Row="2"> + <Button HorizontalAlignment="Right" Width="140" Command="{Binding CloseCommand}">CLOSE</Button> + </Grid> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.xaml.cs new file mode 100644 index 000000000..8bb051c51 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdateDetailsDialog.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.MachineStudio.MachineDesigner.Views +{ + /// <summary> + /// Interaction logic for MachineCreationDialog.xaml + /// </summary> + public partial class MachineUpdateDetailsDialog : UserControl + { + public MachineUpdateDetailsDialog() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.xaml new file mode 100644 index 000000000..bd272718d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.xaml @@ -0,0 +1,114 @@ +<UserControl x:Class="Tango.MachineStudio.MachineDesigner.Views.MachineUpdatesView" + 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.MachineStudio.MachineDesigner.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.MachineDesigner" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1500" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <converters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter" /> + <converters:StringToOneLineConverter x:Key="StringToOneLineConverter" /> + </UserControl.Resources> + + <Grid Margin="20" DataContext="{Binding MachineUpdatesViewVM}"> + <DockPanel IsEnabled="{Binding IsFree}"> + <Grid DockPanel.Dock="Bottom"> + + </Grid> + + <Grid Margin="0 20"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="38*"/> + <ColumnDefinition Width="117*"/> + </Grid.ColumnDefinitions> + + <local:MachineView Margin="30 80 0 0" DataContext="{Binding Machine}" IsHitTestVisible="False" VerticalAlignment="Top" Height="241" /> + + <DockPanel Grid.Column="1" Margin="50 100 50 50"> + <Grid DockPanel.Dock="Bottom" Height="50"> + <StackPanel Orientation="Horizontal"> + <CheckBox IsChecked="{Binding DisplayMachineSetups}">Machine Setups</CheckBox> + <CheckBox IsChecked="{Binding DisplayApplicationUpdates}" Margin="30 0">Software Updates</CheckBox> + <CheckBox IsChecked="{Binding DisplayDatabaseUpdates}">Database Updates</CheckBox> + <CheckBox IsChecked="{Binding DisplaySynchronizations}" Margin="30 0 0 0">Synchronizations</CheckBox> + <CheckBox IsChecked="{Binding DisplayOfflineUpdates}" Margin="30 0 0 0">Offline Updates</CheckBox> + <CheckBox IsChecked="{Binding DisplayFirmwareUpgrades}" Margin="30 0 0 0">Offline Firmware Upgrades</CheckBox> + </StackPanel> + + <Button Command="{Binding RefreshCommand}" HorizontalAlignment="Right" Width="150" Style="{StaticResource MaterialDesignFlatButton}">REFRESH</Button> + </Grid> + <Grid> + <DataGrid Margin="0 0 0 10" SelectionUnit="FullRow" BorderBrush="{StaticResource borderBrush }" BorderThickness="1" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="True" ItemsSource="{Binding Updates}" SelectedItem="{Binding SelectedUpdate}"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + </Style> + </DataGrid.CellStyle> + <DataGrid.Columns> + <DataGridTemplateColumn Header=""> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <materialDesign:PackIcon Width="16" Height="16"> + <materialDesign:PackIcon.Style> + <Style TargetType="materialDesign:PackIcon"> + <Setter Property="Kind" Value="Information"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsSetup}" Value="True"> + <Setter Property="Kind" Value="Settings"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsUpdate}" Value="True"> + <Setter Property="Kind" Value="CloudDownload"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsDataBase}" Value="True"> + <Setter Property="Kind" Value="Database"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsSynchronization}" Value="True"> + <Setter Property="Kind" Value="Sync"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsOfflineUpdate}" Value="True"> + <Setter Property="Kind" Value="Sd"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsOfflineFirmwareUpgrade}" Value="True"> + <Setter Property="Kind" Value="Chip"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsStarted}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource OrangeBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsCompleted}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource GreenBrush }"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding IsFailed}" Value="True"> + <Setter Property="Foreground" Value="Red"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </materialDesign:PackIcon.Style> + </materialDesign:PackIcon> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="STARTED" Binding="{Binding StartDate,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="Auto" /> + <DataGridTextColumn Header="APPLICATION" Binding="{Binding ApplicationVersion}" Width="Auto" /> + <DataGridTextColumn Header="FIRMWARE" Binding="{Binding FirmwareVersion}" Width="Auto" /> + <DataGridTextColumn Header="ENDED" Binding="{Binding EndDate,TargetNullValue='Never',FallbackValue='Never',Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="Auto" /> + <DataGridTextColumn Header="STATUS" Binding="{Binding UpdateStatus,Converter={StaticResource EnumToDescriptionConverter}}" Width="Auto" /> + <DataGridTextColumn Header="REASON" Binding="{Binding FailedReason,Converter={StaticResource StringToOneLineConverter},ConverterParameter='80'}" Width="*" /> + </DataGrid.Columns> + </DataGrid> + </Grid> + </DockPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.xaml.cs new file mode 100644 index 000000000..d13ef2d0e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachineUpdatesView.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.MachineStudio.MachineDesigner.Views +{ + /// <summary> + /// Interaction logic for SpoolsView.xaml + /// </summary> + public partial class MachineUpdatesView : UserControl + { + public MachineUpdatesView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachinesView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachinesView.xaml index 35b578b6a..a231e92a3 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachinesView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MachinesView.xaml @@ -15,6 +15,7 @@ d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <UserControl.Resources> <converters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter" /> + <converters:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter" /> </UserControl.Resources> <Grid> @@ -73,7 +74,8 @@ <DataGridTextColumn Header="NAME" Binding="{Binding Name}" Width="Auto" /> <DataGridTextColumn Header="ORGANIZATION" Binding="{Binding Organization.Name}" Width="Auto" /> <DataGridTextColumn Header="VERSION" Binding="{Binding MachineVersion.Name}" Width="Auto" /> - <DataGridTextColumn Header="DEMO MACHINE" Binding="{Binding IsDemo}" Width="Auto" /> + <DataGridTextColumn Header="REGISTERED" Binding="{Binding IsDeviceRegistered,Converter={StaticResource BooleanToYesNoConverter}}" Width="Auto" /> + <DataGridTextColumn Header="DEMO MACHINE" Binding="{Binding IsDemo,Converter={StaticResource BooleanToYesNoConverter}}" Width="Auto" /> <DataGridTextColumn Header="LAST UPDATED" Binding="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="1*" /> </DataGrid.Columns> </controls:DoubleClickDataGrid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MainView.xaml index bc9b038dc..833086bf0 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/MainView.xaml @@ -9,7 +9,7 @@ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - <Grid> + <Grid IsEnabled="{Binding IsFree}"> <controls:NavigationControl x:Name="navigationControl" TransitionType="Slide"> <local:MachinesView /> <local:MachineDetailsView/> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/SpoolsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/SpoolsView.xaml index 3663f72f8..f08da88d1 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/SpoolsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/SpoolsView.xaml @@ -9,8 +9,14 @@ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EmptyStringToNullConverter x:Key="EmptyStringToNullConverter" /> + </UserControl.Resources> + <Grid Margin="20"> <DockPanel> <Grid DockPanel.Dock="Bottom"> @@ -67,10 +73,7 @@ </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn> - <DataGridTextColumn Header="START OFFSET PULSES" Binding="{Binding StartOffsetPulses}" Width="Auto" /> - <DataGridTextColumn Header="BACKING RATE" Binding="{Binding BackingRate}" Width="Auto" /> - <DataGridTextColumn Header="SEGMENT OFFSET PULSES" Binding="{Binding SegmentOffsetPulses}" Width="Auto" /> - <DataGridTextColumn Header="BOTTOM BACKING RATE" Binding="{Binding BottomBackingRate}" Width="1*" /> + <DataGridTextColumn Header="LIMIT SWITCH START POINT OFFSET" Binding="{Binding LimitSwitchStartPointOffset,Converter={StaticResource EmptyStringToNullConverter}}" Width="1*" /> </DataGrid.Columns> </DataGrid> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.xaml new file mode 100644 index 000000000..895a26ca0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.xaml @@ -0,0 +1,60 @@ +<UserControl x:Class="Tango.MachineStudio.MachineDesigner.Views.TupView" + 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.MachineStudio.MachineDesigner.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.MachineDesigner" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.MachineDesigner.Views" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}" Background="Transparent"> + + <Grid Margin="20" DataContext="{Binding TupViewVM}"> + <DockPanel IsEnabled="{Binding IsFree}"> + <Grid DockPanel.Dock="Bottom"> + + </Grid> + + <Grid Margin="0 20"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="38*"/> + <ColumnDefinition Width="117*"/> + </Grid.ColumnDefinitions> + + <local:MachineView Margin="30 80 0 0" DataContext="{Binding Machine}" IsHitTestVisible="False" VerticalAlignment="Top" Height="241" /> + + <DockPanel Grid.Column="1" Margin="50 100 300 100"> + <TextBlock DockPanel.Dock="Top"> + <Run>Create a complete update package (.tup) in order to update this machine offline using a removable storage device.</Run> + <LineBreak/> + <Run>The latest PPC version is </Run> + <Run Foreground="{StaticResource AccentColorBrush}" FontWeight="SemiBold" Text="{Binding LatestVersion,FallbackValue='loading...',TargetNullValue='loading...'}"></Run> + </TextBlock> + <Grid Margin="0 20 0 0"> + <Border Background="{StaticResource Transparent200}" CornerRadius="5" Padding="60" BorderThickness="1" BorderBrush="Silver"> + <DockPanel> + <DockPanel DockPanel.Dock="Top" Height="40"> + <Button Command="{Binding SelectFileCommand}" DockPanel.Dock="Right" BorderBrush="Silver" BorderThickness="1" Padding="0" Height="Auto" Width="40" Margin="5 0 0 0" Style="{StaticResource MaterialDesignFlatButton}"> + <material:PackIcon Kind="Folder" /> + </Button> + <TextBox materialDesign:HintAssist.Hint="Select package location" BorderBrush="Silver" BorderThickness="1" Text="{Binding FilePath}" IsReadOnly="True" VerticalContentAlignment="Center" Padding="10 0 0 0"></TextBox> + </DockPanel> + <StackPanel DockPanel.Dock="Bottom"> + <TextBlock HorizontalAlignment="Center" Text="{Binding Progress.Message,FallbackValue='Ready',TargetNullValue='Ready'}"></TextBlock> + <ProgressBar Margin="0 10 0 0" Height="15" IsIndeterminate="{Binding Progress.IsIntermediate}" Value="{Binding Progress.Progress}" Maximum="{Binding Progress.Total}"></ProgressBar> + </StackPanel> + <Grid> + <Button Command="{Binding CreateTupFileCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="20 10" Height="60" Width="300">GENERATE UPDATE PACKAGE</Button> + </Grid> + </DockPanel> + </Border> + </Grid> + </DockPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.xaml.cs new file mode 100644 index 000000000..fe01296d8 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.MachineDesigner/Views/TupView.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.MachineStudio.MachineDesigner.Views +{ + /// <summary> + /// Interaction logic for SpoolsView.xaml + /// </summary> + public partial class TupView : UserControl + { + public TupView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/CalibrationMeasurementModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/CalibrationMeasurementModel.cs new file mode 100644 index 000000000..6345d5f59 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/CalibrationMeasurementModel.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.BL.Enumerations; +using Tango.PMR.Printing; + +namespace Tango.MachineStudio.RML.Models +{ + public static class ColorCalibrationExt + { + public static Dictionary<LiquidTypes, LAB> TargetLiquidTypeToLAB = new Dictionary<LiquidTypes, LAB> + { + {LiquidTypes.Cyan, new LAB(51.94591,-18.3438,-39.0577)}, + {LiquidTypes.Magenta, new LAB(47.46248, 65.84478, 3.922838)}, + {LiquidTypes.Yellow, new LAB(84.41956,-0.27005, 94.05445)}, + {LiquidTypes.Black, new LAB(26.57986, -0.13567, 0.948574)}, + }; + public static Dictionary<LiquidTypes, string> DisplayLiquidTypeToLABType = new Dictionary<LiquidTypes, string> + { + {LiquidTypes.Cyan, "L"}, + {LiquidTypes.Magenta, "L"}, + {LiquidTypes.Yellow, "B"}, + {LiquidTypes.Black, "L"}, + }; + }; + + public class LAB + { + public double L { get; set; } + public double A { get; set; } + public double B { get; set; } + + public LAB( double l, double a, double b) + { + L = l; B = b; A = a; + } + }; + + public class CalibrationMeasurementModel : ExtendedObject + { + #region properties + private double _l; + + public double L + { + get { return _l; } + set { _l = value; RaisePropertyChangedAuto(); } + } + + private double _a; + + public double A + { + get { return _a; } + set { _a = value; RaisePropertyChangedAuto(); } + } + + private double _b; + + public double B + { + get { return _b; } + set { _b = value; RaisePropertyChangedAuto(); } + } + + private double _ink; + + public double Ink + { + get { return _ink; } + set { _ink = value; RaisePropertyChangedAuto(); } + } + #endregion + + public CalibrationMeasurementModel() + { + + } + public CalibrationMeasurementModel(Tango.MachineStudio.RML.Models.ColorLinearizationModel.LinearizationDataItem model) + { + L = model.L; + A = model.A; + B = model.B; + Ink = model.InkPercentage; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/ColorLinearizationModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/ColorLinearizationModel.cs new file mode 100644 index 000000000..23179b3f2 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Models/ColorLinearizationModel.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Documents; + +namespace Tango.MachineStudio.RML.Models +{ + public class ColorLinearizationModel + { + public class LinearizationDataItem + { + public double InkPercentage { get; set; } + public double L { get; set; } + public double A { get; set; } + public double B { get; set; } + } + + public ColorLinearizationModel() + { + + } + + public void GetDataFromFile(string fileName, out List<LinearizationDataItem> items, ref string errors) + { + items = null; + try + { + using (ExcelReader reader = new ExcelReader(fileName)) + { + items = reader.GetDataByIndex<LinearizationDataItem>("Sheet1", 2); + } + } + catch (Exception ex) + { + errors = ex.Message; + } + + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Tango.MachineStudio.RML.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Tango.MachineStudio.RML.csproj index 2ff9ab0a3..38d289c58 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Tango.MachineStudio.RML.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Tango.MachineStudio.RML.csproj @@ -49,6 +49,12 @@ <Reference Include="MaterialDesignThemes.Wpf, Version=2.3.1.953, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath> </Reference> + <Reference Include="OxyPlot"> + <HintPath>..\..\..\packages\OxyPlot.Core.2.0.0\lib\net45\OxyPlot.dll</HintPath> + </Reference> + <Reference Include="OxyPlot.Wpf"> + <HintPath>..\..\..\packages\OxyPlot.Wpf.2.0.0\lib\net45\OxyPlot.Wpf.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> @@ -73,7 +79,9 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="Contracts\IMainView.cs" /> + <Compile Include="Models\CalibrationMeasurementModel.cs" /> <Compile Include="Models\CctModel.cs" /> + <Compile Include="Models\ColorLinearizationModel.cs" /> <Compile Include="RMLModule.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType>Code</SubType> @@ -93,16 +101,21 @@ <Compile Include="ViewModels\CalibrationDataPointVM.cs" /> <Compile Include="ViewModels\CalibrationDataViewVM.cs" /> <Compile Include="ViewModels\CalibrationDataVM.cs" /> + <Compile Include="ViewModels\ColorCalibrationViewVM.cs" /> <Compile Include="ViewModels\ColorConversionViewVM.cs" /> <Compile Include="ViewModels\LiquidVolumeVM.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> <Compile Include="ViewModels\RgbVM.cs" /> + <Compile Include="ViewModels\RmlDeleteDialogViewVM.cs" /> <Compile Include="Views\AddLiquidFactorView.xaml.cs"> <DependentUpon>AddLiquidFactorView.xaml</DependentUpon> </Compile> <Compile Include="Views\CalibrationDataView.xaml.cs"> <DependentUpon>CalibrationDataView.xaml</DependentUpon> </Compile> + <Compile Include="Views\ColorCalibrationView.xaml.cs"> + <DependentUpon>ColorCalibrationView.xaml</DependentUpon> + </Compile> <Compile Include="Views\ColorConversionView.xaml.cs"> <DependentUpon>ColorConversionView.xaml</DependentUpon> </Compile> @@ -112,12 +125,24 @@ <Compile Include="Views\ProcessParametersView.xaml.cs"> <DependentUpon>ProcessParametersView.xaml</DependentUpon> </Compile> + <Compile Include="Views\RmlDeleteDialogView.xaml.cs"> + <DependentUpon>RmlDeleteDialogView.xaml</DependentUpon> + </Compile> <Compile Include="Views\RmlsView.xaml.cs"> <DependentUpon>RmlsView.xaml</DependentUpon> </Compile> <Compile Include="Views\RmlView.xaml.cs"> <DependentUpon>RmlView.xaml</DependentUpon> </Compile> + <Compile Include="Views\HeadCleaningParametersView.xaml.cs"> + <DependentUpon>HeadCleaningParametersView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\ThreadParametersView.xaml.cs"> + <DependentUpon>ThreadParametersView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\SpoolsView.xaml.cs"> + <DependentUpon>SpoolsView.xaml</DependentUpon> + </Compile> <EmbeddedResource Include="Properties\Resources.resx"> <Generator>ResXFileCodeGenerator</Generator> <LastGenOutput>Resources.Designer.cs</LastGenOutput> @@ -142,6 +167,10 @@ <Project>{40085232-aced-4cbe-945b-90ba8153c151}</Project> <Name>Tango.BrushPicker</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.ColorCalibration\Tango.ColorCalibration.csproj"> + <Project>{b60c695c-61e8-4091-b506-4c45349c04aa}</Project> + <Name>Tango.ColorCalibration</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.ColorConversion\Tango.ColorConversion.csproj"> <Project>{b4fe6485-4161-4b36-bc08-67e0b53d01b7}</Project> <Name>Tango.ColorConversion</Name> @@ -203,6 +232,10 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Views\ColorCalibrationView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\ColorConversionView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -215,6 +248,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\RmlDeleteDialogView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\RmlsView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -223,6 +260,18 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\HeadCleaningParametersView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Views\ThreadParametersView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Views\SpoolsView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> </ItemGroup> <ItemGroup> <Resource Include="Images\threads.png" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/CalibrationDataViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/CalibrationDataViewVM.cs index b34ef83bc..fd69fef35 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/CalibrationDataViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/CalibrationDataViewVM.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL.Calibration; +using Tango.BL.Entities; using Tango.Core.Commands; using Tango.MachineStudio.Common; using Tango.MachineStudio.Common.Notifications; @@ -106,5 +107,14 @@ namespace Tango.MachineStudio.RML.ViewModels _notification.ShowError("An error occurred while trying to export the calibration data."); } } + + public void ApplyCalibrationData(LiquidType liquidType, List<CalibrationDataPointVM> newpoints) + { + CalibrationDataVM vm = LiquidsCalibrationData.FirstOrDefault(x => x.LiquidType == liquidType); + if(vm != null) + { + newpoints.ForEach(x => vm.CalibrationPoints.Add(x)); + } + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorCalibrationViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorCalibrationViewVM.cs new file mode 100644 index 000000000..f04eccd90 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorCalibrationViewVM.cs @@ -0,0 +1,551 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core; +using Tango.Core.Commands; +using Tango.MachineStudio.RML.Models; +using Tango.SharedUI; +using OxyPlot; +using OxyPlot.Wpf; +using OxyPlot.Annotations; +using Tango.ColorCalibration; +using Tango.PMR.ColorLab; +using Tango.Logging; +using Tango.MachineStudio.Common.Notifications; +using System.Text.RegularExpressions; +using Microsoft.Win32; + +namespace Tango.MachineStudio.RML.ViewModels +{ + public class ColorCalibrationViewVM : ExtendedObject + { + private IColorCalibrator _calibrator; + private ILinearizationMeasurements _linearizationMeasurementscalibrator; + private INotificationProvider _notification; + + #region Properties + + private Rml _rml; + public Rml RML + { + get { return _rml; } + set { _rml = value; RaisePropertyChangedAuto(); } + } + + private BL.Entities.LiquidType _liquidType; + + public BL.Entities.LiquidType LiquidType + { + get { return _liquidType; } + set { _liquidType = value; RaisePropertyChangedAuto(); RaisePropertyChanged("LiquidTypeName"); } + } + + private List<BL.Entities.LiquidType> _liquidTypes; + + public List<BL.Entities.LiquidType> LiquidTypes + { + get { return _liquidTypes; } + set { _liquidTypes = value; } + } + + + private ObservableCollection<CalibrationMeasurementModel> _measurements; + public ObservableCollection<CalibrationMeasurementModel> Measurements + { + get + { + return _measurements; + } + set + { + _measurements = value; RaisePropertyChangedAuto(); + } + } + + + private double _factor; + + public double Factor + { + get { return _factor; } + set { _factor = value; RaisePropertyChangedAuto(); } + } + + private string _errorMessage; + + public string ErrorMessage + { + get { return _errorMessage; } + set { _errorMessage = value; RaisePropertyChangedAuto(); } + } + private bool _hasError; + + public bool HasError + { + get { return _hasError; } + set { _hasError = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand ImportDataCommand { get; set; } + public RelayCommand CreateGraphCommand { get; set; } + public RelayCommand CreateLinearizationGraphCommand { get; set; } + public RelayCommand ExportGraphCommand { get; set; } + public RelayCommand ApplyCalibrationDataCommand { get; set; } + + + public string LiquidTypeName + { + get { return LiquidType == null ?"" : LiquidType.Name; } + } + + public Plot PlotControl { get; set; } + private IList<DataPoint> _points; + /// <summary> + /// Binding to ItemsSource of line chart. + /// </summary> + public IList<DataPoint> Points + { + get { return _points; } + set + { + _points = value; + RaisePropertyChangedAuto(); + } + } + private IList<DataPoint> _targetPoints; + /// <summary> + /// Binding to ItemsSource of line chart. + /// </summary> + public IList<DataPoint> TargetPoints + { + get { return _targetPoints; } + set + { + _targetPoints = value; + RaisePropertyChangedAuto(); + } + } + private int _step; + public int XStep + { + get { return _step; } + set { _step = value; RaisePropertyChangedAuto(); } + } + + private double _from; + /// <summary> + /// From use to binding to bottom axis min value + /// </summary> + public double From + { + get { return _from; } + set + { + _from = value; RaisePropertyChangedAuto(); + } + } + + private double _to; + /// <summary> + /// To use to binding to bottom axis max value + /// </summary> + public double To + { + get { return _to; } + set + { + _to = value; RaisePropertyChangedAuto(); + } + } + + private double _LabMinVal; + + public double LabMinVal + { + get { return _LabMinVal; } + set { _LabMinVal = value; RaisePropertyChangedAuto(); } + } + + private double _LabMaxVal; + + public double LabMaxVal + { + get { return _LabMaxVal; } + set { _LabMaxVal = value; RaisePropertyChangedAuto(); } + } + + public Plot LABLinearizationPlotControl { get; set; } + public Plot LinearizationPlotControl { get; set; } + private IList<DataPoint> _linearizationPoints; + /// <summary> + /// Binding to ItemsSource of line chart. + /// </summary> + public IList<DataPoint> LinearizationPoints + { + get { return _linearizationPoints; } + set + { + _linearizationPoints = value; + RaisePropertyChangedAuto(); + } + } + + private IList<DataPoint> _LPoints; + + public IList<DataPoint> LPoints + { + get { return _LPoints; } + set { _LPoints = value; } + } + + private IList<DataPoint> _APoints; + + public IList<DataPoint> APoints + { + get { return _APoints; } + set { _APoints = value; } + } + + private IList<DataPoint> _BPoints; + + public IList<DataPoint> BPoints + { + get { return _BPoints; } + set { _BPoints = value; } + } + + + #endregion + + public ColorCalibrationViewVM(INotificationProvider notification) + { + _notification = notification; + Measurements = new ObservableCollection<CalibrationMeasurementModel>() + { + new CalibrationMeasurementModel(), + new CalibrationMeasurementModel(), + new CalibrationMeasurementModel(), + }; + Factor = 0; + HasError = false; + ImportDataCommand = new RelayCommand(ImportDataForCalcFactorExcel); + CreateGraphCommand = new RelayCommand(CreateGraph); + CreateLinearizationGraphCommand = new RelayCommand(CreateLinearizationGraph); + ExportGraphCommand = new RelayCommand(ExportGraph); + ApplyCalibrationDataCommand = new RelayCommand(ApplyCalibrationData); + this.Points = new List<DataPoint>(); + TargetPoints = new List<DataPoint>(); + LinearizationPoints = new List<DataPoint>(); + LPoints = new List<DataPoint>(); + APoints = new List<DataPoint>(); + BPoints = new List<DataPoint>(); + } + + public void Loading() + { + LiquidType = LiquidTypes.Count > 0 ? LiquidTypes[0] : null; + _calibrator = new DefaultColorCalibrator(); + _linearizationMeasurementscalibrator = new DefaultColorCalibrator(); + + } + + public void ClearResults() + { + Points.Clear(); + TargetPoints.Clear(); + ErrorMessage = ""; + HasError = false; + Factor = 0.0; + } + + private double GetLiquidFactor() + { + try + { + CalibrationInput conversionInput = new CalibrationInput(); + Measurements.ToList().ForEach(x => conversionInput.Measurements.Add(new CalibrationMeasurement { L = x.L, A = x.A, B = x.B, NanoliterPerCentimeter = x.Ink })); + conversionInput.LiquidType = PMR.ColorLab.LiquidType.TryParse(_liquidType.Type.ToString(), out PMR.ColorLab.LiquidType outValue) ? outValue : PMR.ColorLab.LiquidType.Black; + + + LAB lab; + if (ColorCalibrationExt.TargetLiquidTypeToLAB.TryGetValue(_liquidType.Type, out lab)) + { + conversionInput.TargetL = lab.L; + conversionInput.TargetA = lab.A; + conversionInput.TargetB = lab.B; + } + CalibrationOutput result = _calibrator.GetLiquidFactor(conversionInput); + + ErrorMessage = result.ErrorMessage; + HasError = false == String.IsNullOrEmpty(ErrorMessage); + + return result.LiquidFactor; + } + catch (Exception ex ) + { + HasError = true; + ErrorMessage = "Error occurred while trying to call GetLiquidFactor."; + LogManager.Log(ex, "Error occurred while trying to call GetLiquidFactor."); + } + return 0.0; + } + + private void ImportDataForCalcFactorExcel() + { + OpenFileDialog dlg = new OpenFileDialog(); + + try + { + dlg.Title = $"Import excel file for calculate Factor"; + dlg.Filter = "Excel Files|*.xlsx"; + if (dlg.ShowDialog().Value) + { + ClearResults(); + + List<ColorLinearizationModel.LinearizationDataItem> items;//List<LinearizationDataItem> items + ColorLinearizationModel model = new ColorLinearizationModel(); + string error = ""; + model.GetDataFromFile(dlg.FileName, out items, ref error); + if (false == String.IsNullOrEmpty(error) || items == null || items.Count == 0) + { + _notification.ShowError("An error occurred while trying to import data form the selected excel file. Please check the file format if valid and is available to read."); + return; + } + Measurements.Clear(); + items.ForEach(x => Measurements.Add(new CalibrationMeasurementModel(x))); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error importing excel file " + dlg.FileName); + _notification.ShowError("An error occurred while trying to import the selected excel file. Please check the file format if valid and is available to read."); + } + } + #region CreateGraph + + private async void CreateGraph(object obj) + { + if (_liquidType == null) + return; + ClearResults(); + PlotControl.InvalidatePlot(true); + string labType = ColorCalibrationExt.DisplayLiquidTypeToLABType[_liquidType.Type]; + await Task.Factory.StartNew(() => + { + Factor = GetLiquidFactor( ); + }); + + DataPoint targetPoint = GetTargetPoint(); + + To = 0; + From = 0; + + Measurements.ToList().ForEach(x =>{ Points.Add(new DataPoint(x.Ink, labType == "L" ? x.L : x.B)); + TargetPoints.Add(new DataPoint(x.Ink, targetPoint.Y)); }); + + _to = labType == "L"? 100 : 128; + _from = labType == "L" ? 0 : -127; + + RaisePropertyChanged("To"); + RaisePropertyChanged("From"); + XStep = (int)(Points.Count / 6); + RaisePropertyChanged("CalibrationType"); + PlotControl.InvalidatePlot(true); + + } + + private DataPoint GetTargetPoint() + { + var listValues = Measurements.ToList(); + if (listValues.Count == 0 || Factor <=0) + return new DataPoint(0, 0); + + string labType = ColorCalibrationExt.DisplayLiquidTypeToLABType[_liquidType.Type]; + + var left = listValues.Where(y => y.Ink == listValues.Min(x => x.Ink)).ToList().First(); + var right = listValues.Where(y => y.Ink == listValues.Max(x => x.Ink)).ToList().First(); + // Normalize start/end to left right to make the offset calc simpler. + DataPoint leftPoint = new DataPoint(left.Ink, labType == "L" ? left.L : left.B); + DataPoint rightPoint = new DataPoint(right.Ink, labType == "L" ? right.L : right.B); + + double deltaX = rightPoint.X - leftPoint.X; + double deltaY = rightPoint.Y - leftPoint.Y; + + // prevents division by zero exceptions. + if (deltaX == 0 ) + return new DataPoint(0, 0); + + double slope = deltaY / deltaX; + double offset = leftPoint.Y - leftPoint.X * slope; + double calculatedY = Factor * slope + offset; + + return new DataPoint(Factor, calculatedY); ; + } + + #endregion + #region CreateLinearizationGraph + + private async void CreateLinearizationGraph(object obj) + { + if (_liquidType == null ) + return; + + string labType = ColorCalibrationExt.DisplayLiquidTypeToLABType[_liquidType.Type]; + + ColorLinearizationModel model = new ColorLinearizationModel(); + string fileName = GetInkDataFileOpen();// @"C:\Test\Test Input Lineration.xlsx";//dialog to open file + if (fileName == null) + return; + + LinearizationPoints.Clear(); + LinearizationPlotControl.InvalidatePlot(true); + LPoints.Clear(); + APoints.Clear(); + BPoints.Clear(); + LabMinVal = LabMaxVal = 0; + LABLinearizationPlotControl.InvalidatePlot(true); + + List<ColorLinearizationModel.LinearizationDataItem> items; + string errors = ""; + model.GetDataFromFile(fileName, out items, ref errors); + if(false == String.IsNullOrEmpty(errors) || items == null || items.Count == 0) + { + _notification.ShowError("An error occurred while trying to import data form the selected excel file. Please check the file format if valid and is available to read."); + return; + } + + List<double> outputPoints = new List<double>(); + + await Task.Factory.StartNew(() => + { + outputPoints = GetLinearizationMeasurements(items); + }); + + LabMinVal = items.Min(x => Math.Min(x.L, Math.Min(x.A, x.B))); + LabMaxVal = items.Max(x => Math.Max(x.L, Math.Max(x.A, x.B))); + foreach (var labItem in items) + { + LPoints.Add(new DataPoint(labItem.InkPercentage, labItem.L)); + APoints.Add(new DataPoint(labItem.InkPercentage, labItem.A)); + BPoints.Add(new DataPoint(labItem.InkPercentage, labItem.B)); + } + LABLinearizationPlotControl.InvalidatePlot(true); + + if (outputPoints == null || outputPoints.Count != items.Count) + return; + + foreach (var nw in items.Zip(outputPoints, Tuple.Create)) + { + LinearizationPoints.Add(new DataPoint(nw.Item1.InkPercentage, nw.Item2)); + } + + LinearizationPlotControl.InvalidatePlot(true); + } + + /// <summary> + /// Open file dialog and get name of file + /// </summary> + /// <returns></returns> + private String GetInkDataFileOpen() + { + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Title = "Select Ink data file"; + dlg.Filter = "Excel |*.xlsx"; + if (dlg.ShowDialogCenter()) + { + return dlg.FileName; + } + + return null; + } + + private List<double> GetLinearizationMeasurements(List<ColorLinearizationModel.LinearizationDataItem> items) + { + try + { + LinearizationInput linearizationInput = new LinearizationInput(); + items.ForEach(x => linearizationInput.Measurements.Add(new LinearizationMeasurement { L = x.L, A = x.A, B = x.B, InkPercentage = x.InkPercentage })); + linearizationInput.LiquidType = PMR.ColorLab.LiquidType.TryParse(_liquidType.Type.ToString(), out PMR.ColorLab.LiquidType outValue) ? outValue : PMR.ColorLab.LiquidType.Black; + + LinearizationOutput result = _linearizationMeasurementscalibrator.GetLinearizationMeasurements(linearizationInput); + + if(!String.IsNullOrEmpty(result.ErrorMessage)) + { + LogManager.Log(result.ErrorMessage, "GetLinearizationMeasurements returns error." + result.ErrorMessage); + InvokeUI(() => + { + _notification.ShowError("Linearization failed. " + result.ErrorMessage); + }); + } + + LAB lab; + if (ColorCalibrationExt.TargetLiquidTypeToLAB.TryGetValue(_liquidType.Type, out lab)) + { + linearizationInput.TargetL = lab.L; + linearizationInput.TargetA = lab.A; + linearizationInput.TargetB = lab.B; + } + return result.InkPercentage.ToList(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error occurred while trying to call GetLinearizationMeasurements."); + } + return null; + } + #endregion + + #region Export graph + /// <summary> + /// Exports the graph point to Excel file. + /// </summary> + protected void ExportGraph() + { + SaveFileDialog dlg = new SaveFileDialog(); + try + { + dlg.Title = $"Export excel calibration file for {LiquidType.Name}"; + dlg.Filter = "Excel Files|*.xlsx"; + dlg.DefaultExt = ".xlsx"; + dlg.FileName = $"CData_{LiquidType.Name}_v{LiquidType.Version}.xlsx"; + if (dlg.ShowDialog().Value) + { + List<CalibrationPoint> points = new List<CalibrationPoint>(); + LinearizationPoints.ToList().ForEach(x=> points.Add(ToCalibrationPoint(x))); + BL.Calibration.CalibrationHelper.ExportCalibrationDataToExcel(points, dlg.FileName); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error exporting excel file " + dlg.FileName); + _notification.ShowError("An error occurred while trying to export the calibration data."); + } + } + public CalibrationPoint ToCalibrationPoint(DataPoint point) + { + return new CalibrationPoint() + { + X = point.X, + Y = point.Y, + }; + } + + /// <summary> + /// Applies the calibration data. + /// </summary> + protected void ApplyCalibrationData() + { + if (LinearizationPoints.Count == 0) + return; + + List<CalibrationDataPointVM> points = new List<CalibrationDataPointVM>(); + LinearizationPoints.ToList().ForEach(x => points.Add(new CalibrationDataPointVM(x.X, x.Y))); + ViewModelLocator.MainViewVM.CalibrationDataViewVM.ApplyCalibrationData(LiquidType, points); + } + #endregion + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorConversionViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorConversionViewVM.cs index b68239b4b..95de19f42 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorConversionViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/ColorConversionViewVM.cs @@ -111,6 +111,7 @@ namespace Tango.MachineStudio.RML.ViewModels Color = x.LiquidType.Color, Name = x.LiquidType.Name, LiquidType = x.LiquidType, + MaxNanoliterPerCentimeter = x.MaxNlPerCm, }).ToObservableCollection(); } @@ -309,6 +310,19 @@ namespace Tango.MachineStudio.RML.ViewModels } } + private double GetTotalMaximumLiquidNlPerCMLimit() + { + try + { + var tables = RML.GetActiveProcessGroup().ProcessParametersTables.OrderBy(x => x.TableIndex).ToList(); + return tables.Max(x => x.MaxInkUptake); + } + catch + { + return BrushStop.MAX_INK_UPTAKE; + } + } + private void OnLiquidVolumeChanged() { try @@ -316,7 +330,7 @@ namespace Tango.MachineStudio.RML.ViewModels if (LiquidsCalibrationData == null || _prevent_inverse_conversion) return; //TODO: This is temporary because of out of range volumes. - if (LiquidVolumes.Where(x => x.LiquidType.HasPigment).Sum(x => x.Volume) > 200) + if (LiquidVolumes.Where(x => x.LiquidType.HasPigment).Sum(x => x.NanoliterPerCentimeter) > GetTotalMaximumLiquidNlPerCMLimit()) { IsVolumesOutOfRange = true; return; diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/LiquidVolumeVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/LiquidVolumeVM.cs index 7399d62af..27b811bb6 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/LiquidVolumeVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/LiquidVolumeVM.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.BL.Dispensing; using Tango.BL.Entities; using Tango.Core; using Tango.SharedUI; @@ -47,5 +48,17 @@ namespace Tango.MachineStudio.RML.ViewModels get { return _liquidType; } set { _liquidType = value; RaisePropertyChangedAuto(); } } + + public double MaxNanoliterPerCentimeter { get; set; } + + public double NanoliterPerCentimeter + { + get + { + StandardColorDispensingCalc calc = new StandardColorDispensingCalc(); + return calc.CalculateNanoliterPerCentimeter(Volume, MaxNanoliterPerCentimeter); + } + } + } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs index ee21b9ac3..cadd1fb95 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs @@ -21,12 +21,19 @@ using Tango.MachineStudio.RML.Views; using Tango.PMR.ColorLab; using System.Data.Entity; using Tango.Core.ExtensionMethods; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.ActionLogs; +using Tango.BL.DTO; +using Tango.BL.Enumerations; namespace Tango.MachineStudio.RML.ViewModels { public class MainViewVM : StudioViewModel<IMainView> { private INotificationProvider _notification; + private IAuthenticationProvider _authentication; + private IActionLogManager _actionLogManager; + private RmlDTO _rmlBeforeSave; private ObservablesContext _rmls_context; private ObservablesContext _active_context; @@ -38,6 +45,20 @@ namespace Tango.MachineStudio.RML.ViewModels set { _rmls = value; RaisePropertyChangedAuto(); } } + private ICollectionView _rmlssCollectionView; + /// <summary> + /// Gets or sets the RML collection view. + /// </summary> + public ICollectionView RmlsCollectionView + { + get { return _rmlssCollectionView; } + set + { + _rmlssCollectionView = value; + RaisePropertyChangedAuto(); + } + } + private ObservableCollection<MediaMaterial> _materials; public ObservableCollection<MediaMaterial> Materials { @@ -80,6 +101,13 @@ namespace Tango.MachineStudio.RML.ViewModels set { _fiberSynths = value; RaisePropertyChangedAuto(); } } + private ObservableCollection<SpoolType> _spoolTypes; + public ObservableCollection<SpoolType> SpoolTypes + { + get { return _spoolTypes; } + set { _spoolTypes = value; RaisePropertyChangedAuto(); } + } + private Rml _selectedRML; public Rml SelectedRML { @@ -143,6 +171,30 @@ namespace Tango.MachineStudio.RML.ViewModels set { _colorConversionViewVM = value; RaisePropertyChangedAuto(); } } + private RmlsSpool _selectedSpool; + public RmlsSpool SelectedSpool + { + get { return _selectedSpool; } + set { _selectedSpool = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private ColorCalibrationViewVM _colorCalibrationVM; + public ColorCalibrationViewVM ColorCalibrationVM + { + get { return _colorCalibrationVM; } + set { _colorCalibrationVM = value; RaisePropertyChangedAuto(); } + } + + private String _RMLFilter; + /// <summary> + /// Gets or sets the job filter. + /// </summary> + public String RMLFilter + { + get { return _RMLFilter; } + set { _RMLFilter = value; RaisePropertyChangedAuto(); OnRMLFilterChanged(); } + } + /// <summary> /// Gets or sets the manage RML command. /// </summary> @@ -185,9 +237,21 @@ namespace Tango.MachineStudio.RML.ViewModels public RelayCommand ImportRMLFileCommand { get; set; } - public MainViewVM(INotificationProvider notificationProvider) + /// <summary> + /// Gets or sets the add spool command. + /// </summary> + public RelayCommand AddSpoolCommand { get; set; } + + /// <summary> + /// Gets or sets the remove spool command. + /// </summary> + public RelayCommand RemoveSpoolCommand { get; set; } + + public MainViewVM(INotificationProvider notificationProvider, IAuthenticationProvider authentication, IActionLogManager actionLogManager) { _notification = notificationProvider; + _authentication = authentication; + _actionLogManager = actionLogManager; ManageRmlCommand = new RelayCommand(() => LoadActiveRML(SelectedRML.Guid), () => SelectedRML != null); RemoveRmlCommand = new RelayCommand(RemoveSelectedRml, () => SelectedRML != null); CloneRmlCommand = new RelayCommand(CloneSelectedRml, () => SelectedRML != null); @@ -206,6 +270,9 @@ namespace Tango.MachineStudio.RML.ViewModels ExportRMLFileCommand = new RelayCommand(ExportRmlFile, () => SelectedRML != null && IsFree); ImportRMLFileCommand = new RelayCommand(ImportRmlFile, () => IsFree); + + AddSpoolCommand = new RelayCommand(AddNewSpool); + RemoveSpoolCommand = new RelayCommand(RemoveSpool, () => SelectedSpool != null); } public override void OnApplicationReady() @@ -215,130 +282,177 @@ namespace Tango.MachineStudio.RML.ViewModels private async void LoadRmls() { - if (_rmls_context != null) _rmls_context.Dispose(); + try + { + IsFree = false; - _rmls_context = ObservablesContext.CreateDefault(); - Rmls = await new RmlsCollectionBuilder(_rmls_context).SetAll().WithLiquidFactors().WithMediaProperties().BuildAsync(); + using (_notification.PushTaskItem("Loading Rmls...")) + { + if (_rmls_context != null) _rmls_context.Dispose(); - //Load CCT file names... - var ccts = await _rmls_context.Ccts.Select(x => new - { - x.Guid, - x.FileName - }).ToListAsync(); + _rmls_context = ObservablesContext.CreateDefault(); + Rmls = await new RmlsCollectionBuilder(_rmls_context).SetAll().WithLiquidFactors().WithMediaProperties().BuildAsync(); + //Load CCT file names... + var ccts = await _rmls_context.Ccts.Select(x => new + { + x.Guid, + x.FileName + }).ToListAsync(); - foreach (var rml in Rmls) - { - var cct = ccts.SingleOrDefault(x => x.Guid == rml.CctGuid); + foreach (var rml in Rmls) + { + var cct = ccts.SingleOrDefault(x => x.Guid == rml.CctGuid); - if (cct != null) - { - rml.Cct = new Cct() + if (cct != null) + { + rml.Cct = new Cct() + { + Guid = cct.Guid, + FileName = cct.FileName, + }; + } + } + RmlsCollectionView = CollectionViewSource.GetDefaultView(Rmls); + RmlsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Rml.LastUpdated), ListSortDirection.Descending)); + //RmlsCollectionView.Filter = new Predicate<object>(FilterCollection); + + RmlsCollectionView.Filter = (rml) => { - Guid = cct.Guid, - FileName = cct.FileName, + Rml r = rml as Rml; + return String.IsNullOrWhiteSpace(RMLFilter) + || r.Name.ToLower().Contains(RMLFilter.ToLower()); }; + } } + catch (Exception ex) + { + LogManager.Log(ex, $"Error loading RMLS.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } } private async void LoadActiveRML(String guid) { using (_notification.PushTaskItem("Loading RML...")) { - IsFree = false; - - if (_active_context != null) + try { - _active_context.Dispose(); - } - - _active_context = ObservablesContext.CreateDefault(); + IsFree = false; - CCTS = _active_context.Ccts - .Select(x => new CctModel() + if (_active_context != null) { - Guid = x.Guid, - FileName = x.FileName, + _active_context.Dispose(); + } - }).ToObservableCollection(); + _active_context = ObservablesContext.CreateDefault(); - CCTS.Where(x => String.IsNullOrWhiteSpace(x.FileName)).ToList().ForEach(x => x.FileName = x.Guid); + CCTS = _active_context.Ccts + .Select(x => new CctModel() + { + Guid = x.Guid, + FileName = x.FileName, - LoadRmlProperties(); + }).ToObservableCollection(); - ActiveRML = await new RmlBuilder(_active_context) - .Set(guid) - .WithActiveParametersGroup() - .WithLiquidFactors() - .WithCCT() - .BuildAsync(); + CCTS.Where(x => String.IsNullOrWhiteSpace(x.FileName)).ToList().ForEach(x => x.FileName = x.Guid); - if (ActiveRML.Cct != null) - { - SelectedCCT = CCTS.SingleOrDefault(x => x.Guid == ActiveRML.Cct.Guid); - } + LoadRmlProperties(); - if (ActiveRML.ProcessParametersTablesGroups.ToList().Count == 0) - { - if (!_notification.ShowQuestion("Could not find any process group for the selected RML. Would you like to create one?")) + ActiveRML = await new RmlBuilder(_active_context) + .Set(guid) + .WithActiveParametersGroup() + .WithLiquidFactors() + .WithCCT() + .WithSpools() + .BuildAsync(); + + if (ActiveRML.Cct != null) { - _notification.ShowError("Cannot load an RML with no process group."); - IsFree = true; - return; + SelectedCCT = CCTS.SingleOrDefault(x => x.Guid == ActiveRML.Cct.Guid); } - else + + if (ActiveRML.ProcessParametersTablesGroups.ToList().Count == 0) { - ProcessParametersTablesGroup group = new ProcessParametersTablesGroup(); - group.Name = "Active Group"; - group.Active = true; - group.ProcessParametersTables.Add(new ProcessParametersTable() + if (!_notification.ShowQuestion("Could not find any process group for the selected RML. Would you like to create one?")) + { + _notification.ShowError("Cannot load an RML with no process group."); + IsFree = true; + return; + } + else { - Name = "Process Table 1", - }); + ProcessParametersTablesGroup group = new ProcessParametersTablesGroup(); + group.Name = "Active Group"; + group.Active = true; + group.ProcessParametersTables.Add(new ProcessParametersTable() + { + Name = "Process Table 1", + }); - group.Rml = ActiveRML; + group.Rml = ActiveRML; - _active_context.ProcessParametersTablesGroups.Add(group); - _active_context.ProcessParametersTables.Add(group.ProcessParametersTables[0]); - await _active_context.SaveChangesAsync(); - LoadActiveRML(ActiveRML.Guid); - return; + _active_context.ProcessParametersTablesGroups.Add(group); + _active_context.ProcessParametersTables.Add(group.ProcessParametersTables[0]); + await _active_context.SaveChangesAsync(); + LoadActiveRML(ActiveRML.Guid); + return; + } } - } - ActiveProcessParametersGroup = ActiveRML.ProcessParametersTablesGroups.ToList().FirstOrDefault(); - ActiveProcessParametersTableView = CollectionViewSource.GetDefaultView(ActiveProcessParametersGroup.ProcessParametersTables); - ActiveProcessParametersTableView.SortDescriptions.Add(new SortDescription(nameof(ProcessParametersTable.TableIndex), ListSortDirection.Ascending)); + ActiveProcessParametersGroup = ActiveRML.ProcessParametersTablesGroups.ToList().FirstOrDefault(); + ActiveProcessParametersTableView = CollectionViewSource.GetDefaultView(ActiveProcessParametersGroup.ProcessParametersTables); + ActiveProcessParametersTableView.SortDescriptions.Add(new SortDescription(nameof(ProcessParametersTable.TableIndex), ListSortDirection.Ascending)); - CalibrationDataViewVM = new CalibrationDataViewVM(_notification); - LiquidTypesRmls = ActiveRML.LiquidTypesRmls; + CalibrationDataViewVM = new CalibrationDataViewVM(_notification); + LiquidTypesRmls = ActiveRML.LiquidTypesRmls; - foreach (var liquidTypeRml in LiquidTypesRmls) - { - CalibrationDataVM catVM = new CalibrationDataVM(liquidTypeRml.LiquidType); - - if (liquidTypeRml.DefaultCatData != null) + foreach (var liquidTypeRml in LiquidTypesRmls) { - catVM.CalibrationPoints = liquidTypeRml.GetCalibrationData().CalibrationPoints.Select(x => new CalibrationDataPointVM(x.X, x.Y)).ToObservableCollection(); + CalibrationDataVM catVM = new CalibrationDataVM(liquidTypeRml.LiquidType); + + if (liquidTypeRml.DefaultCatData != null) + { + catVM.CalibrationPoints = liquidTypeRml.GetCalibrationData().CalibrationPoints.Select(x => new CalibrationDataPointVM(x.X, x.Y)).ToObservableCollection(); + } + + CalibrationDataViewVM.LiquidsCalibrationData.Add(catVM); } - CalibrationDataViewVM.LiquidsCalibrationData.Add(catVM); - } + ColorConversionViewVM = new ColorConversionViewVM(_notification) + { + RML = ActiveRML, + CCT = SelectedCCT, + LiquidsCalibrationData = CalibrationDataViewVM.LiquidsCalibrationData, + LiquidTypesRmls = LiquidTypesRmls, + }; - ColorConversionViewVM = new ColorConversionViewVM(_notification) - { - RML = ActiveRML, - CCT = SelectedCCT, - LiquidsCalibrationData = CalibrationDataViewVM.LiquidsCalibrationData, - LiquidTypesRmls = LiquidTypesRmls, - }; + ColorCalibrationVM = new ColorCalibrationViewVM(_notification) + { + RML = ActiveRML, + LiquidTypes = LiquidTypesRmls.Where(x => x.LiquidType.HasPigment).ToList().Select(y => y.LiquidType).ToList(), + }; - View.NavigateTo(RmlNavigationView.RmlView); + _rmlBeforeSave = RmlDTO.FromObservable(ActiveRML); - InvalidateRelayCommands(); + View.NavigateTo(RmlNavigationView.RmlView); - IsFree = true; + InvalidateRelayCommands(); + + IsFree = true; + } + catch (Exception ex) + { + LogManager.Log($"Error loading RML '{ActiveRML.Name}'..."); + _notification.ShowError($"Error loading the selected thread.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } } } @@ -371,6 +485,7 @@ namespace Tango.MachineStudio.RML.ViewModels LinearMassDensityUnits = _active_context.LinearMassDensityUnits.ToObservableCollection(); FiberShapes = _active_context.FiberShapes.ToObservableCollection(); FiberSynths = _active_context.FiberSynths.ToObservableCollection(); + SpoolTypes = _active_context.SpoolTypes.ToObservableCollection(); } private async void AddNewRml() @@ -400,8 +515,10 @@ namespace Tango.MachineStudio.RML.ViewModels Rml rml = new Rml(); rml.Name = name; + rml.DisplayName = name; + rml.QualificationDate = DateTime.UtcNow; rml.Manufacturer = "Twine"; - rml.Code = Rmls.Max(x => x.Code) + 1; + rml.Code = Rmls.Count > 0 ? Rmls.Max(x => x.Code) + 1 : 1; rml.MediaMaterial = Materials.FirstOrDefault(); rml.MediaPurpose = Purposes.FirstOrDefault(); rml.MediaCondition = Conditions.FirstOrDefault(); @@ -423,6 +540,9 @@ namespace Tango.MachineStudio.RML.ViewModels _active_context.ProcessParametersTables.Add(group.ProcessParametersTables[0]); _active_context.Rmls.Add(rml); await _active_context.SaveChangesAsync(); + + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlCreated, _authentication.CurrentUser, rml.Name, rml, "Rml created using Machine Studio."); + LoadActiveRML(rml.Guid); IsFree = true; @@ -432,25 +552,64 @@ namespace Tango.MachineStudio.RML.ViewModels private async void RemoveSelectedRml() { - if (_notification.ShowQuestion("Removing the selected RML will result in the loss of all related process parameters and default calibration data. Are you sure you want to delete the selected RML?")) + if (_notification.ShowQuestion("Removing the selected thread will result in the loss of all related process parameters and default calibration data. Are you sure you want to delete the selected RML?")) { - IsFree = false; - using (_notification.PushTaskItem("Removing RML...")) { try { + IsFree = false; + + var rml_jobs = await _rmls_context.Jobs.Where(x => x.RmlGuid == SelectedRML.Guid).Include(x => x.Machine).OrderBy(x => x.Machine.SerialNumber).ToListAsync(); + + if (rml_jobs.Count > 0) + { + var vm = new RmlDeleteDialogViewVM(SelectedRML, Rmls.ToList(), rml_jobs.ToList()); + _notification.ShowModalDialog<RmlDeleteDialogViewVM, RmlDeleteDialogView>(vm, (x) => { }, () => { }); + + if (!vm.DialogResult) + { + return; + } + + //Perform actions... + using (var db = ObservablesContext.CreateDefault()) + { + foreach (var jobAction in vm.JobsActions) + { + if (jobAction.Action == RmlDeleteDialogViewVM.RmlDeleteJobAction.Delete) + { + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.JobDeleted, _authentication.CurrentUser.Guid, jobAction.Job.Name, jobAction.Job.Guid, $"Job deleted due to RML '{SelectedRML.Name}' being removed."); + await jobAction.Job.DeleteCascadeAsync(db); + } + else if (jobAction.Action == RmlDeleteDialogViewVM.RmlDeleteJobAction.Change) + { + var job = await db.Jobs.SingleOrDefaultAsync(x => x.Guid == jobAction.Job.Guid); + job.RmlGuid = jobAction.TargetRml.Guid; + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.JobSaved, _authentication.CurrentUser.Guid, jobAction.Job.Name, jobAction.Job.Guid, $"Job RML changed to '{jobAction.TargetRml.Name}' due to RML '{SelectedRML.Name}' being removed."); + } + } + + await db.SaveChangesAsync(); + } + } + await SelectedRML.DeleteCascadeAsync(_rmls_context); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlDeleted, _authentication.CurrentUser, SelectedRML.Name, SelectedRML, "RML deleted from Machine Studio."); + LoadRmls(); } catch (Exception ex) { - LogManager.Log(ex, $"Error removing selected RML {SelectedRML.Name}."); - _notification.ShowError($"An error occurred while trying to remove the selected RML.\n{ex.Message}"); + LogManager.Log(ex, $"Error removing selected RML {SelectedRML?.Name}."); + _notification.ShowError($"An error occurred while trying to remove the selected RML.\n{ex.FlattenMessage()}"); + LoadRmls(); + } + finally + { + IsFree = true; } } - - IsFree = true; } } @@ -468,15 +627,18 @@ namespace Tango.MachineStudio.RML.ViewModels using (var context = ObservablesContext.CreateDefault()) { - var rml = await new RmlBuilder(context).Set(SelectedRML.Guid).WithActiveParametersGroup().WithLiquidFactors().BuildAsync(); + var rml = await new RmlBuilder(context).Set(SelectedRML.Guid).WithActiveParametersGroup().WithLiquidFactors().WithSpools().BuildAsync(); Rml cloned = new Rml(); - rml.MapPrimitivesWithStrings(cloned); + rml.MapPropertiesTo(cloned, MappingFlags.NoReferenceTypes); cloned.Code = Rmls.Max(x => x.Code) + 1; cloned.Guid = Guid.NewGuid().ToString(); cloned.ID = 0; cloned.Name = name; + cloned.DisplayName = name; + cloned.RmlQualificationLevel = RmlQualifications.Provisional; + cloned.QualificationDate = DateTime.UtcNow; ProcessParametersTablesGroup group = new ProcessParametersTablesGroup(); group.Name = rml.GetActiveProcessGroup().Name; @@ -502,8 +664,19 @@ namespace Tango.MachineStudio.RML.ViewModels cloned.LiquidTypesRmls.Add(l); } + foreach (var spool in rml.RmlsSpools) + { + RmlsSpool s = new RmlsSpool(); + spool.MapPropertiesTo(s, MappingFlags.ValueTypesOnly); + s.RmlGuid = cloned.Guid; + s.SpoolTypeGuid = spool.SpoolTypeGuid; + cloned.RmlsSpools.Add(s); + } + context.Rmls.Add(cloned); await context.SaveChangesAsync(); + + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlCreated, _authentication.CurrentUser, cloned.Name, cloned, "RML cloned from Machine Studio."); } LoadRmls(); @@ -558,6 +731,11 @@ namespace Tango.MachineStudio.RML.ViewModels ActiveProcessParametersTableView.Refresh(); } + private void OnRMLFilterChanged() + { + RmlsCollectionView.Refresh(); + } + private void RemoveLiquidFactor(LiquidTypesRml liquidFactor) { if (_notification.ShowQuestion("Removing this liquid factor will remove the liquid type association with the RML and will drop the calibration data. Are you sure?")) @@ -648,6 +826,11 @@ namespace Tango.MachineStudio.RML.ViewModels ActiveRML.LastUpdated = DateTime.UtcNow; + if (_rmlBeforeSave.QualificationLevel != ActiveRML.QualificationLevel) + { + ActiveRML.QualificationDate = DateTime.UtcNow; + } + if (SelectedCCT != null) { if (SelectedCCT.IsNew) @@ -665,18 +848,26 @@ namespace Tango.MachineStudio.RML.ViewModels } } + var rmlAfter = RmlDTO.FromObservable(ActiveRML); + await _active_context.SaveChangesAsync(); + + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlSaved, _authentication.CurrentUser, _rmlBeforeSave.Name, _rmlBeforeSave, rmlAfter, "RML saved using Machine Studio."); + + _rmlBeforeSave = rmlAfter; + + LoadActiveRML(ActiveRML.Guid); } } catch (Exception ex) { LogManager.Log(ex, $"Error saving RML {ActiveRML.Name}"); - _notification.ShowError($"An error occurred while trying to save the current RML.\n{ex.Message}"); + _notification.ShowError($"An error occurred while trying to save the current RML.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; } - - LoadActiveRML(ActiveRML.Guid); - - IsFree = true; } private void BackToRmls() @@ -692,6 +883,12 @@ namespace Tango.MachineStudio.RML.ViewModels String file = GetCCTFileOpen(); if (file != null) { + if (CCTS.ToList().Exists(x => x.FileName == Path.GetFileName(file))) + { + _notification.ShowError("The selected CCT file already exists on the database. Please select the CCT file from the dropdown box."); + return; + } + CctModel cctModel = new CctModel(); cctModel.Guid = Guid.NewGuid().ToString(); cctModel.IsNew = true; @@ -804,6 +1001,8 @@ namespace Tango.MachineStudio.RML.ViewModels var rmlFile = await Rml.FromRmlFile(db, json); db.Rmls.Add(rmlFile); + + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlImported, _authentication.CurrentUser, rmlFile.Name, rmlFile, "RML imported from Machine Studio."); } await db.SaveChangesAsync(); @@ -860,5 +1059,26 @@ namespace Tango.MachineStudio.RML.ViewModels } #endregion + + #region Spools + + private void AddNewSpool() + { + _active_context.RmlsSpools.Add(new RmlsSpool() + { + Rml = ActiveRML, + }); + } + + private void RemoveSpool() + { + if (SelectedSpool != null) + { + _active_context.RmlsSpools.Remove(SelectedSpool); + ActiveRML.RmlsSpools.Remove(SelectedSpool); + } + } + + #endregion } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/RmlDeleteDialogViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/RmlDeleteDialogViewVM.cs new file mode 100644 index 000000000..b4c6c6274 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/RmlDeleteDialogViewVM.cs @@ -0,0 +1,95 @@ +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.SharedUI; + +namespace Tango.MachineStudio.RML.ViewModels +{ + public class RmlDeleteDialogViewVM : DialogViewVM + { + public enum RmlDeleteJobAction + { + Delete, + Change + } + + public class RmlDeleteJob : ExtendedObject + { + public Job Job { get; set; } + public Machine Machine { get; set; } + private RmlDeleteJobAction _action; + + public RmlDeleteJobAction Action + { + get { return _action; } + set { _action = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsDelete)); } + } + + public bool IsDelete + { + get { return Action == RmlDeleteJobAction.Delete; } + } + + + public Rml TargetRml { get; set; } + + public override string ToString() + { + return $"{Machine.SerialNumber} => {Job.Name} => {Action} {(Action == RmlDeleteJobAction.Change ? $" => {TargetRml.Name}" : String.Empty)}"; + } + } + + private List<Job> _jobsToDelete; + + private List<RmlDeleteJob> _jobsActions; + public List<RmlDeleteJob> JobsActions + { + get { return _jobsActions; } + set { _jobsActions = value; RaisePropertyChangedAuto(); } + } + + public Rml Rml { get; set; } + + public List<Rml> Rmls { get; set; } + + public List<RmlDeleteJobAction> Actions { get; set; } + + public RmlDeleteDialogViewVM(Rml rml, List<Rml> rmls, List<Job> jobsToDelete) + { + Rml = rml; + Rmls = rmls.Where(x => x.Guid != rml.Guid).ToList(); + _jobsToDelete = jobsToDelete; + JobsActions = new List<RmlDeleteJob>(); + + Actions = new List<RmlDeleteJobAction>() + { + RmlDeleteJobAction.Delete, + RmlDeleteJobAction.Change + }; + } + + public override void OnShow() + { + base.OnShow(); + + List<RmlDeleteJob> list = new List<RmlDeleteJob>(); + + foreach (var job in _jobsToDelete) + { + RmlDeleteJob deleteJob = new RmlDeleteJob(); + deleteJob.Job = job; + deleteJob.Action = RmlDeleteJobAction.Delete; + deleteJob.Machine = job.Machine; + deleteJob.TargetRml = Rmls.FirstOrDefault(x => x.Guid != Rml.Guid); + + list.Add(deleteJob); + } + + JobsActions = list; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml new file mode 100644 index 000000000..116500f80 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml @@ -0,0 +1,213 @@ +<UserControl x:Class="Tango.MachineStudio.RML.Views.ColorCalibrationView" + 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.MachineStudio.RML.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.RML" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:oxy="http://oxyplot.org/wpf" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="1200" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EmptyStringToNullConverter x:Key="EmptyStringToNullConverter" /> + <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> + <converters:BooleanToVisibilityInverseConverter x:Key="BooleanToVisibilityInverseConverter"/> + </UserControl.Resources> + + <Grid> + <DockPanel> + <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="20 10"> + <TextBlock FontSize="16" HorizontalAlignment="Left" VerticalAlignment="Center">Liquid Type:</TextBlock> + <ComboBox Margin="40 0 0 0" MinWidth="180" HorizontalAlignment="Left" ItemsSource="{Binding LiquidTypes}" + SelectedItem="{Binding LiquidType}" DisplayMemberPath="Name" + Style="{StaticResource TransparentComboBoxStyle}" FontSize="16"></ComboBox> + </StackPanel> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1.1*"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <DockPanel Grid.Column="0"> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0 0 0 " Padding="5" CornerRadius="5" Height="40" VerticalAlignment="Top"> + <Border.Effect> + <DropShadowEffect Opacity="0.4" /> + </Border.Effect> + <Grid> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 4 0 0" FontSize="16" Padding="0">LIQUID FACTOR</TextBlock> + </Grid> + </Border> + <Grid Margin="10 20 0 10"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + + + <Grid HorizontalAlignment="Left" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="20 0 10 0"> + <StackPanel Orientation="Vertical"> + <Button HorizontalAlignment="Left" Padding="6" Width="120" Background="{StaticResource TransparentBackgroundBrush200}" Command="{Binding ImportDataCommand}" ToolTip="Import data to calculate Liquid factor." Margin="0 0 10 4" BorderBrush="{StaticResource TransparentBackgroundBrush200}"> + <TextBlock FontSize="14" Foreground="{StaticResource MainWindow.Foreground}">IMPORT DATA</TextBlock> + </Button> + <DataGrid HorizontalAlignment="Left" VerticalScrollBarVisibility ="Auto" MaxHeight="280" SelectionUnit="FullRow" BorderBrush="{StaticResource DarkGrayBrush }" BorderThickness="1" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="False" ItemsSource="{Binding Measurements}" Margin="0 0 0 50"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + </Style> + </DataGrid.CellStyle> + <DataGrid.Resources> + <Style x:Key="CellNumericUpDown" TargetType="{x:Type mahapps:NumericUpDown}" BasedOn="{StaticResource {x:Type mahapps:NumericUpDown}}"> + <Setter Property="FrameworkElement.HorizontalAlignment" Value="Stretch"/> + <Setter Property="HorizontalContentAlignment" Value="Left"/> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/> + <Setter Property="Focusable" Value="false"/> + <Setter Property="IsHitTestVisible" Value="false"/> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/> + <Setter Property="FrameworkElement.VerticalAlignment" Value="Top"/> + <Setter Property="VerticalContentAlignment" Value="Center"/> + <Setter Property="FrameworkElement.MinHeight" Value="0"/> + <Setter Property="HideUpDownButtons" Value="true"/> + </Style> + <Style x:Key="EditableCellNumericUpDown" TargetType="{x:Type mahapps:NumericUpDown}" BasedOn="{StaticResource {x:Type mahapps:NumericUpDown}}"> + <Setter Property="FrameworkElement.HorizontalAlignment" Value="Stretch"/> + <Setter Property="HorizontalContentAlignment" Value="Left"/> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/> + <Setter Property="FrameworkElement.VerticalAlignment" Value="Top"/> + <Setter Property="VerticalContentAlignment" Value="Center"/> + <Setter Property="FrameworkElement.MinHeight" Value="0"/> + </Style> + </DataGrid.Resources> + <DataGrid.Columns> + <mahapps:DataGridNumericUpDownColumn Header="Ink nl/cm" Minimum="0" Maximum="100000" Binding="{Binding Ink}" HideUpDownButtons="True" Width="1*" ElementStyle="{StaticResource CellNumericUpDown}" EditingElementStyle="{StaticResource EditableCellNumericUpDown}" /> + <mahapps:DataGridNumericUpDownColumn Header="L" Minimum="0" Maximum="100" Binding="{Binding L}" HideUpDownButtons="True" Width="1*" ElementStyle="{StaticResource CellNumericUpDown}" EditingElementStyle="{StaticResource EditableCellNumericUpDown}"/> + <mahapps:DataGridNumericUpDownColumn Header="A" Minimum="-128" Maximum="127" Binding="{Binding A}" HideUpDownButtons="True" Width="1*" ElementStyle="{StaticResource CellNumericUpDown}" EditingElementStyle="{StaticResource EditableCellNumericUpDown}" /> + <mahapps:DataGridNumericUpDownColumn Header="B" Minimum="-128" Maximum="127" Binding="{Binding B}" HideUpDownButtons="True" Width="1*" ElementStyle="{StaticResource CellNumericUpDown}" EditingElementStyle="{StaticResource EditableCellNumericUpDown}" /> + </DataGrid.Columns> + </DataGrid> + + </StackPanel> + </Grid> + + <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="1" Grid.Row="0" Margin="10 0 0 0"> + <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="0" BorderBrush="{StaticResource DarkGrayBrush}" CornerRadius="5"> + <oxy:Plot Title="{Binding LiquidTypeName}" TitleFontSize="14" x:Name="CalibrationPlot" Margin="0 0 10 0" Background="Transparent" > + <oxy:Plot.Series > + <oxy:LineSeries ItemsSource="{Binding Points}" Color="#73B6EC" MarkerFill="SteelBlue" MarkerType="Circle" /> + <oxy:LineSeries ItemsSource="{Binding TargetPoints}" Color="#E14141" /> + </oxy:Plot.Series> + <oxy:Plot.Axes> + <oxy:LinearAxis Position="Bottom" Title = "nl/cm" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" /> + <oxy:LinearAxis Position="Left" Title = "Lab" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" Minimum="{Binding From}" Maximum="{Binding To}" /> + </oxy:Plot.Axes> + </oxy:Plot> + </Border> + </Grid> + + <Border Grid.Row="1" Grid.ColumnSpan="2" BorderBrush="{StaticResource BlueBrush100}" BorderThickness="0" CornerRadius="5" Margin="20 0 20 0"> + <StackPanel Orientation="Vertical" Grid.Row="0" Margin="2 5 0 0"> + <Border BorderThickness="0.5" CornerRadius="4" BorderBrush="{StaticResource DarkGrayBrush}" Visibility="{Binding HasError, Converter={StaticResource BooleanToVisibilityInverseConverter}}" Height="Auto" Margin="0 6 0 0"> + <TextBlock FontSize="16" Foreground="{StaticResource MainWindow.Foreground}" FontWeight="SemiBold" Visibility="{Binding HasError, Converter={StaticResource BooleanToVisibilityInverseConverter}}" Margin="10" > + <Run FontSize="16"> Factor: </Run> + <Run Text="{Binding Factor,StringFormat='#.0000'}" Foreground="{StaticResource BlueBrush100}"></Run> + </TextBlock> + </Border> + + <Border BorderThickness="0.5" CornerRadius="4" BorderBrush="{StaticResource DarkGrayBrush}" Visibility="{Binding HasError, Converter={StaticResource BooleanToVisibilityConverter}}" Height="Auto" Margin="0 6 0 0"> + <TextBlock FontSize="16" Foreground="{StaticResource MainWindow.Foreground}" FontWeight="SemiBold" Visibility="{Binding HasError, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="10" > + <Run FontSize="14"> Warning: </Run> + <Run Foreground="{StaticResource RedBrush300}" Text="{Binding ErrorMessage}" ></Run> + </TextBlock> + </Border> + </StackPanel> + </Border> + <Button Grid.Row="2" Grid.Column="1" Margin="0 20 20 0" VerticalAlignment="Bottom" HorizontalAlignment="Right" Background="{StaticResource TransparentBackgroundBrush200}" MinWidth="160" BorderBrush="{StaticResource TransparentBackgroundBrush200}" Command="{Binding CreateGraphCommand}" > + <TextBlock FontSize="14" Foreground="{StaticResource MainWindow.Foreground}">GET LIQUID FACTOR</TextBlock> + </Button> + </Grid> + </DockPanel> + <DockPanel Grid.Column="1"> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0 0 0 " Padding="5" CornerRadius="5" Height="40" VerticalAlignment="Top"> + <Border.Effect> + <DropShadowEffect Opacity="0.4" /> + </Border.Effect> + <Grid> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 4 0 0" FontSize="16" Padding="0">LINEARIZATION</TextBlock> + </Grid> + </Border> + <Grid Margin="10 20 20 10"> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid Grid.Column="0" Margin="10 0 0 0"> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Margin="0 0 0 0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*"></ColumnDefinition> + <ColumnDefinition Width="1*"></ColumnDefinition> + </Grid.ColumnDefinitions> + + <Border Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="0" BorderBrush="{StaticResource DarkGrayBrush}" CornerRadius="5"> + <oxy:Plot Title="{Binding LiquidTypeName}" TitleFontSize="14" x:Name="LABLinearizationPlot" Margin="0 0 10 0" Background="Transparent" LegendPlacement="Inside" LegendPosition="TopRight" LegendOrientation="Vertical" LegendFontSize="9" LegendItemAlignment="Left" LegendLineSpacing="3" Foreground="{StaticResource Dialog.Foreground}"> + <oxy:Plot.Series > + <oxy:LineSeries ItemsSource="{Binding LPoints}" Color="LawnGreen" Title="L" StrokeThickness="1.5"/> + <oxy:LineSeries ItemsSource="{Binding APoints}" Color="#E14141" Title="A" StrokeThickness="1.5"/> + <oxy:LineSeries ItemsSource="{Binding BPoints}" Color="#73B6EC" Title="B" StrokeThickness="1.5"/> + </oxy:Plot.Series> + <oxy:Plot.Axes> + <oxy:LinearAxis Position="Bottom" Title = "Ink%" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" AxisTitleDistance ="12" Minimum="0" Maximum="100" /> + <oxy:LinearAxis Position="Left" Title = "LAB" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" Minimum="{Binding LabMinVal}" Maximum="{Binding LabMaxVal}" MinorStep="10" /> + </oxy:Plot.Axes> + </oxy:Plot> + </Border> + + <Border Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" BorderThickness="0" BorderBrush="{StaticResource DarkGrayBrush}" CornerRadius="5" > + <oxy:Plot Title="{Binding LiquidTypeName}" TitleFontSize="14" x:Name="LinearizationPlot" Margin="0 0 0 0" Background="Transparent" LegendPlacement="Inside" LegendPosition="RightTop" LegendOrientation="Vertical" > + <oxy:Plot.Series > + <oxy:LineSeries ItemsSource="{Binding LinearizationPoints}" Color="#73B6EC" MarkerFill="SteelBlue" MarkerType="Circle"/> + </oxy:Plot.Series> + <oxy:Plot.Axes> + <oxy:LinearAxis Position="Bottom" Title = "In Ink" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" Minimum="0" Maximum="100"/> + <oxy:LinearAxis Position="Left" Title = "Out Ink" MajorGridlineStyle="Solid" MinorGridlineStyle="Dot" IsZoomEnabled="True" Minimum="0" Maximum="100"/> + </oxy:Plot.Axes> + </oxy:Plot> + </Border> + </Grid> + <StackPanel Orientation="Horizontal" Grid.Row="1" Margin="0 20 10 0" HorizontalAlignment="Right"> + <Button Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource TransparentBackgroundBrush200}" Padding="6" MinWidth="130" Command="{Binding ApplyCalibrationDataCommand}" ToolTip="Apply the calibration data to the current RML calibration tables."> + <TextBlock FontSize="14" Foreground="{StaticResource MainWindow.Foreground}">APPLY TO RML</TextBlock> + </Button> + <Button Margin="20 0 0 0" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource TransparentBackgroundBrush200}" Padding="6" ToolTip="Export to excel" MinWidth="130" Command="{Binding ExportGraphCommand}"> + <TextBlock FontSize="14" Foreground="{StaticResource MainWindow.Foreground}">EXPORT TO FILE</TextBlock> + </Button> + <Button Margin="20 0 0 0" VerticalAlignment="Bottom" HorizontalAlignment="Right" Background="{StaticResource TransparentBackgroundBrush200}" MinWidth="180" BorderBrush="{StaticResource TransparentBackgroundBrush200}" Command="{Binding CreateLinearizationGraphCommand}" > + <TextBlock FontSize="14" Foreground="{StaticResource MainWindow.Foreground}">CREATE LINEARIZATION GRAPH</TextBlock> + </Button> + </StackPanel> + </Grid> + + </Grid> + </DockPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml.cs new file mode 100644 index 000000000..c29bb68fb --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ColorCalibrationView.xaml.cs @@ -0,0 +1,42 @@ +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.MachineStudio.RML.ViewModels; + +namespace Tango.MachineStudio.RML.Views +{ + /// <summary> + /// Interaction logic for ColorCalibrationView.xaml + /// </summary> + public partial class ColorCalibrationView : UserControl + { + public ColorCalibrationView() + { + InitializeComponent(); + this.Loaded += ColorCalibrationView_Loaded; + } + + private void ColorCalibrationView_Loaded(object sender, RoutedEventArgs e) + { + if(DataContext is ColorCalibrationViewVM) + { + ColorCalibrationViewVM vm = (ColorCalibrationViewVM)DataContext; + vm.PlotControl = CalibrationPlot; + vm.LinearizationPlotControl = LinearizationPlot; + vm.LABLinearizationPlotControl = LABLinearizationPlot; + vm.Loading(); + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.xaml new file mode 100644 index 000000000..aec12aa63 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.xaml @@ -0,0 +1,59 @@ +<UserControl x:Class="Tango.MachineStudio.RML.Views.HeadCleaningParametersView" + 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.MachineStudio.RML.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.RML" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.RML.Views" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EmptyStringToNullConverter x:Key="EmptyStringToNullConverter" /> + </UserControl.Resources> + + <Grid> + <DockPanel> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0" Padding="5" CornerRadius="5"> + <Border.Effect> + <DropShadowEffect Opacity="0.4" /> + </Border.Effect> + <Grid> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16" Padding="2">HEAD CLEANING PARAMETERS</TextBlock> + </Grid> + </Border> + + <Grid> + <StackPanel Orientation="Horizontal"> + <DockPanel Grid.Column="1" Margin="25" HorizontalAlignment="Left" Width="400"> + <materialDesign:Card> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">CLEANER</TextBlock> + <controls:TableGrid RowHeight="25" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="Margin" Value="0 3 0 0"></Setter> + </Style> + </controls:TableGrid.Resources> + <TextBlock Text="Cleaner Flow:" VerticalAlignment="Center"></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.CleanerFlow,Mode=TwoWay}" Minimum="0" Maximum="10000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Arc Head Cleaning Motor Speed:" VerticalAlignment="Center"></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.ArcHeadCleaningMotorSpeed,Mode=TwoWay}" Minimum="0" Maximum="10000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + </controls:TableGrid> + </DockPanel> + </StackPanel> + </materialDesign:Card> + </DockPanel> + </StackPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.xaml.cs new file mode 100644 index 000000000..8d036efa5 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/HeadCleaningParametersView.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.MachineStudio.RML.Views +{ + /// <summary> + /// Interaction logic for SpoolsView.xaml + /// </summary> + public partial class HeadCleaningParametersView : UserControl + { + public HeadCleaningParametersView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/MainView.xaml index ab5207722..e52ac4ece 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/MainView.xaml @@ -9,7 +9,7 @@ xmlns:local="clr-namespace:Tango.MachineStudio.RML.Views" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - <Grid> + <Grid IsEnabled="{Binding IsFree}"> <controls:NavigationControl x:Name="navigationControl" TransitionType="Slide"> <local:RmlsView /> <local:RmlView/> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ProcessParametersView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ProcessParametersView.xaml index b85fd2c12..03bf65522 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ProcessParametersView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ProcessParametersView.xaml @@ -32,7 +32,7 @@ <DropShadowEffect Opacity="0.4" /> </Border.Effect> <Grid> - <TextBlock HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16">ACTIVE PROCESS GROUP</TextBlock> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16">ACTIVE PROCESS GROUP</TextBlock> <Button ToolTip="Add new table" Style="{StaticResource MaterialDesignFlatButton}" Height="Auto" Width="30" HorizontalAlignment="Right" Padding="0" Command="{Binding AddProcessParametersTableCommand}"> <materialDesign:PackIcon Kind="Plus" Foreground="#0AC30A" Width="24" Height="24" /> </Button> @@ -70,7 +70,7 @@ <DataTemplate> <DockPanel> <TextBlock IsHitTestVisible="False" Margin="0 5 0 5" Text="{Binding Name}" FontSize="11"></TextBlock> - <mahapps:NumericUpDown HorizontalAlignment="Right" Minimum="0" Margin="0 0 5 0" HideUpDownButtons="True" HorizontalContentAlignment="Right" Maximum="10000" StringFormat="0.0" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}"></mahapps:NumericUpDown> + <mahapps:NumericUpDown HorizontalAlignment="Right" Minimum="0" Margin="0 0 5 0" HideUpDownButtons="True" HorizontalContentAlignment="Right" Maximum="10000" StringFormat="{Binding StringFormat}" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}"></mahapps:NumericUpDown> </DockPanel> </DataTemplate> </editors:ParameterizedEditor.DoubleTemplate> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.xaml new file mode 100644 index 000000000..7745848c1 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.xaml @@ -0,0 +1,82 @@ +<UserControl x:Class="Tango.MachineStudio.RML.Views.RmlDeleteDialogView" + 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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:vm="clr-namespace:Tango.MachineStudio.RML.ViewModels" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:local="clr-namespace:Tango.MachineStudio.RML.Views" + mc:Ignorable="d" + d:DesignHeight="400" d:DesignWidth="700" Height="600" Width="900" Background="{StaticResource Dialog.Background}" d:DataContext="{d:DesignInstance Type=vm:RmlDeleteDialogViewVM, IsDesignTimeCreatable=False}" Foreground="{StaticResource Dialog.Foreground}"> + + <UserControl.Resources> + <converters:BooleanToVisibilityInverseConverter x:Key="BooleanToVisibilityInverseConverter" /> + </UserControl.Resources> + + <Grid Margin="10"> + <DockPanel> + <Grid DockPanel.Dock="Top"> + <StackPanel Orientation="Horizontal"> + <Grid> + <materialDesign:PackIcon Kind="Alert" Foreground="{StaticResource OrangeBrush}" Width="42" Height="42" /> + </Grid> + <TextBlock Margin="20 0 0 0" VerticalAlignment="Center" FontSize="22"> + <Run>DELETE</Run> + <Run></Run> + <Run Text="{Binding Rml.Name}"></Run> + </TextBlock> + </StackPanel> + </Grid> + + <Grid DockPanel.Dock="Bottom"> + <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" DockPanel.Dock="Bottom"> + <Button Command="{Binding CloseCommand}" Width="140" Height="40" Margin="0 0 10 0"> + CANCEL + </Button> + <Button Command="{Binding OKCommand}" IsDefault="True" Width="140" Height="40"> + DELETE + </Button> + </StackPanel> + </Grid> + + <Grid> + <DockPanel Margin="0 10 0 0"> + <TextBlock DockPanel.Dock="Top" Margin="5"> + <Run>The following jobs must be removed or change thread type before the selected thread can be deleted.</Run> + </TextBlock> + <DataGrid Margin="0 10 0 10" SelectionUnit="FullRow" SelectionMode="Single" ItemsSource="{Binding JobsActions}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False"> + <DataGrid.Columns> + <DataGridTextColumn Header="MACHINE" Width="Auto" Binding="{Binding Machine.SerialNumber}" IsReadOnly="True" /> + <DataGridTextColumn Header="JOB" Width="200" Binding="{Binding Job.Name}" IsReadOnly="True" /> + <DataGridComboBoxColumn Header="ACTION" Width="100" SelectedItemBinding="{Binding Action}"> + <DataGridComboBoxColumn.ElementStyle> + <Style TargetType="{x:Type ComboBox}"> + <Setter Property="ItemsSource" Value="{Binding Path=DataContext.Actions, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> + </Style> + </DataGridComboBoxColumn.ElementStyle> + <DataGridComboBoxColumn.EditingElementStyle> + <Style TargetType="{x:Type ComboBox}"> + <Setter Property="ItemsSource" Value="{Binding Path=DataContext.Actions, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> + </Style> + </DataGridComboBoxColumn.EditingElementStyle> + </DataGridComboBoxColumn> + <DataGridComboBoxColumn Header="TARGET RML" SelectedItemBinding="{Binding TargetRml}" Width="1*" DisplayMemberPath="Name"> + <DataGridComboBoxColumn.ElementStyle> + <Style TargetType="{x:Type ComboBox}"> + <Setter Property="ItemsSource" Value="{Binding Path=DataContext.Rmls, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> + </Style> + </DataGridComboBoxColumn.ElementStyle> + <DataGridComboBoxColumn.EditingElementStyle> + <Style TargetType="{x:Type ComboBox}"> + <Setter Property="ItemsSource" Value="{Binding Path=DataContext.Rmls, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> + </Style> + </DataGridComboBoxColumn.EditingElementStyle> + </DataGridComboBoxColumn> + </DataGrid.Columns> + </DataGrid> + </DockPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.xaml.cs new file mode 100644 index 000000000..96254c03a --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlDeleteDialogView.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.MachineStudio.RML.Views +{ + /// <summary> + /// Interaction logic for RmlDeleteDialogView.xaml + /// </summary> + public partial class RmlDeleteDialogView : UserControl + { + public RmlDeleteDialogView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlView.xaml index 50f6a6297..b6c91f066 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlView.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.MachineStudio.RML" + xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" xmlns:observables="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" xmlns:shapes="clr-namespace:Tango.SharedUI.Shapes;assembly=Tango.SharedUI" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" @@ -19,6 +20,7 @@ <UserControl.Resources> <converters:ColorToIntegerConverter x:Key="ColorToIntegerConverter"></converters:ColorToIntegerConverter> + <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter"/> </UserControl.Resources> <Grid Margin="20"> @@ -28,7 +30,7 @@ <Button Style="{StaticResource MaterialDesignFlatButton}" Height="Auto" Command="{Binding BackToRmlsCommand}"> <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="{StaticResource DarkGrayBrush200}" ToolTip="Back to RML list" /> </Button> - <TextBlock Text="{Binding ActiveRML.Name}" VerticalAlignment="Center" Margin="10 0 0 0" FontSize="34"></TextBlock> + <TextBlock MaxWidth="350" Text="{Binding ActiveRML.Name}" VerticalAlignment="Center" Margin="10 0 0 0" FontSize="30" TextWrapping="Wrap"></TextBlock> </StackPanel> <Button HorizontalAlignment="Right" Width="170" Height="45" Margin="0 0 20 0" VerticalAlignment="Center" Command="{Binding SaveCommand}"> @@ -54,10 +56,25 @@ <Grid> <DockPanel> <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">PROPERTIES</TextBlock> - <controls:TableGrid RowHeight="35" Margin="20 0"> + <controls:TableGrid RowHeight="35" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="Margin" Value="0 3 0 0"></Setter> + </Style> + </controls:TableGrid.Resources> <TextBlock Text="Name:" ></TextBlock> <TextBox Text="{Binding ActiveRML.Name,UpdateSourceTrigger=PropertyChanged}"></TextBox> + <TextBlock Text="Display Name:" ></TextBlock> + <TextBox Text="{Binding ActiveRML.DisplayName,UpdateSourceTrigger=PropertyChanged}"></TextBox> + + <TextBlock Text="Head Type:" ></TextBlock> + <ComboBox ItemsSource="{Binding Source={x:Type enumerations:HeadTypes},Converter={StaticResource EnumToItemsSourceConverter}}" SelectedValue="{Binding ActiveRML.RmlHeadType}" SelectedValuePath="Value" DisplayMemberPath="DisplayName"></ComboBox> + + <TextBlock Text="Qualification Level:" ></TextBlock> + <ComboBox ItemsSource="{Binding Source={x:Type enumerations:RmlQualifications},Converter={StaticResource EnumToItemsSourceConverter}}" SelectedValue="{Binding ActiveRML.RmlQualificationLevel}" SelectedValuePath="Value" DisplayMemberPath="DisplayName"></ComboBox> + <TextBlock Text="Manufacturer:" ></TextBlock> <TextBox Text="{Binding ActiveRML.Manufacturer}"></TextBox> @@ -138,28 +155,34 @@ <Setter Property="Padding" Value="20,2"></Setter> </Style> </TabControl.Resources> - <TabItem Header="PROCESS PARAMETERS" Margin="-100 0 0 0 "> + <TabItem Header="PROCESS PARAMETERS" Margin="-100 0 0 0" mahapps:ControlsHelper.HeaderFontSize="20"> <local:ProcessParametersView x:Name="processParametersView" WidthLilquidFactors="{Binding ElementName=calibrationDataView,Path=ActualWidth}"/> </TabItem> - <TabItem Header="COLOR CONVERSION" Margin="-100 0 0 0 "> + <TabItem Header="THREAD PARAMETERS" Margin="-100 0 0 0" mahapps:ControlsHelper.HeaderFontSize="20"> + <local:ThreadParametersView/> + </TabItem> + <TabItem Header="HEAD CLEANING" Margin="-100 0 0 0" mahapps:ControlsHelper.HeaderFontSize="20"> + <local:HeadCleaningParametersView/> + </TabItem> + <TabItem Header="COLOR CONVERSION" Margin="-100 0 0 0 " mahapps:ControlsHelper.HeaderFontSize="20"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"></ColumnDefinition> <ColumnDefinition Width="260"></ColumnDefinition> </Grid.ColumnDefinitions> <DockPanel> - <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0" Padding="5" CornerRadius="5"> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0" Padding="7" CornerRadius="5"> <Border.Effect> <DropShadowEffect Opacity="0.4" /> </Border.Effect> <Grid> - <TextBlock HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16">COLOR CONVERSION</TextBlock> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16">COLOR CONVERSION</TextBlock> </Grid> </Border> <local:ColorConversionView x:Name="colorConversionView" Margin="0 0 0 0" Grid.Column="0" DataContext="{Binding ColorConversionViewVM}"/> </DockPanel> <DockPanel Grid.Column="1"> - <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="16 0" Padding="5" CornerRadius="5"> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="16 0" Padding="7" CornerRadius="5"> <Border.Effect> <DropShadowEffect Opacity="0.4" /> </Border.Effect> @@ -191,7 +214,9 @@ </UniformGrid> <TextBlock Margin="0 40 0 0" Text="Color Conversion Version:" HorizontalAlignment="Center"></TextBlock> - <mahapps:NumericUpDown Minimum="1" Maximum="2" Value="{Binding ActiveRML.ColorConversionVersion}" HorizontalContentAlignment="Center" Background="Transparent" BorderBrush="{StaticResource DimGrayBrush}" HasDecimals="False" Margin="0 5 0 0" /> + <mahapps:NumericUpDown Minimum="1" Maximum="4" Value="{Binding ActiveRML.ColorConversionVersion}" HorizontalContentAlignment="Center" Background="Transparent" BorderBrush="{StaticResource DimGrayBrush}" HasDecimals="False" Margin="0 5 0 0" /> + + <CheckBox ToolTip="Use the color conversion engine to generate gradients" IsChecked="{Binding ActiveRML.UseColorLibGradients}" HorizontalAlignment="Center" Margin="0 40 0 0">Enable Gradient Generation</CheckBox> </StackPanel> </StackPanel> </Grid> @@ -200,6 +225,12 @@ </DockPanel> </Grid> </TabItem> + <TabItem Header="SPOOLS" Margin="-100 0 0 0" mahapps:ControlsHelper.HeaderFontSize="20"> + <local:SpoolsView/> + </TabItem> + <TabItem Header="COLOR CALIBRATION" Margin="-100 0 0 0" mahapps:ControlsHelper.HeaderFontSize="20"> + <local:ColorCalibrationView DataContext="{Binding ColorCalibrationVM}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/> + </TabItem> </TabControl> </Grid> <Grid Grid.Row="1"> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml index 288f00a3d..b1a1f4aa5 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/RmlsView.xaml @@ -18,10 +18,14 @@ <converters:ColorToIntegerConverter x:Key="ColorToIntegerConverter"></converters:ColorToIntegerConverter> </UserControl.Resources> - <Grid> + <Grid IsEnabled="{Binding IsFree}"> <DockPanel Margin="100 100 100 50" MaxWidth="1200"> <Grid DockPanel.Dock="Top"> <Image Source="../Images/threads.png" Width="300" Margin="10" /> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 10 30"> + <materialDesign:PackIcon Kind="Magnify" Width="26" Height="26"/> + <TextBox Width="300" materialDesign:HintAssist.Hint="Search by name" Text="{Binding RMLFilter,UpdateSourceTrigger=PropertyChanged,Delay=500}"></TextBox> + </StackPanel> </Grid> <Grid DockPanel.Dock="Bottom"> <StackPanel> @@ -74,7 +78,7 @@ </StackPanel> </Grid> <Grid> - <DataGrid Margin="0 0 0 10" BorderBrush="Silver" IsReadOnly="True" BorderThickness="1" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRML}"> + <DataGrid Margin="0 0 0 10" BorderBrush="Silver" IsReadOnly="True" BorderThickness="1" RowHeight="60" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding Rmls}" SelectedItem="{Binding SelectedRML}"> <DataGrid.CellStyle> <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> <Setter Property="BorderThickness" Value="0"/> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.xaml new file mode 100644 index 000000000..6eae05c76 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.xaml @@ -0,0 +1,85 @@ +<UserControl x:Class="Tango.MachineStudio.RML.Views.SpoolsView" + 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.MachineStudio.RML.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.RML" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.RML.Views" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EmptyStringToNullConverter x:Key="EmptyStringToNullConverter" /> + </UserControl.Resources> + + <Grid> + <DockPanel> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0" Padding="5" CornerRadius="5"> + <Border.Effect> + <DropShadowEffect Opacity="0.4" /> + </Border.Effect> + <Grid> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16" Padding="2">SPOOLS</TextBlock> + </Grid> + </Border> + + <Grid> + <DockPanel Grid.Column="1" Margin="25"> + <Grid DockPanel.Dock="Bottom"> + <StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 0 0 0"> + <Button Margin="0 0 10 0" MinWidth="160" Height="50" Background="{StaticResource RedBrush300}" BorderBrush="{StaticResource RedBrush300}" Command="{Binding RemoveSpoolCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Delete" Width="20" Height="20" /> + <TextBlock Margin="5 0 0 0" FontSize="16">DELETE</TextBlock> + </StackPanel> + </Button> + <Button Margin="0 0 0 0" MinWidth="160" Height="50" Background="{StaticResource GreenBrush300}" BorderBrush="{StaticResource GreenBrush300}" Command="{Binding AddSpoolCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Plus" Width="20" Height="20" /> + <TextBlock Margin="5 0 0 0" FontSize="16">NEW SPOOL</TextBlock> + </StackPanel> + </Button> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> + + </StackPanel> + </Grid> + <Grid> + <DataGrid Margin="0 0 0 10" SelectionUnit="FullRow" BorderBrush="{StaticResource borderBrush }" BorderThickness="1" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding ActiveRML.RmlsSpools}" SelectedItem="{Binding SelectedSpool}"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + </Style> + </DataGrid.CellStyle> + <DataGrid.Columns> + <DataGridComboBoxColumn Header="SPOOL TYPE" SelectedItemBinding="{Binding SpoolType}" DisplayMemberPath="Name" Width="Auto"> + <DataGridComboBoxColumn.ElementStyle> + <Style TargetType="ComboBox"> + <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid},Path=DataContext.SpoolTypes}"/> + </Style> + </DataGridComboBoxColumn.ElementStyle> + <DataGridComboBoxColumn.EditingElementStyle> + <Style TargetType="ComboBox"> + <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid},Path=DataContext.SpoolTypes}"/> + </Style> + </DataGridComboBoxColumn.EditingElementStyle> + </DataGridComboBoxColumn> + <DataGridTextColumn Header="ROTATIONS PER PASSAGE" Binding="{Binding RotationsPerPassage,Converter={StaticResource EmptyStringToNullConverter}}" Width="Auto" /> + <DataGridTextColumn Header="MAX LENGTH" Binding="{Binding Length,Converter={StaticResource EmptyStringToNullConverter}}" Width="Auto" /> + <DataGridTextColumn Header="BACKING RATE" Binding="{Binding BackingRate,Converter={StaticResource EmptyStringToNullConverter}}" Width="Auto" /> + <DataGridTextColumn Header="BOTTOM BACKING RATE" Binding="{Binding BottomBackingRate,Converter={StaticResource EmptyStringToNullConverter}}" Width="Auto" /> + </DataGrid.Columns> + </DataGrid> + </Grid> + </DockPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.xaml.cs new file mode 100644 index 000000000..6e363681c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/SpoolsView.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.MachineStudio.RML.Views +{ + /// <summary> + /// Interaction logic for SpoolsView.xaml + /// </summary> + public partial class SpoolsView : UserControl + { + public SpoolsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.xaml new file mode 100644 index 000000000..c083e9b02 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.xaml @@ -0,0 +1,121 @@ +<UserControl x:Class="Tango.MachineStudio.RML.Views.ThreadParametersView" + 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.MachineStudio.RML.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.RML" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.RML.Views" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <converters:EmptyStringToNullConverter x:Key="EmptyStringToNullConverter" /> + </UserControl.Resources> + + <Grid> + <DockPanel> + <Border DockPanel.Dock="Top" Background="{StaticResource TransparentBackgroundBrush200}" Margin="20 0" Padding="5" CornerRadius="5"> + <Border.Effect> + <DropShadowEffect Opacity="0.4" /> + </Border.Effect> + <Grid> + <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20 0 0 0" FontSize="16" Padding="2">THREAD PARAMETERS</TextBlock> + </Grid> + </Border> + + <Grid> + <StackPanel Orientation="Horizontal"> + <DockPanel Grid.Column="1" Margin="25" HorizontalAlignment="Left" Width="400"> + <materialDesign:Card> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">FEEDER</TextBlock> + <controls:TableGrid RowHeight="25" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="Margin" Value="0 3 0 0"></Setter> + </Style> + </controls:TableGrid.Resources> + <TextBlock Text="Feeder P:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.FeederP,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Feeder I:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.FeederI,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Feeder D:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.FeederD,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + </controls:TableGrid> + </DockPanel> + + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">PULLER</TextBlock> + <controls:TableGrid RowHeight="25" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="Margin" Value="0 3 0 0"></Setter> + </Style> + </controls:TableGrid.Resources> + <TextBlock Text="Puller P:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.PullerP,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Puller I:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.PullerI,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Puller D:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.PullerD,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + </controls:TableGrid> + </DockPanel> + + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">WINDER</TextBlock> + <controls:TableGrid RowHeight="25" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + <Setter Property="Margin" Value="0 3 0 0"></Setter> + </Style> + </controls:TableGrid.Resources> + <TextBlock Text="Winder P:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.WinderP,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Winder I:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.WinderI,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + + <TextBlock Text="Winder D:" ></TextBlock> + <mahapps:NumericUpDown Value="{Binding ActiveRML.WinderD,Mode=TwoWay}" Minimum="-100000" Maximum="1000000" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" InterceptMouseWheel="True" HasDecimals="False" HorizontalContentAlignment="Left"></mahapps:NumericUpDown> + </controls:TableGrid> + </DockPanel> + </StackPanel> + </materialDesign:Card> + </DockPanel> + + <DockPanel Grid.Column="1" Margin="25" HorizontalAlignment="Left" Width="400"> + <materialDesign:Card> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" Margin="20 10 0 10" FontSize="16">ROCKERS</TextBlock> + <controls:TableGrid RowHeight="25" Margin="20 0" MakeFirstColumnVerticalAlignmentBottom="False"> + <controls:TableGrid.Resources> + <Style TargetType="TextBlock"> + <Setter Property="VerticalAlignment" Value="Center"></Setter> + </Style> + </controls:TableGrid.Resources> + <TextBlock Text="Bypass Rockers:" ></TextBlock> + <ToggleButton IsChecked="{Binding ActiveRML.BypassRockers,Mode=TwoWay}" HorizontalAlignment="Right" ></ToggleButton> + </controls:TableGrid> + </DockPanel> + </StackPanel> + </materialDesign:Card> + </DockPanel> + </StackPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.xaml.cs new file mode 100644 index 000000000..aa63e48fb --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/Views/ThreadParametersView.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.MachineStudio.RML.Views +{ + /// <summary> + /// Interaction logic for SpoolsView.xaml + /// </summary> + public partial class ThreadParametersView : UserControl + { + public ThreadParametersView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/App.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/App.xaml new file mode 100644 index 000000000..01a064b05 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/App.xaml @@ -0,0 +1,12 @@ +<Application x:Class="Tango.MachineStudio.Sites.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.MachineStudio.Common;component/Resources/MaterialDesign.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.MachineStudio.Common;component/Themes/LightThemeColors.xaml" /> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> + </Application.Resources> +</Application> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Contracts/IMainView.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Contracts/IMainView.cs new file mode 100644 index 000000000..67f57b28c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Contracts/IMainView.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.SharedUI; + +namespace Tango.MachineStudio.Sites.Contracts +{ + public enum SitesNavigationView + { + SitesView, + SiteDetailsView, + } + + public interface IMainView : IView + { + void NavigateTo(SitesNavigationView view); + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/machine_site.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/machine_site.png Binary files differnew file mode 100644 index 000000000..9b22e53b0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/machine_site.png diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/site.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/site.png Binary files differnew file mode 100644 index 000000000..2fee5fafa --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Images/site.png diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Models/SiteModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Models/SiteModel.cs new file mode 100644 index 000000000..007f8a3ad --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Models/SiteModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.SharedUI.Components; + +namespace Tango.MachineStudio.Sites.Models +{ + public class SiteModel : Site + { + public String Organization { get; set; } + public int MachineCount { get; set; } + public int CatalogCount { get; set; } + public int ThreadCount { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/AssemblyInfo.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a6eebb5a8 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +[assembly: AssemblyTitle("Tango - Machine Studio Sites Module")] +[assembly: AssemblyVersion("1.0.0.1737")] + +[assembly: ComVisible(false)] + +[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/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Resources.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Resources.Designer.cs new file mode 100644 index 000000000..ecefa25e7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/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.MachineStudio.Sites.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.MachineStudio.Sites.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/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Resources.resx b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/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/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Settings.Designer.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Settings.Designer.cs new file mode 100644 index 000000000..5fa894ceb --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/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.MachineStudio.Sites.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/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Settings.settings b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/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/MachineStudio/Modules/Tango.MachineStudio.Sites/SitesModule.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/SitesModule.cs new file mode 100644 index 000000000..96d3aed49 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/SitesModule.cs @@ -0,0 +1,62 @@ +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.MachineStudio.Common; +using Tango.MachineStudio.Sites.Views; +using Tango.SharedUI.Helpers; + +namespace Tango.MachineStudio.Sites +{ + [StudioModule(20)] + public class SitesModule : StudioModuleBase + { + public override string Name + { + get + { + return "Sites"; + } + } + + public override string Description + { + get + { + return "Manage organizations sites and their common machine properties."; + } + } + + public override BitmapSource Image + { + get + { + return ResourceHelper.GetImageFromResources("Images/site.png"); + } + } + + public override Type MainViewType + { + get + { + return typeof(MainView); + } + } + + public override Permissions Permission + { + get + { + return Permissions.RunRMLModule; + } + } + + public override void Dispose() + { + + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Tango.MachineStudio.Sites.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Tango.MachineStudio.Sites.csproj new file mode 100644 index 000000000..ea9162ce2 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Tango.MachineStudio.Sites.csproj @@ -0,0 +1,177 @@ +<?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>{18A27902-9881-4556-8163-F6DF2236A14D}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.MachineStudio.Sites</RootNamespace> + <AssemblyName>Tango.MachineStudio.Sites</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\Machine Studio\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\Machine Studio\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="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="MahApps.Metro, Version=1.5.0.23, Culture=neutral, PublicKeyToken=f4fb5a3c4d1e5b4f, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignColors, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignColors.1.1.2\lib\net45\MaterialDesignColors.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignThemes.Wpf, Version=2.3.1.953, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath> + </Reference> + <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> + </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\MahApps.Metro.1.5.0\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> + <Compile Include="Contracts\IMainView.cs" /> + <Compile Include="Models\SiteModel.cs" /> + <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="ViewModels\SiteDetailsViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="SitesModule.cs" /> + <Compile Include="Views\SiteDetailsView.xaml.cs"> + <DependentUpon>SiteDetailsView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\SitesView.xaml.cs"> + <DependentUpon>SitesView.xaml</DependentUpon> + </Compile> + <Page Include="App.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Views\MainView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\SiteDetailsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\SitesView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <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> + <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> + <Resource Include="Images\machine_site.png" /> + </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.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.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.Transport\Tango.Transport.csproj"> + <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> + <Name>Tango.Transport</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.MachineStudio.Common\Tango.MachineStudio.Common.csproj"> + <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project> + <Name>Tango.MachineStudio.Common</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\site.png" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModelLocator.cs new file mode 100644 index 000000000..c06ae05e7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModelLocator.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.MachineStudio.Sites.ViewModels; + +namespace Tango.MachineStudio.Sites +{ + public static class ViewModelLocator + { + /// <summary> + /// Initializes a new instance of the ViewModelLocator class. + /// </summary> + static ViewModelLocator() + { + TangoIOC.Default.Register<MainViewVM>(); + } + + public static MainViewVM MainViewVM + { + get + { + return TangoIOC.Default.GetInstance<MainViewVM>(); + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..5db5e004d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/MainViewVM.cs @@ -0,0 +1,220 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.ActionLogs; +using Tango.BL.Builders; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.Core.Threading; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Common.Authentication; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Sites.Contracts; +using Tango.MachineStudio.Sites.Models; + +namespace Tango.MachineStudio.Sites.ViewModels +{ + public class MainViewVM : StudioViewModel<IMainView> + { + private ObservablesContext _db; + private INotificationProvider _notification; + private IAuthenticationProvider _authentication; + private IActionLogManager _actionLogManager; + private ActionTimer _filter_timer; + + private List<SiteModel> _sites; + public List<SiteModel> Sites + { + get { return _sites; } + set { _sites = value; RaisePropertyChangedAuto(); } + } + + private SiteModel _selectedSite; + public SiteModel SelectedSite + { + get { return _selectedSite; } + set { _selectedSite = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _filter; + public String Filter + { + get { return _filter; } + set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private SiteDetailsViewVM _siteDetailsViewVM; + public SiteDetailsViewVM SiteDetailsViewVM + { + get { return _siteDetailsViewVM; } + set { _siteDetailsViewVM = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand AddSiteCommand { get; set; } + + public RelayCommand RemoveSiteCommand { get; set; } + + public RelayCommand ManageSiteCommand { get; set; } + + public RelayCommand BackToSitesCommand { get; set; } + + public MainViewVM(INotificationProvider notificationProvider, IAuthenticationProvider authentication, IActionLogManager actionLogManager) + { + _notification = notificationProvider; + _authentication = authentication; + _actionLogManager = actionLogManager; + _filter_timer = new ActionTimer(TimeSpan.FromMilliseconds(500)); + + ManageSiteCommand = new RelayCommand(() => LoadSelectedSite(), () => SelectedSite != null); + BackToSitesCommand = new RelayCommand(() => { View.NavigateTo(SitesNavigationView.SitesView); }); + AddSiteCommand = new RelayCommand(AddNewSite); + RemoveSiteCommand = new RelayCommand(RemoveSelectedSite, () => SelectedSite != null); + } + + private async void RemoveSelectedSite() + { + if (!_notification.ShowQuestion("Are you sure you wish to remove the selected site?")) return; + + try + { + using (_notification.PushTaskItem("Removing site...")) + { + IsFree = false; + await Task.Factory.StartNew(() => + { + var site = _db.Sites.SingleOrDefault(x => x.Guid == SelectedSite.Guid); + site.Delete(_db); + _db.SaveChanges(); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.SiteDeleted, _authentication.CurrentUser, site.Name, site, "Site deleted using Machine Studio."); + Sites.Remove(SelectedSite); + LoadSites(); + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error removing site."); + _notification.ShowError($"Error removing site.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private async void AddNewSite() + { + try + { + String name = _notification.ShowTextInput("Enter site name", "name"); + if (String.IsNullOrWhiteSpace(name)) return; + + using (_notification.PushTaskItem("Creating site...")) + { + IsFree = false; + SiteDetailsViewVM = new SiteDetailsViewVM(); + SiteDetailsViewVM.Saved += SiteDetailsViewVM_Saved; + await SiteDetailsViewVM.Init(SelectedSite?.Guid, _notification, _authentication, _actionLogManager, true, name); + View.NavigateTo(SitesNavigationView.SiteDetailsView); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error creating site."); + _notification.ShowError($"Error creating site.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private async void LoadSelectedSite() + { + try + { + using (_notification.PushTaskItem("Loading site details...")) + { + IsFree = false; + SiteDetailsViewVM = new SiteDetailsViewVM(); + SiteDetailsViewVM.Saved += SiteDetailsViewVM_Saved; + await SiteDetailsViewVM.Init(SelectedSite.Guid, _notification, _authentication, _actionLogManager, false); + View.NavigateTo(SitesNavigationView.SiteDetailsView); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading site details."); + _notification.ShowError($"Error loading site details.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private void SiteDetailsViewVM_Saved(object sender, EventArgs e) + { + OnFilterChanged(); + View.NavigateTo(SitesNavigationView.SitesView); + } + + private void OnFilterChanged() + { + if (Filter != null) + { + _filter_timer.ResetReplace(() => + { + try + { + LoadSites(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading sites list."); + } + }); + } + } + + private void LoadSites() + { + using (_notification.PushTaskItem("Loading sites...")) + { + Sites = (from site in _db.Sites + join organization in _db.Organizations on site.OrganizationGuid equals organization.Guid + join sites_rmls in _db.SitesRmls on site.Guid equals sites_rmls.SiteGuid into rmls + join sites_catalogs in _db.SitesCatalogs on site.Guid equals sites_catalogs.SiteGuid into catalogs + join sites_machines in _db.Machines on site.Guid equals sites_machines.SiteGuid into machines + where Filter == null || Filter == "" || site.Name.ToLower().StartsWith(Filter.ToLower()) || organization.Name.ToLower().StartsWith(Filter.ToLower()) + select new + { + Site = site, + OrganizationName = organization.Name, + ThreadCount = rmls.Count(x => x.SiteGuid == site.Guid), + CatalogCount = catalogs.Count(x => x.SiteGuid == site.Guid), + MachineCount = machines.Count(x => x.SiteGuid == site.Guid) + }).Distinct().ToList().DistinctBy(x => x.Site.Guid).Select(x => new SiteModel() + { + Guid = x.Site.Guid, + ID = x.Site.ID, + Name = x.Site.Name, + Description = x.Site.Description, + ThreadCount = x.ThreadCount, + CatalogCount = x.CatalogCount, + MachineCount = x.MachineCount, + Organization = x.OrganizationName, + }).ToList(); + } + } + + public override void OnApplicationReady() + { + _db = ObservablesContext.CreateDefault(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/SiteDetailsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/SiteDetailsViewVM.cs new file mode 100644 index 000000000..cacda1e8d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/ViewModels/SiteDetailsViewVM.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.SharedUI; +using Tango.SharedUI.Components; +using System.Data.Entity; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.ActionLogs; +using Tango.BL.DTO; +using Tango.BL.Builders; + +namespace Tango.MachineStudio.Sites.ViewModels +{ + public class SiteDetailsViewVM : ViewModel + { + private ObservablesContext _db; + private INotificationProvider _notification; + private IAuthenticationProvider _authentication; + private IActionLogManager _actionLogManager; + private bool _isNew; + private SiteDTO _siteBeforeSave; + + public event EventHandler Saved; + + private Site _site; + public Site Site + { + get { return _site; } + set { _site = value; RaisePropertyChangedAuto(); } + } + + private List<Organization> _organizations; + public List<Organization> Organizations + { + get { return _organizations; } + set { _organizations = value; RaisePropertyChangedAuto(); } + } + + private SelectedObjectCollection<Rml> _rmls; + public SelectedObjectCollection<Rml> Rmls + { + get { return _rmls; } + set { _rmls = value; RaisePropertyChangedAuto(); } + } + + private SelectedObjectCollection<ColorCatalog> _catalogs; + public SelectedObjectCollection<ColorCatalog> Catalogs + { + get { return _catalogs; } + set { _catalogs = value; RaisePropertyChangedAuto(); } + } + + private List<Machine> _machines; + public List<Machine> Machines + { + get { return _machines; } + set { _machines = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand SaveCommand { get; set; } + + public SiteDetailsViewVM() + { + SaveCommand = new RelayCommand(Save, () => IsFree); + } + + public async Task Init(String siteGuid, INotificationProvider notification, IAuthenticationProvider authentication, IActionLogManager actionLogManager, bool isNew, string newSiteName = null) + { + _notification = notification; + _authentication = authentication; + _actionLogManager = actionLogManager; + + _db = ObservablesContext.CreateDefault(); + Organizations = await _db.Organizations.ToListAsync(); + + if (isNew) + { + Site = new Site(); + Site.Name = newSiteName; + Site.Description = "My site description"; + _db.Sites.Add(Site); + + _isNew = true; + } + else + { + _isNew = false; + Site = await new SiteBuilder(_db).Set(siteGuid) + .WithSiteCatalogs() + .WithCatalogs() + .WithSiteRmls() + .WithRmls() + .WithOrganization() + .BuildAsync(); + } + + Machines = await _db.Machines.Where(x => x.SiteGuid == Site.Guid).Include(x => x.Organization).ToListAsync(); + + var rmls = await _db.Rmls.OrderBy(x => x.Name).ToListAsync(); + var catalogs = await _db.ColorCatalogs.OrderBy(x => x.Name).ToListAsync(); + + Rmls = new SelectedObjectCollection<Rml>(rmls.ToObservableCollection(), Site.SitesRmls.Select(x => x.Rml).ToObservableCollection()); + Catalogs = new SelectedObjectCollection<ColorCatalog>(catalogs.ToObservableCollection(), Site.SitesCatalogs.Select(x => x.ColorCatalog).ToObservableCollection()); + + _siteBeforeSave = SiteDTO.FromObservable(Site); + } + + private async void Save() + { + try + { + if (!Site.Validate(_db)) + { + _notification.ShowError(String.Join("\n", Site.ValidationErrors)); + return; + } + + IsFree = false; + + using (_notification.PushTaskItem("Saving site details...")) + { + //Check if site organization has changed and there are no machines that belongs to this site but different organization. + if (_db.Machines.Any(x => x.SiteGuid == Site.Guid && x.OrganizationGuid != Site.OrganizationGuid)) + { + throw new InvalidOperationException($"One or more machines belongs to this site but not to '{Site.Organization.Name}' organization."); + } + + //Remove site rmls. + Site.SitesRmls.ToList().Where(x => !Rmls.SynchedSource.ToList().Exists(y => y.Guid == x.RmlGuid)).ToList().ForEach(x => _db.SitesRmls.Remove(x)); + Site.SitesCatalogs.ToList().Where(x => !Catalogs.SynchedSource.ToList().Exists(y => y.Guid == x.ColorCatalogGuid)).ToList().ForEach(x => _db.SitesCatalogs.Remove(x)); + + foreach (var selectedRml in Rmls.SynchedSource.Where(x => !Site.SitesRmls.ToList().Exists(y => y.RmlGuid == x.Guid))) + { + _db.SitesRmls.Add(new SitesRml() { SiteGuid = Site.Guid, RmlGuid = selectedRml.Guid }); + } + + foreach (var selectedCatalog in Catalogs.SynchedSource.Where(x => !Site.SitesCatalogs.ToList().Exists(y => y.ColorCatalogGuid == x.Guid))) + { + _db.SitesCatalogs.Add(new SitesCatalog() { SiteGuid = Site.Guid, ColorCatalogGuid = selectedCatalog.Guid }); + } + + await _db.SaveChangesAsync(); + + if (_isNew) + { + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.SiteCreated, _authentication.CurrentUser, Site.Name, Site, "Site created using Machine Studio."); + } + else + { + SiteDTO siteAfter = SiteDTO.FromObservable(Site); + _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.SiteSaved, _authentication.CurrentUser, _siteBeforeSave.Name, _siteBeforeSave, siteAfter, "Site saved using Machine Studio."); + _siteBeforeSave = siteAfter; + } + } + _db.Dispose(); + Saved?.Invoke(this, new EventArgs()); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error saving site details."); + _notification.ShowError($"Error saving site details.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml new file mode 100644 index 000000000..4ca82c4f7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml @@ -0,0 +1,19 @@ +<UserControl x:Class="Tango.MachineStudio.Sites.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:local="clr-namespace:Tango.MachineStudio.Sites.Views" + xmlns:vm="clr-namespace:Tango.MachineStudio.Sites.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.Sites" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + <Grid IsEnabled="{Binding IsFree}"> + <controls:NavigationControl x:Name="navigationControl" TransitionType="Slide"> + <local:SitesView /> + <local:SiteDetailsView/> + </controls:NavigationControl> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml.cs new file mode 100644 index 000000000..c4f9995ce --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/MainView.xaml.cs @@ -0,0 +1,36 @@ +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.MachineStudio.Sites.Contracts; + +namespace Tango.MachineStudio.Sites.Views +{ + /// <summary> + /// Interaction logic for MainView.xaml + /// </summary> + public partial class MainView : UserControl, IMainView + { + public MainView() + { + InitializeComponent(); + TangoIOC.Default.Register<IMainView>(this); + } + + public void NavigateTo(SitesNavigationView view) + { + navigationControl.NavigateTo(view.ToString()); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.xaml new file mode 100644 index 000000000..182f05be0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.xaml @@ -0,0 +1,170 @@ +<UserControl x:Class="Tango.MachineStudio.Sites.Views.SiteDetailsView" + 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.MachineStudio.Sites.Views" + xmlns:vm="clr-namespace:Tango.MachineStudio.Sites.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.Sites" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <Style x:Key="GridStyle" TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}"> + <Setter Property="AutoGenerateColumns" Value="False"></Setter> + <Setter Property="SelectionMode" Value="Single"></Setter> + <Setter Property="SelectionUnit" Value="FullRow"></Setter> + <Setter Property="IsReadOnly" Value="True"></Setter> + </Style> + + <Style x:Key="CellStyle" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type DataGridCell}"> + <Grid Background="{TemplateBinding Background}"> + <ContentPresenter VerticalAlignment="Center" Margin="8" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="BorderBrush" Value="Cyan"/> + </Trigger> + </Style.Triggers> + </Style> + </UserControl.Resources> + + <Grid Margin="20" DataContext="{Binding SiteDetailsViewVM}" d:DataContext="{d:DesignInstance Type=vm:SiteDetailsViewVM, IsDesignTimeCreatable=False}"> + <DockPanel> + <Grid DockPanel.Dock="Top"> + <StackPanel Orientation="Horizontal"> + <Button Style="{StaticResource MaterialDesignFlatButton}" Height="Auto" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.BackToSitesCommand}"> + <materialDesign:PackIcon Kind="ArrowLeft" Width="50" Height="50" Foreground="#202020" ToolTip="Back to RML list" /> + </Button> + <TextBlock Text="{Binding Site.Name,NotifyOnValidationError=False,ValidatesOnNotifyDataErrors=False}" VerticalAlignment="Center" Margin="10 0 0 0" FontSize="34"></TextBlock> + </StackPanel> + + <StackPanel HorizontalAlignment="Right" Orientation="Horizontal"> + <Button Margin="10 0 0 0" Width="170" Height="45" VerticalAlignment="Center" Command="{Binding SaveCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="ContentSaveAll" Width="24" Height="24" /> + <TextBlock VerticalAlignment="Center" Margin="10 0 0 0">SAVE</TextBlock> + </StackPanel> + </Button> + </StackPanel> + </Grid> + + <Grid Margin="0 20"> + <Grid.RowDefinitions> + <RowDefinition Height="113*"/> + <RowDefinition Height="358*"/> + </Grid.RowDefinitions> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="302*"/> + <ColumnDefinition Width="399*"/> + <ColumnDefinition Width="1179*"/> + </Grid.ColumnDefinitions> + + <Grid Margin="10"> + <materialDesign:Card Background="{DynamicResource MaterialDesignBackground}" VerticalAlignment="Stretch"> + <Border Padding="20"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16">PROPERTIES</TextBlock> + <controls:TableGrid RowHeight="35"> + <TextBlock Text="Name:" ></TextBlock> + <TextBox Text="{Binding Site.Name,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + + <TextBlock Text="Organization:" ></TextBlock> + <ComboBox ItemsSource="{Binding Organizations}" SelectedItem="{Binding Site.Organization}" DisplayMemberPath="Name"></ComboBox> + + <TextBlock Text="Description:" ></TextBlock> + <TextBox Text="{Binding Site.Description,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + </controls:TableGrid> + </DockPanel> + </Border> + </materialDesign:Card> + </Grid> + + <Grid Grid.Column="1" Margin="10"> + + </Grid> + + <Grid Grid.ColumnSpan="3"> + + </Grid> + </Grid> + + <Grid Grid.Row="1" Margin="0 20 0 0"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*"/> + <ColumnDefinition Width="1*"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + + + <DockPanel Margin="10"> + <TextBlock DockPanel.Dock="Top" FontSize="16">SITE RML</TextBlock> + + <materialDesign:Card Margin="0 5 0 0" Background="{DynamicResource MaterialDesignBackground}" VerticalAlignment="Stretch"> + <DataGrid ItemsSource="{Binding Rmls}" Style="{StaticResource GridStyle}" CellStyle="{StaticResource CellStyle}"> + <DataGrid.Columns> + <DataGridTemplateColumn Header="" Width="Auto"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="NAME" IsReadOnly="True" Binding="{Binding Data.Name}" Width="1*" /> + </DataGrid.Columns> + </DataGrid> + </materialDesign:Card> + </DockPanel> + + + <DockPanel Margin="10" Grid.Column="1"> + <TextBlock DockPanel.Dock="Top" FontSize="16" Text="SITE CATALOGS"/> + <materialDesign:Card Margin="0 5 0 0" Background="{DynamicResource MaterialDesignBackground}" VerticalAlignment="Stretch"> + <DataGrid ItemsSource="{Binding Catalogs}" Style="{StaticResource GridStyle}" CellStyle="{StaticResource CellStyle}"> + <DataGrid.Columns> + <DataGridTemplateColumn Header="" Width="Auto"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="NAME" Binding="{Binding Data.Name}" Width="1*" /> + </DataGrid.Columns> + </DataGrid> + </materialDesign:Card> + </DockPanel> + + <DockPanel Margin="10" Grid.Column="2"> + <TextBlock DockPanel.Dock="Top" FontSize="16" Text="SITE MACHINES"/> + <materialDesign:Card Margin="0 5 0 0" Background="{DynamicResource MaterialDesignBackground}" VerticalAlignment="Stretch"> + <DataGrid ItemsSource="{Binding Machines}" Style="{StaticResource GridStyle}" CellStyle="{StaticResource CellStyle}"> + <DataGrid.Columns> + <DataGridTextColumn Header="ORGANIZATION" Binding="{Binding Organization.Name}" Width="Auto" /> + <DataGridTextColumn Header="SERIAL NUMBER" Binding="{Binding SerialNumber}" Width="Auto" /> + <DataGridTextColumn Header="NAME" Binding="{Binding Name}" Width="1*" /> + </DataGrid.Columns> + </DataGrid> + </materialDesign:Card> + </DockPanel> + </Grid> + </Grid> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.xaml.cs new file mode 100644 index 000000000..03e9a2f75 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SiteDetailsView.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.MachineStudio.Sites.Views +{ + /// <summary> + /// Interaction logic for SiteDetailsView.xaml + /// </summary> + public partial class SiteDetailsView : UserControl + { + public SiteDetailsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.xaml new file mode 100644 index 000000000..437003a8a --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.xaml @@ -0,0 +1,76 @@ +<UserControl x:Class="Tango.MachineStudio.Sites.Views.SitesView" + 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.MachineStudio.Sites.Views" + xmlns:vm="clr-namespace:Tango.MachineStudio.Sites.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.Sites" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + mc:Ignorable="d" + d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + <UserControl.Resources> + <converters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter" /> + </UserControl.Resources> + + <Grid> + <DockPanel Margin="100" MaxWidth="1200"> + <Grid DockPanel.Dock="Top"> + <StackPanel Orientation="Horizontal"> + <Image Source="../Images/machine_site.png" Width="350" RenderOptions.BitmapScalingMode="Fant" Margin="10" /> + + <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="0 0 0 10"> + <materialDesign:PackIcon VerticalAlignment="Center" Kind="Magnify" Width="32" Height="32" /> + <TextBox Width="400" FontSize="20" Margin="10 0 0 0" materialDesign:HintAssist.Hint="Name, Organization" Text="{Binding Filter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </StackPanel> + </StackPanel> + </Grid> + <Grid DockPanel.Dock="Bottom" IsEnabled="{Binding IsFree}"> + <StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Left" Margin="0 0 0 0"> + <Button Margin="0 0 10 0" MinWidth="160" Height="50" Background="{StaticResource RedBrush300}" BorderBrush="{StaticResource RedBrush300}" Command="{Binding RemoveSiteCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Delete" Width="20" Height="20" /> + <TextBlock Margin="5 0 0 0" FontSize="16">DELETE</TextBlock> + </StackPanel> + </Button> + <Button Margin="0 0 10 0" MinWidth="160" Height="50" Background="{StaticResource GreenBrush300}" BorderBrush="{StaticResource GreenBrush300}" Command="{Binding AddSiteCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Plus" Width="20" Height="20" /> + <TextBlock Margin="5 0 0 0" FontSize="16">NEW SITE</TextBlock> + </StackPanel> + </Button> + </StackPanel> + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> + <Button Margin="50 0 0 0" MinWidth="200" Height="60" Command="{Binding ManageSiteCommand}"> + <StackPanel Orientation="Horizontal"> + <materialDesign:PackIcon Kind="Pencil" Width="24" Height="24" /> + <TextBlock Margin="10 0 0 0" FontSize="18">EDIT</TextBlock> + </StackPanel> + </Button> + </StackPanel> + </Grid> + <Grid IsEnabled="{Binding IsFree}"> + <controls:DoubleClickDataGrid Style="{StaticResource {x:Type DataGrid}}" DoubleClickCommand="{Binding ManageSiteCommand}" Margin="0 0 0 10" BorderBrush="{StaticResource borderBrush}" IsReadOnly="True" BorderThickness="1" Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding Sites}" SelectedItem="{Binding SelectedSite}"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + </Style> + </DataGrid.CellStyle> + <DataGrid.Columns> + <DataGridTextColumn Header="NAME" Binding="{Binding Name}" Width="Auto" /> + <DataGridTextColumn Header="DESCRIPTION" Binding="{Binding Description}" Width="Auto" /> + <DataGridTextColumn Header="ORGANIZATION" Binding="{Binding Organization}" Width="Auto" /> + <DataGridTextColumn Header="MACHINES" Binding="{Binding MachineCount}" Width="Auto" /> + <DataGridTextColumn Header="THREADS" Binding="{Binding ThreadCount}" Width="Auto" /> + <DataGridTextColumn Header="CATALOGS" Binding="{Binding CatalogCount}" Width="Auto" /> + <DataGridTextColumn Header="LAST UPDATED" Binding="{Binding LastUpdated,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="1*" /> + </DataGrid.Columns> + </controls:DoubleClickDataGrid> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.xaml.cs new file mode 100644 index 000000000..e6a4a6fe6 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/Views/SitesView.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.MachineStudio.Sites.Views +{ + /// <summary> + /// Interaction logic for SitesView.xaml + /// </summary> + public partial class SitesView : UserControl + { + public SitesView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/app.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/app.config new file mode 100644 index 000000000..7b82e5f7c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/app.config @@ -0,0 +1,85 @@ +<?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="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="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="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="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> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/packages.config new file mode 100644 index 000000000..e57143046 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Sites/packages.config @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> + <package id="MahApps.Metro" version="1.5.0" targetFramework="net461" /> + <package id="MaterialDesignColors" version="1.1.2" targetFramework="net461" /> + <package id="MaterialDesignThemes" version="2.3.1.953" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> +</packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config index ed4582d5b..75b63289d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config @@ -22,7 +22,7 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + <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" /> @@ -30,27 +30,27 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" /> + <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.3.0" newVersion="4.0.3.0" /> + <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.2.0" newVersion="4.0.2.0" /> + <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.1.0.0" newVersion="4.1.0.0" /> + <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.2.0" newVersion="4.0.2.0" /> + <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.1.0.0" newVersion="4.1.0.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> @@ -74,7 +74,7 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> + <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> @@ -92,6 +92,10 @@ <assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.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/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs new file mode 100644 index 000000000..2d9a3cfd9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs @@ -0,0 +1,48 @@ +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.MachineStudio.Statistics.Converters +{ + public class CollectionConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value != null && value is System.Collections.IEnumerable) + { + var colection = value as System.Collections.IEnumerable; + var text = new StringBuilder(); + foreach(var val in colection) + { + string visibleText = val.ToString(); + if(val is bool && parameter is string) + { + string[] tokens = (parameter as string).Split(','); + if(tokens.Count() > 1) + { + visibleText = (bool)val == true ? tokens[1] : tokens[0]; + } + } + text.Append(visibleText); + text.Append("/"); + } + string str_text = text.ToString(); + if(str_text.Length > 1) + { + str_text = str_text.Remove(str_text.Length - 1); + } + return str_text; + } + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.cs new file mode 100644 index 000000000..6b5154ce3 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.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.MachineStudio.Statistics.Converters +{ + public class DateTimeToStringFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value != null) + { + return ((TimeSpan)value).ToString(@"hh\:mm\:ss"); + } + else + { + return TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.cs new file mode 100644 index 000000000..cd928d9c9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.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; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class JobLengthConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + if (values != null && values.Count() == 3) + { + double length = (double)values[0]; + double endPoint = (double)values[1]; + double width = (double)values[2]; + var v = Math.Round((endPoint / length) * width, MidpointRounding.AwayFromZero); + + if (double.IsInfinity(v)) + { + return 0d; + } + return v; + } + } + catch { } + + return 0d; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.cs new file mode 100644 index 000000000..3ab013ab3 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.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; + + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class LiquidQuantityToFormatStringConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + string format = ""; + if (parameter is string) + { + format = (string)parameter; + } + + var longValue = System.Convert.ToUInt64(value.ToString()); + double liters_val = (longValue / 1000000000d); + double cc_val = (longValue / 1000000d); + double dispensers_val = (longValue / 130000000d); + string tooltip = String.Format($"Nanoliters: {longValue.ToString(format)}\nCubic Centimeters: {cc_val}\nLiters: {liters_val}\nDispensers: {dispensers_val}"); + return tooltip; + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs new file mode 100644 index 000000000..b36bf608e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using Tango.BL; +using Tango.BL.Enumerations; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class LiquidTypeToColorConverter : IValueConverter + { + private static Dictionary<LiquidTypes,Color> liquidTypes; + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (liquidTypes == null) + { + liquidTypes = new Dictionary<LiquidTypes, Color>(); + + foreach (var type in ObservablesStaticCollections.Instance.LiquidTypes.ToList()) + { + liquidTypes.Add(type.Type, type.LiquidTypeColor); + } + } + + if (value != null) + { + return liquidTypes[(LiquidTypes)value]; + } + + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs new file mode 100644 index 000000000..de002046e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Globalization; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class MidTankLevelToElementHeightConverter : IMultiValueConverter + { + public const double MAX_QUANTITY = 130000000; + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + double parentActualHeight; + Double.TryParse(values[0].ToString(), out parentActualHeight); + double quantity; + Double.TryParse(values[1].ToString(), out quantity); + + double midTankLevel = (double)Math.Min(quantity, MAX_QUANTITY); + double delta = ((midTankLevel / MAX_QUANTITY) * parentActualHeight); + if (quantity > 0 && midTankLevel < (MAX_QUANTITY/10))// if quantity < 10|% set 2 pixel + delta = 2.0; + var test = delta; + return parentActualHeight - delta; + } + catch + { + return 0d; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs new file mode 100644 index 000000000..97f4ec066 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs @@ -0,0 +1,36 @@ +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.MachineStudio.Statistics.Converters +{ + public class NanoLiterToLiterFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + var longValue = System.Convert.ToUInt64(value.ToString()); + double val = (longValue / 1000000000d); + if (parameter is string) + { + string format= (string)parameter; + return val.ToString(format); + } + return val.ToString(); + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs new file mode 100644 index 000000000..f7633a7d0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class StringToBoolYesNoNullConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is bool) + { + return (bool)value ? "Yes" : "No"; + } + return "Null"; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + //throw new NotImplementedException(); + if (value is ComboBoxItem) + { + string str_val = ((ComboBoxItem)value).Content.ToString(); + if (str_val.ToUpper() == "NO") + return false; + if (str_val.ToUpper() == "YES") + return true; + } + return null; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToFirstLetterConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToFirstLetterConverter.cs new file mode 100644 index 000000000..a1c9561b9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/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.MachineStudio.Statistics.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(); + } + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs new file mode 100644 index 000000000..6c4d1347f --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs @@ -0,0 +1,38 @@ +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.MachineStudio.Statistics.Converters +{ + class TooltipLiquidQuantityFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + string format = ""; + if (parameter is string) + { + format = (string)parameter; + } + var longValue = System.Convert.ToUInt64(value.ToString()); + decimal liters_val = (decimal)(longValue / 1000000000d); + decimal cc_val = (decimal)(longValue / 1000000d); + decimal dispensers_val = (decimal)(longValue / 130000000d); + string tooltip = String.Format($"Nanoliters: {longValue.ToString(format)}\nCubic Centimeters: {cc_val}\nLiters: {liters_val}\nDispensers: {dispensers_val}"); + return tooltip; + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs new file mode 100644 index 000000000..f06b9fe60 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class ExcelModel + { + public String ID { get; set; } + public String Machine { get; set; } + public String User { get; set; } + public String JobName { get; set; } + public String Thread { get; set; } + public String Length { get; set; } + public String Source { get; set; } + public String UploadDuration { get; set; } + public String HeatingDuration { get; set; } + public String StartTime { get; set; } + public String IsGradient { get; set; } + public String GR { get; set; } + public String Status { get; set; } + public String EndTime { get; set; } + public String EndPosition { get; set; } + public String Cyan { get; set; } + public String Magenta { get; set; } + public String Yellow { get; set; } + public String Black { get; set; } + public String Transparent { get; set; } + public String Lubricant { get; set; } + public String Cleaner { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs new file mode 100644 index 000000000..83897ca16 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class JobRunModel + { + public JobRun JobRun { get; set; } + + public Machine Machine { get; set; } + + public User User { get; set; } + + public TimeSpan? UploadDuration { get; set; } + + public TimeSpan? HeatingDuration { get; set; } + + public RmlModel Rml { get; set; } + + public void Init() + { + if (JobRun.HeatingStartDate != null) + { + UploadDuration = JobRun.HeatingStartDate - JobRun.StartDate; + } + + if (JobRun.ActualStartDate != null && JobRun.HeatingStartDate != null) + { + HeatingDuration = JobRun.ActualStartDate - JobRun.HeatingStartDate; + } + + + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs new file mode 100644 index 000000000..98b719cae --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs @@ -0,0 +1,45 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; +using Tango.Core.ExtensionMethods; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class JobRunStatisticsModel : JobRun + { + private static Dictionary<String, Machine> _machines = new Dictionary<string, Machine>(); + + public JobRunStatisticsModel() + { + + } + + public JobRunStatisticsModel(JobRun run) + { + run.MapPropertiesTo(this, MappingFlags.NoReferenceTypes); + } + + public Task LoadMachine(ObservablesContext context) + { + return Task.Factory.StartNew(() => + { + if (!_machines.ContainsKey(MachineGuid)) + { + Machine = context.Machines.SingleOrDefault(x => x.Guid == MachineGuid); + _machines.Add(MachineGuid, Machine); + } + else + { + Machine = _machines[MachineGuid]; + } + }); + } + + public Machine Machine { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs new file mode 100644 index 000000000..789779e42 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class RmlModel + { + public string Guid { get; set; } + + public string Name { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs new file mode 100644 index 000000000..b5615e4d1 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs @@ -0,0 +1,319 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; +using Tango.Core; +using System.Windows.Media; +using System.Windows; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class StatisticsValue + { + public string Name { get; set; } + + public object Value { get; set; } + + public string Unit { get; set; } + } + public class MoreValue + { + public string Text { get; set; } + } + + public class StatisticsValueCollection : ExtendedObject + { + private List<Color> _pieColors; + + #region Properties + + private ObservableCollection<StatisticsValue> _statisticsCollection; + + /// <summary> + /// Gets or sets the statistics collection of StatisticsValue object. + /// </summary> + public ObservableCollection<StatisticsValue> StatisticsCollection + { + get { return _statisticsCollection; } + set + { + _statisticsCollection = value; + RaisePropertyChangedAuto(); + } + } + + private List<StatisticsValue> _threadConsumptionPerThread; + /// <summary> + /// Gets or sets the thread consumption per thread list. + /// </summary> + public List<StatisticsValue> ThreadConsumptionPerThread + { + get { return _threadConsumptionPerThread; } + set { _threadConsumptionPerThread = value; RaisePropertyChangedAuto(); } + } + + /// <summary> + /// Gets or sets the thread consumption per thread collection. + /// </summary> + public CompositeCollection ThreadConsumptionPerThreadCollection { get; set; } + + private LabeledSeriesCollection _pieJobSource; + + /// <summary> + /// Gets or sets the pie job source. + /// </summary> + public LabeledSeriesCollection PieJobSource + { + get { return _pieJobSource; } + set { _pieJobSource = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieJobRunStatus; + + /// <summary> + /// Gets or sets the pie job run status. + /// </summary> + public LabeledSeriesCollection PieJobRunStatus + { + get { return _pieJobRunStatus; } + set { _pieJobRunStatus = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieGradientSolid; + + /// <summary> + /// Gets or sets the pie gradient solid. + /// </summary> + public LabeledSeriesCollection PieGradientSolid + { + get { return _pieGradientSolid; } + set { _pieGradientSolid = value; RaisePropertyChangedAuto(); } + } + + private List<TotalLiquidQuantityModel> _liquidQuantities; + + /// <summary> + /// Gets or sets the liquid quantities. + /// </summary> + public List<TotalLiquidQuantityModel> LiquidQuantities + { + get + { + if (_liquidQuantities == null) + { + _liquidQuantities = new List<TotalLiquidQuantityModel>(); + } + return _liquidQuantities; + } + set + { _liquidQuantities = value; RaisePropertyChangedAuto(); } + } + + private ulong _totalLiquidQuantities; + + /// <summary> + /// Gets or sets the total liquid quantities. + /// </summary> + public ulong TotalLiquidQuantities + { + get { return _totalLiquidQuantities; } + set { _totalLiquidQuantities = value; RaisePropertyChangedAuto(); } + } + + #endregion + + public StatisticsValueCollection() + { + StatisticsCollection = new ObservableCollection<StatisticsValue>(); + ThreadConsumptionPerThread = new List<StatisticsValue>(); + ThreadConsumptionPerThreadCollection = new CompositeCollection(); + + _pieColors = new List<Color>(); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["RedBrush500"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["OrangeBrush"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["GreenBrush"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["BlueBrush100"]).Color); + _pieColors.Add(Color.FromRgb(255, 216, 76)); + + + PieJobSource = new LabeledSeriesCollection() + { + Title = "PPC/MS", + SeriesColors = _pieColors, + }; + PieJobRunStatus = new LabeledSeriesCollection() + { + Title = "Failed/Aborted/Completed", + SeriesColors = _pieColors, + }; + PieGradientSolid = new LabeledSeriesCollection() + { + Title = "Gradient/Solid", + SeriesColors = _pieColors, + }; + } + + /// <summary> + /// Cleans all values. + /// </summary> + public void Clean() + { + StatisticsCollection.Clear(); + ThreadConsumptionPerThreadCollection.Clear(); + ThreadConsumptionPerThread.Clear(); + PieJobSource.SeriesCollection.Clear(); + PieJobRunStatus.SeriesCollection.Clear(); + PieGradientSolid.SeriesCollection.Clear(); + } + + /// <summary> + /// Adds the statistics value. + /// </summary> + public void AddStatisticsValue(string name, object value, string unit) + { + StatisticsCollection.Add(new StatisticsValue() { Name = name, Value = value, Unit = unit }); + RaisePropertyChanged("StatisticsCollection"); + } + + /// <summary> + /// Creates the thread consumption per thread. + /// </summary> + public void CreateThreadConsumptionPerThread(List<StatisticsValue> threads) + { + ThreadConsumptionPerThreadCollection.Add(new CollectionContainer() { Collection = threads.Take(threads.Count() > 2 ? 2 : threads.Count()) }); + if (threads.Count() > 2) + { + ThreadConsumptionPerThreadCollection.Add(new CollectionContainer() { Collection = new List<MoreValue>() { new MoreValue() { Text = "More threads ..." } } }); + ThreadConsumptionPerThread = threads.Skip(2).ToList(); + } + + RaisePropertyChanged("ThreadConsumptionPerThreadCollection"); + } + + #region GeneratePieChart + Func<ChartPoint, string> labelPoint = chartPoint => + string.Format("{0} ({1:P})", chartPoint.Y, chartPoint.Participation); + + public void GeneratePieJobSource(int PPCCount, int MSCount) + { + var series = new PieSeries() + { + Title = "PPC", + Values = new ChartValues<int>() { PPCCount }, + Fill = new SolidColorBrush(_pieColors[4]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + + }; + + PieJobSource.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "MS", + Values = new ChartValues<int>() { MSCount }, + Fill = new SolidColorBrush(_pieColors[3]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieJobSource.SeriesCollection.Add(series); + RaisePropertyChanged("PieJobSource"); + } + + public void GeneratePieJobRunStatus(int failedCount, int abortedCount, int completedCount) + { + var series = new PieSeries() + { + Title = "Failed", + Values = new ChartValues<int>() { failedCount }, + Fill = new SolidColorBrush(_pieColors[0]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + + PieJobRunStatus.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Aborted", + Values = new ChartValues<int>() { abortedCount }, + Fill = new SolidColorBrush(_pieColors[1]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint, + + }; + PieJobRunStatus.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Completed", + Values = new ChartValues<int>() { completedCount }, + Fill = new SolidColorBrush(_pieColors[2]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieJobRunStatus.SeriesCollection.Add(series); + + RaisePropertyChanged("PieJobRunStatus"); + } + + public void GeneratePieGradientSolid(int gradientCount, int solidCount) + { + var series = new PieSeries() + { + Title = "Solid", + Values = new ChartValues<int>() { solidCount }, + Fill = new SolidColorBrush(_pieColors[4]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieGradientSolid.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Gradient", + Values = new ChartValues<int>() { gradientCount }, + Fill = new SolidColorBrush(_pieColors[3]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + + }; + + PieGradientSolid.SeriesCollection.Add(series); + + + RaisePropertyChanged("PieGradientSolid"); + } + #endregion + + /// <summary> + /// Generates the statistics liquid quantity and TotalLiquidQuantities. + /// </summary> + public void GenerateStatisticsLiquidQuantity(List<TotalLiquidQuantityModel> liquidQuantities) + { + LiquidQuantities = liquidQuantities; + TotalLiquidQuantities = 0; + + foreach (var item in liquidQuantities) + { + TotalLiquidQuantities += (ulong)item.Quantity; + } + } + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs new file mode 100644 index 000000000..b5e2e9fb7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class TotalLiquidQuantityModel + { + public LiquidTypes LiquidType { get; set; } + public ulong Quantity { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj index 243663c5a..4ce0ea87d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj @@ -38,6 +38,9 @@ <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="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="LiveCharts, Version=0.9.7.0, Culture=neutral, PublicKeyToken=0bc1f845d1ebb8df, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll</HintPath> </Reference> @@ -73,13 +76,38 @@ <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> + <Compile Include="Converters\CollectionConverter .cs" /> + <Compile Include="Converters\DateTimeToStringFormatConverter.cs" /> + <Compile Include="Converters\JobLengthConverter.cs" /> + <Compile Include="Converters\LiquidQuantityToFormatStringConverter.cs" /> + <Compile Include="Converters\LiquidTypeToColorConverter.cs" /> + <Compile Include="Converters\MidTankLevelToElementHeightConverter.cs" /> + <Compile Include="Converters\NanoLiterToLiterFormatConverter.cs" /> + <Compile Include="Converters\StringToBoolYesNoNullConverter.cs" /> + <Compile Include="Converters\StringToFirstLetterConverter.cs" /> + <Compile Include="Converters\TooltipLiquidQuantityFormatConverter.cs" /> + <Compile Include="Models\ExcelModel.cs" /> + <Compile Include="Models\TotalLiquidQuantityModel.cs" /> + <Compile Include="Models\JobRunModel.cs" /> + <Compile Include="Models\JobRunStatisticsModel.cs" /> <Compile Include="Models\LabeledSeriesCollection.cs" /> + <Compile Include="Models\RmlModel.cs" /> + <Compile Include="Models\StatisticsValueCollection.cs" /> <Compile Include="Tooltips\PieChartTooltipControl.xaml.cs"> <DependentUpon>PieChartTooltipControl.xaml</DependentUpon> </Compile> <Compile Include="StatisticsModule.cs" /> + <Compile Include="ValidationRules\DateExpiredRule.cs" /> <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\ChartsViewVM.cs" /> + <Compile Include="ViewModels\JobRunsViewVM.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\ChartsView.xaml.cs"> + <DependentUpon>ChartsView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\JobRunsView.xaml.cs"> + <DependentUpon>JobRunsView.xaml</DependentUpon> + </Compile> <Compile Include="Views\MainView.xaml.cs"> <DependentUpon>MainView.xaml</DependentUpon> </Compile> @@ -94,6 +122,14 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\ChartsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\JobRunsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\MainView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -128,6 +164,10 @@ <Resource Include="Images\statistics.png" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\..\..\SideChains\Tango.AutoComplete\Tango.AutoComplete.csproj"> + <Project>{bb2abb74-ba58-4812-83aa-ec8171f42df4}</Project> + <Name>Tango.AutoComplete</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj"> <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> <Name>Tango.BL</Name> @@ -136,10 +176,18 @@ <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.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.Serialization\Tango.Serialization.csproj"> <Project>{22f87980-e990-4686-be81-be63d562c4d5}</Project> <Name>Tango.Serialization</Name> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml index 07f1308ec..b03f02249 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml @@ -7,7 +7,7 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> - <Border Padding="10" Background="White" CornerRadius="5" BorderThickness="1" BorderBrush="Silver" MaxWidth="400"> + <Border Padding="10" Background="{StaticResource TransparentBackgroundBrush450}" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource borderBrush}" MaxWidth="400"> <TextBlock Text="{Binding Title}" TextWrapping="Wrap"></TextBlock> </Border> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs new file mode 100644 index 000000000..98b90f855 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; + + +namespace Tango.MachineStudio.Statistics.ValidationRules +{ + public class DateExpiredRule : ValidationRule + { + public override ValidationResult Validate(object value, CultureInfo cultureInfo) + { + DateTime orderDate = (DateTime)value; + + return new ValidationResult(orderDate < DateTime.Now, "Please enter a date until today."); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs new file mode 100644 index 000000000..a98257086 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs @@ -0,0 +1,364 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Media; +using Tango.BL.Enumerations; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Statistics.Models; +using Tango.BL.Entities; +using Tango.SharedUI; +using Tango.BL; +using Tango.MachineStudio.Common.Notifications; +using System.Threading.Tasks; +using Tango.Core.Commands; + +namespace Tango.MachineStudio.Statistics.ViewModels +{ + public class ChartsViewVM : ViewModel + { + private INotificationProvider _notification; + //private ObservablesContext _context; + private List<JobRunStatisticsModel> _job_runs; + private bool _loaded; + + #region Properties + private LabeledSeriesCollection _timelineJobStatusSeries; + public LabeledSeriesCollection TimelineJobStatusSeries + { + get { return _timelineJobStatusSeries; } + set { _timelineJobStatusSeries = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieJobFailedReasons; + public LabeledSeriesCollection PieJobFailedReasons + { + get { return _pieJobFailedReasons; } + set { _pieJobFailedReasons = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _printPerWeekSeries; + public LabeledSeriesCollection PrintPerWeekSeries + { + get { return _printPerWeekSeries; } + set { _printPerWeekSeries = value; RaisePropertyChangedAuto(); } + } + + private DateTime _startDate; + public DateTime StartDate + { + get { return _startDate; } + set { _startDate = value; RaisePropertyChangedAuto(); RaisePropertyChanged("EndDate"); } + } + + private DateTime _endDate; + public DateTime EndDate + { + get { return _endDate; } + set { _endDate = value; RaisePropertyChangedAuto(); RaisePropertyChanged("StartDate"); } + } + + public RelayCommand LoadJobRunsCommand { get; set; } + #endregion + + public ChartsViewVM(INotificationProvider notificationProvider) + { + _notification = notificationProvider; + StartDate = DateTime.Now.AddMonths(-1); + EndDate = DateTime.Now; + LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree); + } + + #region Generate Charts + + private async Task LoadJobRuns() + { + using (_notification.PushTaskItem("Loading statistics...")) + { + try + { + IsFree = false; + + await Task.Factory.StartNew(() => + { + using (var db = ObservablesContext.CreateDefault()) + { + DateTime startUtc = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (EndDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = EndDate.ToUniversalTime() + offsetTime; + + _job_runs = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)).OrderBy(x => x.StartDate).ToList().Select(x => new JobRunStatisticsModel(x)).ToList(); + + foreach (var run in _job_runs) + { + run.LoadMachine(db).GetAwaiter().GetResult(); + } + } + }); + + InvokeUIOnIdle(() => + { + if (_loaded) + { + OnDateRangeChanged(); + } + }); + + _loaded = true; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading statistics."); + } + finally + { + IsFree = true; + } + } + } + + + private List<JobRunStatisticsModel> GetJobRunsByDateRange(DateTime startDate, DateTime endTime, JobRunStatus? status = null) + { + return _job_runs.Where(x => x.StartDate.ToLocalTime() >= startDate && x.StartDate.ToLocalTime() <= endTime && (status == null || x.JobRunStatus == status)).ToList(); + } + + private List<JobRunStatisticsModel> GetJobRunsByDate(DateTime date, JobRunStatus? status = null) + { + return _job_runs.Where(x => x.StartDate.ToLocalTime().Date == date.Date && (status == null || x.JobRunStatus == status)).ToList(); + } + + private IEnumerable<DateTime> CreateDates(DateTime start, DateTime end) + { + for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1)) + { + yield return date; + } + } + + private void GenerateTimelineJobStatusChart() + { + TimelineJobStatusSeries = new LabeledSeriesCollection() + { + Title = "Job Runs Status", + ChartTitle = "Number Of Runs", + LabelsTitle = "Date", + SeriesColors = new List<Color>() + { + Colors.Green, + Colors.Orange, + Colors.Red, + }, + }; + + Series completed_job_runs = new ColumnSeries() + { + Title = "Completed", + Values = new ChartValues<int>(), + Fill = Brushes.Green, + MinWidth = 1, + + }; + Series aborted_job_runs = new ColumnSeries() + { + Title = "Aborted", + Values = new ChartValues<int>(), + Fill = Brushes.Orange, + MinWidth = 1, + }; + Series failed_job_runs = new ColumnSeries() + { + Title = "Failed", + Values = new ChartValues<int>(), + Fill = Brushes.Red, + MinWidth = 1, + }; + + if (EndDate - StartDate > TimeSpan.FromDays(40)) + { + completed_job_runs = new LineSeries() + { + Title = "Completed", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + + }; + aborted_job_runs = new LineSeries() + { + Title = "Aborted", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + }; + failed_job_runs = new LineSeries() + { + Title = "Failed", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + }; + } + + foreach (var date in CreateDates(StartDate, EndDate)) + { + completed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Completed).Count()); + aborted_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Aborted).Count()); + failed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Failed).Count()); + + TimelineJobStatusSeries.Labels.Add(date.ToShortDateString()); + } + + + + TimelineJobStatusSeries.SeriesCollection.Add(failed_job_runs); + TimelineJobStatusSeries.SeriesCollection.Add(aborted_job_runs); + TimelineJobStatusSeries.SeriesCollection.Add(completed_job_runs); + } + + private void GeneratePieFailedReasonsChart() + { + var groups = GetJobRunsByDateRange(StartDate, EndDate, JobRunStatus.Failed).GroupBy(x => x.FailedMessage).OrderBy(x => x.Count()); + + List<Color> colors = new List<Color>(); + + int max = groups.Count() > 0 ? groups.Max(x => x.Count()) : 0; + + for (int i = 0; i < groups.Count(); i++) + { + int count = groups.ElementAt(i).Count(); + double alpha = Math.Max(((double)(count) / max * 200), 20); + colors.Add(Color.FromArgb((byte)alpha, 200, 0, 0)); + } + + PieJobFailedReasons = new LabeledSeriesCollection() + { + Title = "Job Failure Reasons", + SeriesColors = colors, + }; + + int index = 0; + + foreach (var group in groups) + { + int count = group.Count(); + + var series = new PieSeries() + { + Title = group.First().FailedMessage, + Values = new ChartValues<int>() { count }, + Fill = new SolidColorBrush(colors[index++]), + DataLabels = true, + ToolTip = group.First().FailedMessage, + }; + + PieJobFailedReasons.SeriesCollection.Add(series); + } + } + + private void GeneratePrintPerWeekChart() + { + List<JobRunStatisticsModel> range_job_runs = GetJobRunsByDateRange(StartDate, EndDate); + + Dictionary<Machine, List<double>> weeks_print_avg = new Dictionary<Machine, List<double>>(); + + //Init machines weeks averages dictionary. + foreach (var machine in range_job_runs.Select(x => x.Machine).OrderBy(x => x.Name).DistinctBy(x => x.Guid)) + { + weeks_print_avg[machine] = new List<double>(); + } + + //Create all available dates + List<DateTime> all_dates = range_job_runs.Select(x => x.StartDate).ToList(); + + //get first Sunday. + DateTime current_sunday = all_dates.FirstOrDefault(x => x.DayOfWeek == DayOfWeek.Sunday); + + if (current_sunday != null && all_dates.Count > 0) + { + //Iterate over each week starting from the earliest Sunday. + while (current_sunday <= all_dates.Last()) + { + var week_job_runs = range_job_runs.Where(x => x.EndPosition > 10 && x.StartDate >= current_sunday && x.StartDate <= current_sunday.AddDays(7)).ToList(); + + foreach (var machine_job_runs in week_job_runs.GroupBy(x => x.Machine)) + { + weeks_print_avg[machine_job_runs.Key].Add(machine_job_runs.Select(x => x.EndPosition).Average()); + } + + current_sunday = current_sunday.AddDays(8); + } + } + + Dictionary<Machine, double> week_print_avg = new Dictionary<Machine, double>(); + + //Init machines week average dictionary. + foreach (var machine in weeks_print_avg) + { + if (machine.Value.Count > 0) + { + week_print_avg[machine.Key] = machine.Value.Average(); + } + } + + //Init chart series + PrintPerWeekSeries = new LabeledSeriesCollection() + { + Title = "Average Printed Thread Per Week (m)", + ChartTitle = "Average Print Per Week (m)", + LabelsTitle = "Date", + SeriesColors = new List<Color>() + { + + }, + }; + + //Init series colors intensity by number of prints. + double max = week_print_avg.Count > 0 ? week_print_avg.Max(x => x.Value) : 0; + foreach (var machine in week_print_avg) + { + double a = (machine.Value / max); + PrintPerWeekSeries.SeriesColors.Add(Color.FromArgb((byte)(255d * (machine.Value / max)), 0, 200, 0)); + } + + //Init columns. + int index = 0; + + foreach (var machine in week_print_avg) + { + var series = new ColumnSeries() + { + Title = machine.Key.Name, + Values = new ChartValues<int>() { (int)machine.Value }, + Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]), + DataLabels = true, + ToolTip = machine.Key.SerialNumber, + }; + + PrintPerWeekSeries.SeriesCollection.Add(series); + } + } + + #endregion + + #region Filter by Date + public void OnDateRangeChanged() + { + if (_job_runs != null)// && _job_runs.Count > 0)// && _loaded) + { + GenerateTimelineJobStatusChart(); + GeneratePieFailedReasonsChart(); + GeneratePrintPerWeekChart(); + } + } + #endregion + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs new file mode 100644 index 000000000..ae1592d8d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs @@ -0,0 +1,729 @@ +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.BL.Builders; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Statistics.Models; +using Tango.SharedUI; +using Tango.SharedUI.Components; +using Tango.AutoComplete.Editors; +using System.Windows.Media; +using LiveCharts.Wpf; +using LiveCharts; +using Tango.BL.ValueObjects; +using System.Diagnostics; +using Microsoft.Win32; +using Tango.CSV; +using System.ComponentModel; + +namespace Tango.MachineStudio.Statistics.ViewModels +{ + public enum HeadCleaningSelectionEnum + { + [Description("Exclude")] + Exclude = 0, + [Description("Include")] + Include = 1, + [Description("Only")] + Only = 2 + }; + + + public class JobRunsViewVM : ViewModel + { + private INotificationProvider _notification; + private List<Machine> _allMachines; + private List<User> _allUsers; + private List<RmlModel> _rmlsModels; + + + + #region Properties + + private ObservableCollection<JobRunModel> _jobRuns; + /// <summary> + /// Gets or sets the job runs. Contains filtered data of JobRunModel. + /// </summary> + public ObservableCollection<JobRunModel> JobRuns + { + get { return _jobRuns; } + set + { + _jobRuns = value; + RaisePropertyChangedAuto(); + } + } + + private JobRunModel _selectedJobRun = null; + /// <summary> + /// Gets or sets the JobRunModel. Binding to selected item of grid items. + /// </summary> + public JobRunModel SelectedJobRun + { + get { return _selectedJobRun; } + set + { + _selectedJobRun = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<Machine> _selectedMachines; + /// <summary> + /// Gets or sets the selected machines. Contains all available machines and selected machines. Binding to ComboBox Machines. + /// </summary> + public SelectedObjectCollection<Machine> SelectedMachines + { + get { return _selectedMachines; } + set + { + _selectedMachines = value; + RaisePropertyChangedAuto(); + } + } + + private DateTime _startSelectedDate; + /// <summary> + /// Gets or sets the start selected date. + /// </summary> + public DateTime StartSelectedDate + { + get { return _startSelectedDate; } + set { _startSelectedDate = value; + RaisePropertyChangedAuto(); + } + } + + private DateTime _endSelectedDate; + /// <summary> + /// Gets or sets the end selected date. + /// </summary> + public DateTime EndSelectedDate + { + get { return _endSelectedDate; } + set { _endSelectedDate = value; RaisePropertyChangedAuto(); } + } + + protected Double _lengthLowerValue; + /// <summary> + /// Gets or sets the length lower value of Range Slider + /// </summary> + public Double LengthLowerValue + { + get { return _lengthLowerValue; } + set + { + _lengthLowerValue = value; + RaisePropertyChangedAuto(); + } + } + + protected Double _lengthUpperValue; + /// <summary> + /// Gets or sets the length upper value of Range Slider. + /// </summary> + public Double LengthUpperValue + { + get { return _lengthUpperValue; } + set + { + _lengthUpperValue = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<JobSource> _jobRunSelectedSources; + /// <summary> + /// Gets or sets the job run selected sources. Binding to ComboBox "Source". + /// </summary> + public SelectedObjectCollection<JobSource> JobRunSelectedSources + { + get { return _jobRunSelectedSources; } + set { _jobRunSelectedSources = value; RaisePropertyChangedAuto(); } + } + + private SelectedObjectCollection<JobRunStatus> _jobRunSelectedStatuses; + /// <summary> + /// Gets or sets the job run selected statuses. Binding to ComboBox "Status". + /// </summary> + public SelectedObjectCollection<JobRunStatus> JobRunSelectedStatuses + { + get { return _jobRunSelectedStatuses; } + set { _jobRunSelectedStatuses = value; RaisePropertyChangedAuto(); } + } + + public SelectedObjectCollection<bool> _isGradientSelection; + /// <summary> + /// Gets or sets the is gradient selection. Binding to ComboBox "IsGradient". + /// </summary> + public SelectedObjectCollection<bool> IsGradientSelection + { + get { return _isGradientSelection; } + set + { + _isGradientSelection = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<RmlModel> _selectedThreads; + /// <summary> + /// Gets or sets the selected threads. Contains all available threads and selected threads. Binding to ComboBox "Thread". + /// </summary> + public SelectedObjectCollection<RmlModel> SelectedThreads + { + get { return _selectedThreads; } + set + { + _selectedThreads = value; + RaisePropertyChangedAuto(); + } + } + + private HeadCleaningSelectionEnum _headCleaningSelected; + + public HeadCleaningSelectionEnum HeadCleaningSelected + { + get { return _headCleaningSelected; } + set + { + _headCleaningSelected = value; + RaisePropertyChangedAuto(); + } + } + + + /// <summary> + /// Gets or sets the JobRuns providers. + /// </summary> + public ISuggestionProvider JobsProvider { get; set; } + + private Job _selectedJob; + /// <summary> + /// Gets or sets the job. + /// </summary> + public Job SelectedJob + { + get { return _selectedJob; } + set + { + _selectedJob = value; + RaisePropertyChangedAuto(); + } + } + + /// <summary> + /// Gets or sets the statistics value collection. Class - container included calculated statistic values. + /// </summary> + public StatisticsValueCollection StatisticsValueCollection { get; set; } + + #endregion + + public RelayCommand LoadJobRunsCommand { get; set; } + + public RelayCommand ExportToExcelCommand { get; set; } + + public JobRunsViewVM(INotificationProvider notificationProvider) + { + _notification = notificationProvider; + JobRuns = new ObservableCollection<JobRunModel>(); + LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree); + ExportToExcelCommand = new RelayCommand(ExportToExcel, () => IsFree); + LengthUpperValue = 10000.0; + LengthLowerValue = 0.0; + DateTime now = DateTime.Now; + StartSelectedDate = now.AddMonths(-1); + EndSelectedDate = now; + + JobRunSelectedSources = new SelectedObjectCollection<JobSource>(new ObservableCollection<JobSource>() + { + JobSource.Local, + JobSource.Remote + }, new ObservableCollection<JobSource>() + { + JobSource.Local, + JobSource.Remote + }); + JobRunSelectedSources.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); + JobRunSelectedSources.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); + + JobRunSelectedStatuses = new SelectedObjectCollection<JobRunStatus>(new ObservableCollection<JobRunStatus>() + { + JobRunStatus.Aborted, + JobRunStatus.Completed, + JobRunStatus.Failed, + + }, new ObservableCollection<JobRunStatus>() + { + JobRunStatus.Aborted, + JobRunStatus.Completed, + JobRunStatus.Failed, + + }); + JobRunSelectedStatuses.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); + JobRunSelectedStatuses.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); + + IsGradientSelection = new SelectedObjectCollection<bool>(new ObservableCollection<bool> + { + true, + false + }, new ObservableCollection<bool> + { + true, + false + }); + IsGradientSelection.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); + IsGradientSelection.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); + + HeadCleaningSelected = HeadCleaningSelectionEnum.Exclude; + + JobsProvider = new SuggestionProvider((filter) => + { + try + { + if (filter != null) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + return db.Jobs.Where(x => x.Name != null && x.Name.ToLower().Contains(filter.ToLower())).ToList(); + } + } + else + { + return new List<Job>(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading jobs."); + return null; + } + }); + + StatisticsValueCollection = new StatisticsValueCollection(); + } + + /// <summary> + /// Initializes this instance. Called form main view VM in OnApplicationReady + /// </summary> + public async void Init() + { + using (_notification.PushTaskItem("Loading job runs...")) + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + _allMachines = await db.Machines.ToListAsync(); + _allUsers = await db.Users.Include(x => x.Contact).ToListAsync(); + _rmlsModels = await db.Rmls.Select(x => new RmlModel() { Name = x.Name, Guid = x.Guid }).ToListAsync(); + SelectedMachines = new SelectedObjectCollection<Machine>(_allMachines.ToObservableCollection(), new ObservableCollection<Machine>()); + SelectedThreads = new SelectedObjectCollection<RmlModel>(_rmlsModels.ToObservableCollection(), new ObservableCollection<RmlModel>()); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading job runs."); + } + finally + { + IsFree = true; + } + } + + } + + /// <summary> + /// Loads the job runs by filters. + /// </summary> + private async Task LoadJobRuns() + { + using (_notification.PushTaskItem("Loading job runs...")) + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + DateTime startUtc = new DateTime(StartSelectedDate.Year, StartSelectedDate.Month, StartSelectedDate.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (EndSelectedDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = EndSelectedDate.ToUniversalTime() + offsetTime; + + string jobName = SelectedJob == null ? "" : SelectedJob.Name; + + var db_JobRuns = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)) + .Select(x => new + { + x.ID, + x.ActualStartDate, + x.EndDate, + x.EndPosition, + x.GradientResolutionCm, + x.Guid, + x.HeatingStartDate, + x.IsGradient, + x.JobGuid, + x.JobLength, + x.JobName, + x.JobSource, + x.MachineGuid, + x.RmlGuid, + x.StartDate, + x.Status, + x.UploadingStartDate, + x.UserGuid, + x.CyanQuantity, + x.MagentaQuantity, + x.YellowQuantity, + x.BlackQuantity, + x.TransparentQuantity, + x.LubricantQuantity, + x.CleanerQuantity, + x.IsHeadCleaning + }); + var machineIDs = new HashSet<string>(SelectedMachines.SynchedSource.ToList().Select(p => p.Guid)); + if (machineIDs.Count > 0) + { + db_JobRuns = db_JobRuns.Where(x => machineIDs.Contains(x.MachineGuid)); + } + int[] jobRunSourceArr = JobRunSelectedSources.SynchedSource.Select(x => (int)x).ToArray(); + if (jobRunSourceArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => jobRunSourceArr.Contains(x.JobSource)); + } + int[] jobRunStatusArr = JobRunSelectedStatuses.SynchedSource.Select(x => (int)x).ToArray(); + if (jobRunStatusArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => jobRunStatusArr.Contains(x.Status)); + } + bool[] isGradientArr = IsGradientSelection.SynchedSource.Select(x => (bool)x).ToArray(); + if (isGradientArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => isGradientArr.Contains(x.IsGradient)); + } + + if(HeadCleaningSelected != HeadCleaningSelectionEnum.Include) + { + bool isHeadCleaning = HeadCleaningSelected == HeadCleaningSelectionEnum.Only; + db_JobRuns = db_JobRuns.Where(x => isHeadCleaning == x.IsHeadCleaning); + } + + List<String> rmlGuids = SelectedThreads.SynchedSource.Select(y => y.Guid).ToList(); + if (rmlGuids != null && rmlGuids.Count > 0) + { + db_JobRuns = db_JobRuns.Where(x => rmlGuids.Contains(x.RmlGuid)); + } + if (!String.IsNullOrEmpty(jobName)) + { + db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower().StartsWith(jobName.ToLower())); + } + + var runs_db = await db_JobRuns.ToListAsync(); //Execute actual query. + + + List<JobRun> runs = runs_db.Where(x => (x.JobLength < LengthUpperValue && x.JobLength >= LengthLowerValue)) + .Select(x => new JobRun() + { + ID = x.ID, + ActualStartDate = x.ActualStartDate, + EndDate = x.EndDate, + EndPosition = x.EndPosition, + GradientResolutionCm = x.GradientResolutionCm, + Guid = x.Guid, + HeatingStartDate = x.HeatingStartDate, + IsGradient = x.IsGradient, + JobGuid = x.JobGuid, + JobLength = x.JobLength, + JobName = x.JobName, + JobSource = x.JobSource, + MachineGuid = x.MachineGuid, + RmlGuid = x.RmlGuid, + StartDate = x.StartDate, + Status = x.Status, + UploadingStartDate = x.UploadingStartDate, + UserGuid = x.UserGuid, + CyanQuantity = x.CyanQuantity, + MagentaQuantity = x.MagentaQuantity, + YellowQuantity = x.YellowQuantity, + BlackQuantity = x.BlackQuantity, + TransparentQuantity = x.TransparentQuantity, + LubricantQuantity = x.LubricantQuantity, + CleanerQuantity = x.CleanerQuantity, + IsHeadCleaning = x.IsHeadCleaning + }).ToList(); + + var modelList = runs.Select(x => new JobRunModel() + { + JobRun = x, + Machine = _allMachines.FirstOrDefault(y => y.Guid == x.MachineGuid), + User = _allUsers.SingleOrDefault(y => y.Guid == x.UserGuid), + Rml = _rmlsModels.SingleOrDefault(y => y.Guid == x.RmlGuid), + }).OrderByDescending(x => x.JobRun.StartDate).ToList(); + + modelList.ForEach(x => x.Init()); + JobRuns = modelList.ToObservableCollection(); + GenerateStatistics(); + } + + + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading job runs."); + } + finally + { + IsFree = true; + } + } + } + + private void ExportToExcel() + { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Title = "Job Runs Statistic Report"; + dlg.Filter = "CSV Files|*.csv"; + dlg.FileName = $"Statistics_Job_runs"; + dlg.DefaultExt = ".csv"; + if (dlg.ShowDialog().Value) + { + try + { + CsvFile<ExcelModel> csvFile = new CsvFile<ExcelModel>(new CsvDestination(dlg.FileName), new CsvDefinition() + { + Columns = new List<String>() + { + "ID", + "Machine", + "User", + "Job Name", + "Thread", + "Length", + "Source", + "Upload Duration", + "Heating Duration", + "Start Time", + "IsGradient", + "Gradient Resolution", + "Status", + "End Date", + "End Position", + "Cyan", + "Magenta", + "Yellow", + "Black", + "Transparent", + "Lubricant", + "Cleaner" + }, + }); + var selection = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null); + foreach (var jobRunModel in selection) + { + ExcelModel excel_model = new ExcelModel(); + excel_model.ID = jobRunModel.JobRun.ID.ToString(); + excel_model.Machine = jobRunModel.Machine != null ? jobRunModel.Machine.SerialNumber : ""; + excel_model.User = jobRunModel.User != null ? jobRunModel.User.Contact.FullName: ""; + excel_model.JobName = jobRunModel.JobRun.JobName; + excel_model.Thread = jobRunModel.Rml != null ? jobRunModel.Rml.Name : ""; + excel_model.Length = String.Format("{0:0.##}", jobRunModel.JobRun.JobLength); + excel_model.Source = jobRunModel.JobRun.Source.ToString(); + excel_model.UploadDuration = jobRunModel.UploadDuration != null ? ((TimeSpan)(jobRunModel.UploadDuration)).ToString(@"hh\:mm\:ss") : TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + excel_model.HeatingDuration = jobRunModel.HeatingDuration != null ? ((TimeSpan)(jobRunModel.HeatingDuration)).ToString(@"hh\:mm\:ss") : TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + excel_model.StartTime = jobRunModel.JobRun.ActualStartDate != null ? ((DateTime)jobRunModel.JobRun.ActualStartDate).ToLocalTime().ToString("MM/dd/yy HH:mm"): ""; + excel_model.IsGradient = jobRunModel.JobRun.IsGradient ? "Yes" : "No"; + excel_model.GR = jobRunModel.JobRun.GradientResolutionCm.ToString(); + excel_model.Status = jobRunModel.JobRun.JobRunStatus.ToString(); + excel_model.EndTime = jobRunModel.JobRun.EndDate != null ? ((DateTime)jobRunModel.JobRun.EndDate).ToLocalTime().ToString("MM/dd/yy HH:mm"): ""; + excel_model.EndPosition = String.Format("{0:0.##}", jobRunModel.JobRun.EndPosition); + excel_model.Cyan = jobRunModel.JobRun.CyanQuantity < 0 ? "" :jobRunModel.JobRun.CyanQuantity.ToString(); + excel_model.Magenta = jobRunModel.JobRun.MagentaQuantity < 0 ? "" : jobRunModel.JobRun.MagentaQuantity.ToString(); + excel_model.Yellow = jobRunModel.JobRun.YellowQuantity < 0 ? "" : jobRunModel.JobRun.YellowQuantity.ToString(); + excel_model.Black = jobRunModel.JobRun.BlackQuantity < 0 ? "" : jobRunModel.JobRun.BlackQuantity.ToString(); + excel_model.Transparent = jobRunModel.JobRun.TransparentQuantity < 0 ? "" : jobRunModel.JobRun.TransparentQuantity.ToString(); + excel_model.Lubricant = jobRunModel.JobRun.LubricantQuantity < 0 ? "" : jobRunModel.JobRun.LubricantQuantity.ToString(); + excel_model.Cleaner = jobRunModel.JobRun.CleanerQuantity < 0 ? "" : jobRunModel.JobRun.CleanerQuantity.ToString(); + csvFile.Append(excel_model); + + } + + csvFile.Dispose(); + _notification.ShowInfo("Report generated successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating Statistics Job Runs report."); + _notification.ShowError($"Error generating Statistics Job Runs report..\n{ex.Message}"); + } + } + } + #region GenerateS_StatisticsValueCollection + + /// <summary> + /// Generates the statistics. + /// </summary> + protected void GenerateStatistics() + { + StatisticsValueCollection.Clean(); + if (JobRuns.Count() == 0) + return; + GenerateTotalRunsCount(); + GenerateTotalRunsLength(); + GenerateTotalThreadConsumption(); + GenerateRunsDuration(); + GenerateAverageUploadDuration(); + GenerateAverageHeatingDuration(); + + GeneratePieCharts(); + CreateThreadConsumptionPerThread(); + GenerateAllLiquidQuantities(); + } + + protected void GenerateTotalRunsCount() + {//Total Runs: + int val = JobRuns.Count(); + StatisticsValueCollection.AddStatisticsValue("Total Runs ", val, " "); + } + + /// <summary> + /// Generates the total length of the job runs. + /// </summary> + protected void GenerateTotalRunsLength() + { + double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.JobRun.JobLength); + StatisticsValueCollection.AddStatisticsValue("Total Runs Length", val, " m"); + } + + /// <summary> + /// Generates the duration and average of the job runs. + /// </summary> + protected void GenerateRunsDuration() + { + var selection = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null); + double val = 0d; + double average = 0d; + if (selection != null && selection.Count<JobRunModel>() > 0) + { + val = selection.Sum(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalHours); + average = selection.Average(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalMilliseconds); + } + StatisticsValueCollection.AddStatisticsValue("Total Dyeing Time", val, " hours"); + StatisticsValueCollection.AddStatisticsValue("Average Dyeing Time", Math.Max(TimeSpan.FromMilliseconds(average).TotalHours, 0), " hours"); + } + + /// <summary> + /// Generates the average upload duration of the job runs. + /// </summary> + protected void GenerateAverageUploadDuration() + { + var average = (long)JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.UploadDuration != null).Average(x => x.UploadDuration.Value.TotalMilliseconds); + StatisticsValueCollection.AddStatisticsValue("Average Upload Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); + } + + /// <summary> + /// Generates the average duration heating of the job runs. + /// </summary> + protected void GenerateAverageHeatingDuration() + { + var average = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.HeatingDuration != null && z.HeatingDuration.Value.Ticks > 0).Average(x => x.HeatingDuration.Value.TotalMilliseconds); + StatisticsValueCollection.AddStatisticsValue("Average Heating Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); + } + + /// <summary> + /// Generates the total thread consumption by EndPosition. + /// </summary> + protected void GenerateTotalThreadConsumption() + { + double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.JobRun.EndPosition); + StatisticsValueCollection.AddStatisticsValue("Total Dyeing Length", val, " m"); + } + + /// <summary> + /// Generates the pie charts in percentage: JobSource, JobRunStatus, Gradient. + /// </summary> + protected void GeneratePieCharts() + { + int PPCCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Local); + int MSCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Remote); + StatisticsValueCollection.GeneratePieJobSource(PPCCount, MSCount); + + int failedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Failed); + int abortedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Aborted); + int completedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Completed); + StatisticsValueCollection.GeneratePieJobRunStatus(failedCount, abortedCount, completedCount); + + int gradientCount = JobRuns.Count(x => x.JobRun.IsGradient == true); + int solidCount = JobRuns.Count(x => x.JobRun.IsGradient == false); + StatisticsValueCollection.GeneratePieGradientSolid(gradientCount, solidCount); + + } + + /// <summary> + /// Creates the thread consumption per thread. + /// </summary> + protected void CreateThreadConsumptionPerThread() + { + var temp = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null).GroupBy(x => x.Rml.Name); + List<StatisticsValue> result = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null && !String.IsNullOrEmpty(z.Rml.Name)).GroupBy(x => x.Rml.Name).Select(y => new StatisticsValue { Name = y.Key, Value = y.Sum(x => x.JobRun.EndPosition), Unit = "m" }).ToList(); + StatisticsValueCollection.CreateThreadConsumptionPerThread(result); + } + + /// <summary> + /// Generates all liquid quantities. + /// </summary> + protected void GenerateAllLiquidQuantities() + { + var runs = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.LiquidQuantitiesFast.Count > 0).ToList(); + + Dictionary<LiquidTypes, ulong> total_quantities = new Dictionary<LiquidTypes, ulong>(); + + foreach (LiquidTypes ltype in (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes))) + { + total_quantities[ltype] = 0; + } + + foreach (var run in runs) + { + foreach (var lq in run.JobRun.LiquidQuantitiesFast) + { + if (lq.Quantity < 0) + { + Debug.WriteLine($"Warning: JobRun '{run.JobRun.ID}' contains an invalid value '{lq.Quantity}' for {lq.LiquidType} quantity."); + } + + total_quantities[lq.LiquidType] += Convert.ToUInt64(Math.Max(lq.Quantity, 0)); + } + } + + List<TotalLiquidQuantityModel> allLiquidQuantities = total_quantities.Select(x => new TotalLiquidQuantityModel() + { + LiquidType = x.Key, + Quantity = x.Value + }).ToList(); + + + //foreach (LiquidTypes ltype in (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes))) + //{ + // var liquidQuantityByTypeList = db_liquidQuantities.Select(x => x.FirstOrDefault(y => y.LiquidType == ltype)).Where(x => x != null); + // var count = liquidQuantityByTypeList != null ? liquidQuantityByTypeList.Sum(x => x.Quantity) : 0; + // JobRunLiquidQuantity lq = new JobRunLiquidQuantity() { LiquidType = ltype, Quantity = count }; + // allLiquidQuantities.Add(lq); + //} + StatisticsValueCollection.GenerateStatisticsLiquidQuantity(allLiquidQuantities); + } + #endregion + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs index ef9561d0b..e7e2013c5 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs @@ -7,360 +7,49 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Media; using Tango.BL; -using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Helpers; using Tango.MachineStudio.Common; using Tango.MachineStudio.Statistics.Models; using System.Data.Entity; using Tango.MachineStudio.Common.Notifications; +using Tango.BL.Entities; namespace Tango.MachineStudio.Statistics.ViewModels { public class MainViewVM : StudioViewModel { - private ObservablesContext _context; - private List<JobRun> _job_runs; - private bool rendered; private INotificationProvider _notification; - private bool _loaded; - - private LabeledSeriesCollection _timelineJobStatusSeries; - public LabeledSeriesCollection TimelineJobStatusSeries - { - get { return _timelineJobStatusSeries; } - set { _timelineJobStatusSeries = value; RaisePropertyChangedAuto(); } - } - - private LabeledSeriesCollection _pieJobFailedReasons; - public LabeledSeriesCollection PieJobFailedReasons - { - get { return _pieJobFailedReasons; } - set { _pieJobFailedReasons = value; RaisePropertyChangedAuto(); } - } - - private LabeledSeriesCollection _printPerWeekSeries; - public LabeledSeriesCollection PrintPerWeekSeries - { - get { return _printPerWeekSeries; } - set { _printPerWeekSeries = value; RaisePropertyChangedAuto(); } - } - private DateTime _startDate; - public DateTime StartDate + private ChartsViewVM _chartsViewVM; + public ChartsViewVM ChartsViewVM { - get { return _startDate; } - set { _startDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } + get { return _chartsViewVM; } + set { _chartsViewVM = value; RaisePropertyChangedAuto(); } } - private DateTime _endDate; - public DateTime EndDate + private JobRunsViewVM _jobRunsViewVM; + public JobRunsViewVM JobRunsViewVM { - get { return _endDate; } - set { _endDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } + get { return _jobRunsViewVM; } + set { _jobRunsViewVM = value; RaisePropertyChangedAuto(); } } - - private DateTime _minDate; - public DateTime MinDate - { - get { return _minDate; } - set { _minDate = value; RaisePropertyChangedAuto(); } - } - - private DateTime _maxDate; - public DateTime MaxDate - { - get { return _maxDate; } - set { _maxDate = value; RaisePropertyChangedAuto(); } - } - - + public MainViewVM(INotificationProvider notificationProvider) { _notification = notificationProvider; - - StartDate = DateTime.Now.AddMonths(-1); - EndDate = DateTime.Now; + ChartsViewVM = new ChartsViewVM(_notification); + JobRunsViewVM = new JobRunsViewVM(_notification); } public override void OnApplicationReady() { - + JobRunsViewVM.Init(); } - private List<JobRun> GetJobRunsByDateRange(DateTime startDate, DateTime endTime, JobRunStatus? status = null) - { - return _job_runs.Where(x => x.StartDate.ToLocalTime() >= startDate && x.StartDate.ToLocalTime() <= endTime && (status == null || x.JobRunStatus == status)).ToList(); - } - - private List<JobRun> GetJobRunsByDate(DateTime date, JobRunStatus? status = null) - { - return _job_runs.Where(x => x.StartDate.ToLocalTime().Date == date.Date && (status == null || x.JobRunStatus == status)).ToList(); - } - - private IEnumerable<DateTime> CreateDates(DateTime start, DateTime end) - { - for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1)) - { - yield return date; - } - } - - - - public override async void OnNavigatedTo() + public override void OnNavigatedTo() { base.OnNavigatedTo(); - - if (rendered) return; - - rendered = true; - - - using (_notification.PushTaskItem("Loading statistics...")) - { - IsFree = false; - - await Task.Factory.StartNew(() => - { - _context = ObservablesContext.CreateDefault(); - _job_runs = _context.JobRuns.Include(x => x.Job).Include(x => x.Job.Machine).OrderBy(x => x.StartDate).ToList(); - }); - - if (_job_runs.Count > 0) - { - MinDate = _job_runs.Min(x => x.StartDate); - MaxDate = _job_runs.Max(x => x.StartDate); - } - - InvokeUIOnIdle(() => - { - OnDateRangeChanged(); - }); - - _loaded = true; - - IsFree = true; - } - } - - private void OnDateRangeChanged() - { - if (_job_runs != null && _job_runs.Count > 0 && _loaded) - { - GenerateTimelineJobStatusChart(); - GeneratePieFailedReasonsChart(); - GeneratePrintPerWeekChart(); - } - } - - private void GenerateTimelineJobStatusChart() - { - TimelineJobStatusSeries = new LabeledSeriesCollection() - { - Title = "Job Runs Status", - ChartTitle = "Number Of Runs", - LabelsTitle = "Date", - SeriesColors = new List<Color>() - { - Colors.Green, - Colors.Orange, - Colors.Red, - }, - }; - - Series completed_job_runs = new ColumnSeries() - { - Title = "Completed", - Values = new ChartValues<int>(), - Fill = Brushes.Green, - MinWidth = 1, - - }; - Series aborted_job_runs = new ColumnSeries() - { - Title = "Aborted", - Values = new ChartValues<int>(), - Fill = Brushes.Orange, - MinWidth = 1, - }; - Series failed_job_runs = new ColumnSeries() - { - Title = "Failed", - Values = new ChartValues<int>(), - Fill = Brushes.Red, - MinWidth = 1, - }; - - if (EndDate - StartDate > TimeSpan.FromDays(40)) - { - completed_job_runs = new LineSeries() - { - Title = "Completed", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - - }; - aborted_job_runs = new LineSeries() - { - Title = "Aborted", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - }; - failed_job_runs = new LineSeries() - { - Title = "Failed", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - }; - } - - foreach (var date in CreateDates(StartDate, EndDate)) - { - completed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Completed).Count()); - aborted_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Aborted).Count()); - failed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Failed).Count()); - - TimelineJobStatusSeries.Labels.Add(date.ToShortDateString()); - } - - - - TimelineJobStatusSeries.SeriesCollection.Add(failed_job_runs); - TimelineJobStatusSeries.SeriesCollection.Add(aborted_job_runs); - TimelineJobStatusSeries.SeriesCollection.Add(completed_job_runs); - } - - private void GeneratePieFailedReasonsChart() - { - var groups = GetJobRunsByDateRange(StartDate, EndDate, JobRunStatus.Failed).GroupBy(x => x.FailedMessage).OrderBy(x => x.Count()); - - List<Color> colors = new List<Color>(); - - int max = groups.Count() > 0 ? groups.Max(x => x.Count()) : 0; - - for (int i = 0; i < groups.Count(); i++) - { - int count = groups.ElementAt(i).Count(); - double alpha = Math.Max(((double)(count) / max * 200), 20); - colors.Add(Color.FromArgb((byte)alpha, 200, 0, 0)); - } - - PieJobFailedReasons = new LabeledSeriesCollection() - { - Title = "Job Failure Reasons", - SeriesColors = colors, - }; - - int index = 0; - - foreach (var group in groups) - { - int count = group.Count(); - - var series = new PieSeries() - { - Title = group.First().FailedMessage, - Values = new ChartValues<int>() { count }, - Fill = new SolidColorBrush(colors[index++]), - DataLabels = true, - ToolTip = group.First().FailedMessage, - }; - - PieJobFailedReasons.SeriesCollection.Add(series); - } - } - - private void GeneratePrintPerWeekChart() - { - List<JobRun> range_job_runs = GetJobRunsByDateRange(StartDate, EndDate); - - Dictionary<Machine, List<double>> weeks_print_avg = new Dictionary<Machine, List<double>>(); - - //Init machines weeks averages dictionary. - foreach (var machine in range_job_runs.Select(x => x.Job.Machine).OrderBy(x => x.Name).DistinctBy(x => x.Guid)) - { - weeks_print_avg[machine] = new List<double>(); - } - - //Create all available dates - List<DateTime> all_dates = range_job_runs.Select(x => x.StartDate).ToList(); - - //get first Sunday. - DateTime current_sunday = all_dates.FirstOrDefault(x => x.DayOfWeek == DayOfWeek.Sunday); - - if (current_sunday != null && all_dates.Count > 0) - { - //Iterate over each week starting from the earliest Sunday. - while (current_sunday <= all_dates.Last()) - { - var week_job_runs = range_job_runs.Where(x => x.EndPosition > 10 && x.StartDate >= current_sunday && x.StartDate <= current_sunday.AddDays(7)).ToList(); - - foreach (var machine_job_runs in week_job_runs.GroupBy(x => x.Job.Machine)) - { - weeks_print_avg[machine_job_runs.Key].Add(machine_job_runs.Select(x => x.EndPosition).Average()); - } - - current_sunday = current_sunday.AddDays(8); - } - } - - Dictionary<Machine, double> week_print_avg = new Dictionary<Machine, double>(); - - //Init machines week average dictionary. - foreach (var machine in weeks_print_avg) - { - if (machine.Value.Count > 0) - { - week_print_avg[machine.Key] = machine.Value.Average(); - } - } - - //Init chart series - PrintPerWeekSeries = new LabeledSeriesCollection() - { - Title = "Average Printed Thread Per Week (m)", - ChartTitle = "Average Print Per Week (m)", - LabelsTitle = "Date", - SeriesColors = new List<Color>() - { - - }, - }; - - //Init series colors intensity by number of prints. - double max = week_print_avg.Count > 0 ? week_print_avg.Max(x => x.Value) : 0; - foreach (var machine in week_print_avg) - { - double a = (machine.Value / max); - PrintPerWeekSeries.SeriesColors.Add(Color.FromArgb((byte)(255d * (machine.Value / max)), 0, 200, 0)); - } - - //Init columns. - int index = 0; - - foreach (var machine in week_print_avg) - { - var series = new ColumnSeries() - { - Title = machine.Key.Name, - Values = new ChartValues<int>() { (int)machine.Value }, - Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]), - DataLabels = true, - ToolTip = machine.Key.SerialNumber, - }; - - PrintPerWeekSeries.SeriesCollection.Add(series); - } } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml new file mode 100644 index 000000000..b76154941 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml @@ -0,0 +1,145 @@ +<UserControl x:Class="Tango.MachineStudio.Statistics.Views.ChartsView" + 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.MachineStudio.Statistics.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.Statistics" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:localrule="clr-namespace:Tango.MachineStudio.Statistics.ValidationRules" + xmlns:local="clr-namespace:Tango.MachineStudio.Statistics.Views" + xmlns:tooltips="clr-namespace:Tango.MachineStudio.Statistics.Tooltips" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800"> + <Grid IsEnabled="{Binding IsFree}"> + <Grid.RowDefinitions> + <RowDefinition Height="80"/> + <RowDefinition Height="337*"/> + </Grid.RowDefinitions> + + + <StackPanel Margin="60 20 0 0" VerticalAlignment="Center" HorizontalAlignment="Left" Orientation="Horizontal" DockPanel.Dock="Left"> + <StackPanel> + <TextBlock FontSize="10">Start Date:</TextBlock> + <DatePicker x:Name="startdatePicker" SelectedDateChanged="StartDatePicker_SelectedDateChanged" materialDesign:HintAssist.Hint="Pick start date" Width="200" VerticalAlignment="Bottom" FontSize="16"> + <DatePicker.SelectedDate> + <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="StartDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + + <StackPanel Margin="40 0 0 0"> + <TextBlock FontSize="10">End Date:</TextBlock> + <DatePicker x:Name="endDatePicker" materialDesign:HintAssist.Hint="Pick end date" Width="200" VerticalAlignment="Bottom" FontSize="16" SelectedDateChanged="EndDatePicker_SelectedDateChanged"> + <DatePicker.SelectedDate> + <Binding Path="EndDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="EndDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + <Button Width="100" Margin="60 0 0 0" Command="{Binding LoadJobRunsCommand}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Content="LOAD"> + <Button.Style> + <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> + <Setter Property="IsEnabled" Value="False"/> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference startdatePicker}}" Value="False"/> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference endDatePicker}}" Value="False"/> + </MultiDataTrigger.Conditions> + <Setter Property="IsEnabled" Value="True"/> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </Button.Style> + </Button> + </StackPanel> + + + <UniformGrid Columns="3" Margin="50 20 50 50" Rows="2" Grid.Row="1"> + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding TimelineJobStatusSeries.Title}"></TextBlock> + <lvc:CartesianChart Series="{Binding TimelineJobStatusSeries.SeriesCollection}" LegendLocation="Bottom"> + <lvc:CartesianChart.DataTooltip> + <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> + </lvc:CartesianChart.DataTooltip> + <lvc:CartesianChart.AxisX> + <lvc:Axis Title="{Binding TimelineJobStatusSeries.LabelsTitle}" Labels="{Binding TimelineJobStatusSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> + <lvc:Axis.Separator> + <lvc:Separator Stroke="#A5A5A5" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisX> + <lvc:CartesianChart.AxisY> + <lvc:Axis Title="{Binding TimelineJobStatusSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > + <lvc:Axis.Separator> + <lvc:Separator Stroke="#B0B0B0" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisY> + </lvc:CartesianChart> + </DockPanel> + </Border> + + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PieJobFailedReasons.Title}"></TextBlock> + <UniformGrid Columns="2"> + <lvc:PieChart DataHover="PieChart_DataHover" Series="{Binding PieJobFailedReasons.SeriesCollection}" LegendLocation="None" Background="Transparent"> + <lvc:PieChart.Resources> + <Style TargetType="lvc:PieSeries"> + <Setter Property="Stroke" Value="#99F9F9F9"></Setter> + <Setter Property="StrokeThickness" Value="2"/> + </Style> + </lvc:PieChart.Resources> + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Hidden" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + + <TextBlock x:Name="txtPieTitle" TextWrapping="Wrap"></TextBlock> + </UniformGrid> + </DockPanel> + </Border> + + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PrintPerWeekSeries.Title}"></TextBlock> + <lvc:CartesianChart Series="{Binding PrintPerWeekSeries.SeriesCollection}" LegendLocation="Bottom" > + <lvc:CartesianChart.Resources> + <Style TargetType="lvc:ColumnSeries"> + <Setter Property="Foreground" Value="{StaticResource DarkGrayBrush200}"></Setter> + </Style> + </lvc:CartesianChart.Resources> + <lvc:CartesianChart.AxisX> + <lvc:Axis Title="{Binding PrintPerWeekSeries.LabelsTitle}" Labels="{Binding PrintPerWeekSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> + <lvc:Axis.Separator> + <lvc:Separator Stroke="#A5A5A5" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisX> + <lvc:CartesianChart.AxisY> + <lvc:Axis Title="{Binding PrintPerWeekSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > + <lvc:Axis.Separator> + <lvc:Separator Stroke="#6F6F6F" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisY> + <lvc:CartesianChart.DataTooltip> + <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> + </lvc:CartesianChart.DataTooltip> + </lvc:CartesianChart> + </DockPanel> + </Border> + </UniformGrid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs new file mode 100644 index 000000000..bd97ed2bc --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs @@ -0,0 +1,74 @@ +using LiveCharts; +using LiveCharts.Wpf; +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.MachineStudio.Statistics.Views +{ + /// <summary> + /// Interaction logic for ChartsView.xaml + /// </summary> + public partial class ChartsView : UserControl + { + public ChartsView() + { + InitializeComponent(); + } + private void PieChart_DataHover(object sender, ChartPoint chartPoint) + { + var tooltip = ((chartPoint.ChartView as PieChart).DataTooltip as Tooltips.PieChartTooltipControl).Title; + txtPieTitle.Text = tooltip; + } + private void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj != null && datePickerObj.SelectedDate != null && endDatePicker.SelectedDate != null) + { + if (datePickerObj.SelectedDate > endDatePicker.SelectedDate) + { + BindingExpression start_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(StartDateExpiredRule, start_be); + validationError.ErrorContent = "The start time must be less than or equal to end time."; + Validation.MarkInvalid(start_be, validationError); + } + else if (Validation.GetHasError(endDatePicker)) + { + BindingExpression end_be = endDatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(end_be); + } + } + } + + private void EndDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj.SelectedDate != null && startdatePicker.SelectedDate != null) + { + if (datePickerObj != null && datePickerObj.SelectedDate < startdatePicker.SelectedDate) + { + BindingExpression end_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(EndDateExpiredRule, end_be); + validationError.ErrorContent = "The end time must be greater than or equal to the start time."; + Validation.MarkInvalid(end_be, validationError); + } + else if (Validation.GetHasError(startdatePicker)) + { + BindingExpression start_be = startdatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(start_be); + } + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml new file mode 100644 index 000000000..bc99c1bfa --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml @@ -0,0 +1,787 @@ +<UserControl x:Class="Tango.MachineStudio.Statistics.Views.JobRunsView" + 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:sharedConverters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:localConverters="clr-namespace:Tango.MachineStudio.Statistics.Converters" + xmlns:localrule="clr-namespace:Tango.MachineStudio.Statistics.ValidationRules" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" + xmlns:tooltips="clr-namespace:Tango.MachineStudio.Statistics.Tooltips" + xmlns:sys="clr-namespace:System;assembly=mscorlib" + xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:local="clr-namespace:Tango.MachineStudio.Statistics.Views" + xmlns:model="clr-namespace:Tango.MachineStudio.Statistics.Models" + xmlns:vs="clr-namespace:Tango.MachineStudio.Statistics.ViewModels" + xmlns:wellknowntypes="clr-namespace:Google.Protobuf.WellKnownTypes;assembly=Google.Protobuf" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="1800" Foreground="{StaticResource JobFieldForeground}"> + <UserControl.Resources> + <sharedConverters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> + <sharedConverters:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter"/> + <sharedConverters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <localConverters:DateTimeToStringFormatConverter x:Key="DateTimeToStringFormatConverter" /> + <sharedConverters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter"/> + <localConverters:StringToBoolYesNoNullConverter x:Key="StringToBoolYesNoNullConverter"/> + <localConverters:LiquidTypeToColorConverter x:Key="LiquidTypeToColorConverter"/> + <localConverters:CollectionConverter x:Key="CollectionConverter"/> + <localConverters:StringToFirstLetterConverter x:Key="StringToFirstLetterConverter"/> + <localConverters:MidTankLevelToElementHeightConverter x:Key="MidTankLevelToElementHeightConverter"/> + <localConverters:JobLengthConverter x:Key="JobLengthConverter"/> + <localConverters:NanoLiterToLiterFormatConverter x:Key="NanoLiterToLiterFormatConverter"/> + <localConverters:LiquidQuantityToFormatStringConverter x:Key="LiquidQuantityToFormatStringConverter"/> + <localConverters:TooltipLiquidQuantityFormatConverter x:Key="TooltipLiquidQuantityFormatConverter"/> + + <ResourceDictionary x:Key="SelectAllTextBoxResource"> + <Style TargetType="TextBox"> + <EventSetter Event="GotFocus" Handler="TextBox_GotFocus"></EventSetter> + <EventSetter Event="MouseDown" Handler="TextBox_PreviewMouseUp"></EventSetter> + </Style> + </ResourceDictionary> + + <ObjectDataProvider x:Key="HeadCleaning" MethodName="GetValues" ObjectType="{x:Type sys:Enum}"> + <ObjectDataProvider.MethodParameters> + <x:Type TypeName="vs:HeadCleaningSelectionEnum"/> + </ObjectDataProvider.MethodParameters> + </ObjectDataProvider> + + <Style TargetType="{x:Type TextBlock}" x:Key="WrapText"> + <Setter Property="TextWrapping" Value="Wrap"/> + </Style> + + <Style TargetType="lvc:PieSeries"> + <Setter Property="Stroke" Value="#99F9F9F9"></Setter> + <Setter Property="StrokeThickness" Value="2"/> + <Setter Property="Foreground" Value="#FF1C1C1F" /> + </Style> + <Style TargetType="lvc:PieChart"> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="LegendLocation" Value="None"/> + </Style> + + <DataTemplate x:Key="PopUpDataTemplate"> + <CheckBox VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected}" Click="CheckBox_StayChecked" Tag="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},Mode=OneWay}"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data}"></TextBlock> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + + <DataTemplate x:Key="PopupBoolDataTemplate"> + <CheckBox VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected}" Click="CheckBox_StayChecked" Tag="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},Mode=OneWay}"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data, Converter={StaticResource BooleanToYesNoConverter}}"/> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + + + <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}" BasedOn="{StaticResource MaterialDesignToolTip}"> + <Setter Property="Background" Value="{StaticResource Logging.Background}" /> + <Setter Property="Foreground" Value="{StaticResource MainWindow.Foreground}" /> + </Style> + + </UserControl.Resources> + + <Grid IsEnabled="{Binding IsFree}" > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="3*"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid Grid.Row="0" Background="{StaticResource WhiteBackgroundBrush}" Width="Auto" Margin="20 0 0 1" > + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" CornerRadius="2" > + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + + <Grid > + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="1*"/> + </Grid.RowDefinitions> + <StackPanel Orientation="Horizontal" Grid.Row="0"> + <StackPanel Margin="10 5 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Machine:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="140" Margin="0 10 0 0" x:Name="selectMachineButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" Height="24"> + <DockPanel> + <Button x:Name="selectMachineButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="Button_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5"> + <TextBlock.Style> + <Style TargetType="{x:Type TextBlock}"> + <Setter Property="Text" Value="{Binding SelectedMachines.SynchedSource.Count, StringFormat={}Selected Machines({0})}"> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding SelectedMachines.SynchedSource.Count}" Value="0"> + <Setter Property="Text" Value="All machines"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <controls:AllSelectedCheckboxList Style="{StaticResource AllSelectedCheckBoxListStyle}" MaxHeight="600" ItemsSource="{Binding SelectedMachines}" Background="{StaticResource ComboBox.Floating.Background}" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Multiple" AllSelected="True" FontSize="11" FontFamily="{StaticResource FontName}"> + <controls:AllSelectedCheckboxList.ItemTemplate> + <DataTemplate > + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data.SerialNumber}" ToolTip="{Binding Data.SerialNumber}" FontFamily="{StaticResource FontName}" Background="{DynamicResource TransparentBackgroundBrush}" FontSize="11"></TextBlock> + + </DataTemplate> + </controls:AllSelectedCheckboxList.ItemTemplate> + </controls:AllSelectedCheckboxList> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + + <StackPanel Margin="30 10 0 0" HorizontalAlignment="Center"> + <TextBlock FontSize="11">Start Date:</TextBlock> + <DatePicker x:Name="startdatePicker" SelectedDateChanged="StartDatePicker_SelectedDateChanged" Margin="0 5 0 0" materialDesign:HintAssist.Hint="Pick start date" Width="130" VerticalAlignment="Center" FontSize="11" > + <DatePicker.SelectedDate> + <Binding Path="StartSelectedDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="StartDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + <StackPanel Margin="30 10 0 0" HorizontalAlignment="Center"> + <TextBlock FontSize="11">End Date:</TextBlock> + <DatePicker x:Name="endDatePicker" Margin="0 5 0 0" materialDesign:HintAssist.Hint="Pick end date" Width="130" VerticalAlignment="Center" FontSize="11" SelectedDateChanged="EndDatePicker_SelectedDateChanged"> + <DatePicker.SelectedDate> + <Binding Path="EndSelectedDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="EndDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + + </DatePicker> + </StackPanel> + </StackPanel> + + <StackPanel Orientation="Horizontal" Grid.Row="1"> + <StackPanel Margin="10 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Job Name:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <autoComplete:AutoCompleteTextBox Margin="0 10 0 0" Provider="{Binding JobsProvider}" Width="140" FontSize="11" LoadingContent="Loading..." SelectedItem="{Binding SelectedJob,Mode=TwoWay}" materialDesign:HintAssist.Hint="All" DisplayMember="Name" materialDesign:HintAssist.IsFloating="False"> + <autoComplete:AutoCompleteTextBox.ItemTemplate> + <DataTemplate> + <StackPanel> + <TextBlock Text="{Binding Name}" FontWeight="Bold" FontStyle="Italic"></TextBlock> + </StackPanel> + </DataTemplate> + </autoComplete:AutoCompleteTextBox.ItemTemplate> + </autoComplete:AutoCompleteTextBox> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Source:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="130" Height="24" Margin="0 10 0 0" x:Name="selectJobRunSources" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="jobRunSourcesButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="JobRunSourcesButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" Text="{Binding JobRunSelectedSources.SynchedSource, Converter={StaticResource CollectionConverter}}"/> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding JobRunSelectedSources}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopUpDataTemplate}"/> + + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Gradient:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="130" Margin="0 10 0 0" x:Name="selectIsGradient" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="isGradientButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="IsGradientButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5 0 2 0"> + <Run Text="{Binding IsGradientSelection.SynchedSource, Converter={StaticResource CollectionConverter}, ConverterParameter='No, Yes'}"></Run> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}"> + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding IsGradientSelection}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopupBoolDataTemplate}"/> + + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Length:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <Border BorderThickness="1" CornerRadius="3" BorderBrush="{StaticResource borderBrush}" Margin="0 10 0 0" Height="24" Padding="10 0"> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding LengthLowerValue, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" FontSize="11" Width="30"></TextBlock> + <mahapps:RangeSlider Focusable="True" Height="40" Margin="5 5 5 5" Minimum="0" Maximum="10000" Width="140" ExtendedMode="True" + LowerValue="{Binding LengthLowerValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + UpperValue="{Binding LengthUpperValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + VerticalAlignment="Center" IsSnapToTickEnabled="True" FontSize="8"/> + <TextBlock Text="{Binding LengthUpperValue}" VerticalAlignment="Center" FontSize="11" Width="30"></TextBlock> + </StackPanel> + </Border> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Status:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="170" Margin="0 10 0 0" x:Name="selectJobRunStatus" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="jobRunStatusButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="JobRunStatusButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" Text="{Binding JobRunSelectedStatuses.SynchedSource, Converter={StaticResource CollectionConverter}}"/> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding JobRunSelectedStatuses}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopUpDataTemplate}"/> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Threads:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="100" Margin="0 10 0 0" x:Name="selectThreadsButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" Height="24"> + <DockPanel> + <Button x:Name="selectThreadButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="SelectMachineButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" > + <TextBlock.Style> + <Style TargetType="{x:Type TextBlock}"> + <Setter Property="Text" Value="{Binding SelectedThreads.SynchedSource.Count, StringFormat={}Selected Threads({0})}"> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding SelectedThreads.SynchedSource.Count}" Value="0"> + <Setter Property="Text" Value="All threads"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <controls:AllSelectedCheckboxList Style="{StaticResource AllSelectedCheckBoxListStyle}" MaxHeight="600" ItemsSource="{Binding SelectedThreads}" Background="{StaticResource ComboBox.Floating.Background}" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Multiple" AllSelected="True" FontSize="11" FontFamily="{StaticResource FontName}"> + <controls:AllSelectedCheckboxList.ItemTemplate> + <DataTemplate > + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data.Name}" ToolTip="{Binding Data.Name}" FontFamily="{StaticResource FontName}"></TextBlock> + </DataTemplate> + </controls:AllSelectedCheckboxList.ItemTemplate> + </controls:AllSelectedCheckboxList> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="HeadCleaning:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="120" Margin="0 10 0 0" x:Name="isHeadCleaningToggleButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="IsHeadCleaningButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="IsHeadCleaningButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5 0 2 0" Text="{Binding HeadCleaningSelected, Converter={StaticResource EnumToDescriptionConverter}}"> + + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}"> + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ListBox x:Name="HeadCleaningListBoxItem" ItemsSource="{Binding Source={StaticResource HeadCleaning}}" Foreground="{StaticResource MainWindow.Foreground}" SelectedItem="{Binding HeadCleaningSelected, Mode=TwoWay}" SelectionMode="Single" > + <ListBox.ItemTemplate> + <DataTemplate> + <CheckBox x:Name="HeadCleaningCheckBox" Selector.IsSelected="True" VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, UpdateSourceTrigger=PropertyChanged}" Click="CheckBox_PreventUndoCheck"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Converter={StaticResource EnumToDescriptionConverter}}"/> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + </StackPanel> + </Grid> + <Button Grid.Column="1" HorizontalAlignment="Right" Command="{Binding LoadJobRunsCommand}" Margin="0 0 10 0" Padding="30 15" Height="Auto" VerticalAlignment="Center" Content="ANALYZE"> + <Button.Style> + <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> + <Setter Property="IsEnabled" Value="False"/> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference startdatePicker}}" Value="False"/> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference endDatePicker}}" Value="False"/> + </MultiDataTrigger.Conditions> + <Setter Property="IsEnabled" Value="True"/> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </Button.Style> + </Button> + </Grid> + </Border> + </Grid> + + <DataGrid x:Name="ItemsGrid" GridLinesVisibility="None" Grid.Row="1" Margin="20 0 0 10" SelectionMode="Single" SelectionUnit="FullRow" BorderBrush="{StaticResource borderBrush}" IsReadOnly="True" BorderThickness="1" RowHeight="80" + Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserReorderColumns="False" + CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding JobRuns}" HorizontalScrollBarVisibility="Disabled" CanUserResizeColumns="False" CanUserResizeRows="False" + SelectedItem="{Binding SelectedJobRun}" CanUserSortColumns="True" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" FontSize="11"> + + <DataGrid.Resources> + <Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"> + <Setter Property="HorizontalAlignment" Value="Left"></Setter> + <Setter Property="HorizontalContentAlignment" Value="Left"></Setter> + <Setter Property="Padding" Value="0 8 0 8"></Setter> + <Setter Property="Margin" Value="0 0 0 0"></Setter> + <Setter Property="FontWeight" Value="SemiBold"/> + </Style> + </DataGrid.Resources> + + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalAlignment" Value="Center"/> + <Setter Property="HorizontalAlignment" Value="Left"/> + <Setter Property="Margin" Value="0 0 10 0"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type DataGridCell}"> + <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.CellStyle> + <DataGrid.RowStyle> + <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}"> + <Setter Property="BorderThickness" Value="0 0 0 1"/> + <Setter Property="BorderBrush" Value="LightGray"/> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + <Setter Property="Cursor" Value="Hand"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + <Trigger Property="IsFocused" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.RowStyle> + + <DataGrid.Columns> + <DataGridTemplateColumn Header="" Width="50"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <materialDesign:PackIcon Width="24" Height="24" Margin="8 -5 0 0"> + <materialDesign:PackIcon.Style> + <Style TargetType="materialDesign:PackIcon"> + <Setter Property="Kind" Value="Check"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Completed"> + <Setter Property="Kind" Value="Check"></Setter> + <Setter Property="Foreground" Value="{StaticResource GreenOpenFileBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Aborted"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource OrangeBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Failed"> + <Setter Property="Kind" Value="AlertOctagon"></Setter> + <Setter Property="Foreground" Value="{StaticResource RedBrush100}"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </materialDesign:PackIcon.Style> + </materialDesign:PackIcon> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="ID" Binding="{Binding JobRun.ID}" Width="50" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Machine" Binding="{Binding Machine.SerialNumber}" Width="100" ></DataGridTextColumn> + <DataGridTextColumn Header="User" Binding="{Binding User.Contact.FullName,TargetNullValue='PPC',FallbackValue='PPC'}" Width="100" ElementStyle="{StaticResource WrapText}" /> + <DataGridTextColumn Header="Job Name" Binding="{Binding JobRun.JobName}" Width="100" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Thread" Binding="{Binding Rml.Name}" Width="80" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Length" Binding="{Binding JobRun.JobLength, StringFormat={}{0:0.00}}" Width="60" /> + <DataGridTextColumn Header="Source" Binding="{Binding JobRun.Source, Converter={StaticResource EnumToDescriptionConverter}}" Width="60" /> + <DataGridTextColumn Header="Upload Duration" Binding="{Binding UploadDuration, Converter={StaticResource DateTimeToStringFormatConverter}, FallbackValue='N/A',TargetNullValue='N/A'}" Width="80"/> + <DataGridTextColumn Header="Heating Duration" Binding="{Binding HeatingDuration, Converter={StaticResource DateTimeToStringFormatConverter}, FallbackValue='N/A',TargetNullValue='N/A'}" Width="80" /> + <DataGridTextColumn Header="Start Time" Binding="{Binding JobRun.ActualStartDate, Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="95" /> + <DataGridTextColumn Header="IsGradient" Binding="{Binding JobRun.IsGradient}" Width="70" /> + <DataGridTextColumn Header="GR" Binding="{Binding JobRun.GradientResolutionCm}" Width="30" /> + <DataGridTextColumn Header="Status" Binding="{Binding JobRun.JobRunStatus, Converter={StaticResource EnumToDescriptionConverter}}" Width="70"/> + <DataGridTextColumn Header="End Time" Binding="{Binding JobRun.EndDate, Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="95" /> + <DataGridTextColumn Header="End Position" Binding="{Binding JobRun.EndPosition, StringFormat={}{0:0.00}}" Width="70" /> + <DataGridTemplateColumn Header="Liquid Quantities" Width="1*"> + <DataGridTemplateColumn.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalAlignment" Value="Center"/> + <Setter Property="HorizontalAlignment" Value="Stretch"/> + <Setter Property="Margin" Value="0 0 10 0"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type DataGridCell}"> + <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGridTemplateColumn.CellStyle> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="20"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*" MaxWidth="200"/> + </Grid.ColumnDefinitions> + <ItemsControl ItemsSource="{Binding JobRun.LiquidQuantitiesFast,Mode=OneWay}" Margin="0 0 0 0" Height="70"> + <ItemsControl.ItemContainerStyle> + <Style TargetType="ContentPresenter"> + <Setter Property="Visibility" Value="Visible"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Quantity}" Value="0"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <StackPanel Orientation="Horizontal" IsItemsHost="True"></StackPanel> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <DockPanel ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}" ToolTipService.Placement="Center" ToolTipService.VerticalOffset="10"> + <Grid DockPanel.Dock="Top" Height="40" Margin="0 5 8 0" Width="16" > + <Border x:Name="LiquidTypeBorder" BorderThickness="1" BorderBrush="{StaticResource borderBrush}" CornerRadius="2" > + <Canvas x:Name="LiquidCanvas" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" ClipToBounds="True" ToolTip="{Binding Quantity}" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="10"> + <Border Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualHeight }" Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualWidth }" > + <Border.Background> + <SolidColorBrush Color="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" /> + </Border.Background> + <Border.Style> + <Style> + <Setter Property="Canvas.Top" > + <Setter.Value> + <MultiBinding Converter="{StaticResource MidTankLevelToElementHeightConverter}"> + <Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" /> + <Binding Path="Quantity" /> + </MultiBinding> + </Setter.Value> + </Setter> + </Style> + </Border.Style> + </Border> + <Border Background="Transparent" ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}" Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualHeight }" Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualWidth }"></Border> + </Canvas> + </Border> + </Grid> + <TextBlock DockPanel.Dock="Bottom" FontSize="9" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0" Text="{Binding LiquidType,Converter={StaticResource StringToFirstLetterConverter}}" Foreground="Gray"/> + </DockPanel> + + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <Border Grid.Row="1" Grid.Column="0" Background="Transparent" HorizontalAlignment="Stretch" Height="8" BorderThickness="1" BorderBrush="{StaticResource borderBrush}"> + <Rectangle Margin="0 0 -1 0" Fill="{StaticResource AccentColorBrush}" HorizontalAlignment="Left" VerticalAlignment="Stretch" ToolTip="{Binding JobRun.EndPosition}"> + <Rectangle.Width> + <MultiBinding Converter="{StaticResource JobLengthConverter}"> + <Binding Path="JobRun.JobLength" /> + <Binding Path="JobRun.EndPosition"/> + <Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType=Border}"/> + </MultiBinding> + </Rectangle.Width> + </Rectangle> + </Border> + </Grid> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + </DataGrid.Columns> + </DataGrid> + <Border Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Margin="20, 0, 20, 20" BorderBrush="{StaticResource borderBrush}" Background="{StaticResource TransparentBackgroundBrush}" BorderThickness="1"> + + <StackPanel> + <TextBlock Margin="10" Text="{Binding SelectedJobName}"></TextBlock> + </StackPanel> + </Border> + <Border Grid.Row="2" Margin="20, 0, 0, 20" Height="200" BorderBrush="{StaticResource borderBrush}" Background="{StaticResource TransparentBackgroundBrush}" BorderThickness="1"> + <Grid > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="2"/> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="2"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Border Grid.Column="0" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <StackPanel Orientation="Vertical" Margin="5"> + <ItemsControl ItemsSource="{Binding StatisticsValueCollection.StatisticsCollection}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal" Margin="0 3"> + <TextBlock Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:N2}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <TextBlock Visibility="Collapsed" Margin="0 10 0 0" Text="Total Thread Consumption per thread:" FontWeight="SemiBold"> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Visibility" Value="Visible" /> + <Style.Triggers> + <DataTrigger Binding="{Binding StatisticsValueCollection.ThreadConsumptionPerThreadCollection.Count}" Value="0"> + <Setter Property="Visibility" Value="Collapsed" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + <ItemsControl Visibility="Collapsed" ItemsSource="{Binding StatisticsValueCollection.ThreadConsumptionPerThreadCollection}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Rows="3" /> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.Resources> + <DataTemplate DataType="{x:Type model:StatisticsValue}"> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:0.0}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + <DataTemplate DataType="{x:Type model:MoreValue}"> + <Border BorderThickness="0"> + <TextBlock Text="{Binding Text}" Tag="{Binding Path=DataContext.StatisticsValueCollection.ThreadConsumptionPerThread, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}}" HorizontalAlignment="Left" VerticalAlignment="Center" > + <TextBlock.ToolTip > + <ToolTip DataContext="{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Tag}" Placement="Right" Background="{StaticResource Logging.Background}"> + <Border CornerRadius="5"> + <ItemsControl ItemsSource="{Binding }"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal" Margin="2"> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:N0}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Border> + </ToolTip> + </TextBlock.ToolTip> + </TextBlock> + </Border> + </DataTemplate> + </ItemsControl.Resources> + </ItemsControl> + </StackPanel> + </Border> + <Border Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="2" Background="{StaticResource borderBrush}" Margin="0 4" Visibility="Visible"></Border> + <Border Grid.Column="2" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <UniformGrid Columns="3"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="PPC/MS"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieJobSource.SeriesCollection}" > + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="Failed/Aborted/Completed"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieJobRunStatus.SeriesCollection}"> + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="Gradient/Solid"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieGradientSolid.SeriesCollection}" > + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + </UniformGrid> + </DockPanel> + </Border> + + <Border Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="2" Background="{StaticResource borderBrush}" Margin="0 6" CornerRadius="1"/> + + <Border Grid.Column="4" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding StatisticsValueCollection.LiquidQuantities}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Columns="3"/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border Background="Transparent" ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}"> + <StackPanel Orientation="Horizontal" Margin="4"> + <Ellipse Width="30" Height="30"> + <Ellipse.Fill> + <SolidColorBrush Color="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" /> + </Ellipse.Fill> + </Ellipse> + <StackPanel Orientation="Vertical" Margin="4"> + <TextBlock Text="{Binding LiquidType,Converter={StaticResource EnumToDescriptionConverter}}" FontWeight="SemiBold"></TextBlock> + <TextBlock > + <Run Text="{Binding Quantity, Converter={StaticResource NanoLiterToLiterFormatConverter}, ConverterParameter='0.00'}"></Run> + <Run Text=" liters"></Run> + </TextBlock> + </StackPanel> + </StackPanel> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <Border Background="Transparent" ToolTip="{Binding StatisticsValueCollection.TotalLiquidQuantities, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}"> + <TextBlock DockPanel.Dock="Bottom" Margin="4 10 0 0 "> + <Run Text="Total liquid quantities for all: " FontWeight="SemiBold"/> + <Run Text="{Binding StatisticsValueCollection.TotalLiquidQuantities, Converter={StaticResource NanoLiterToLiterFormatConverter}, ConverterParameter='0.00'}"></Run> + <Run Text=" liters"></Run> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Visibility" Value="Visible" /> + <Style.Triggers> + <DataTrigger Binding="{Binding StatisticsValueCollection.LiquidQuantities.Count}" Value="0"> + <Setter Property="Visibility" Value="Collapsed" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </Border> + </DockPanel> + </Border> + </Grid> + </Border> + <Grid Grid.Row="0" Grid.Column="1" Margin="20 0 20 0"> + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" CornerRadius="2" > + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + + <Button Grid.Column="1" HorizontalAlignment="Right" Command="{Binding ExportToExcelCommand}" Margin="0 0 10 0" Padding="10 15" Height="Auto" VerticalAlignment="Center" Width="Auto">EXPORT TO EXCEL</Button> + </Border> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs new file mode 100644 index 000000000..961d7f691 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs @@ -0,0 +1,175 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +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.SharedUI.Components; + +namespace Tango.MachineStudio.Statistics.Views +{ + /// <summary> + /// Interaction logic for JobRunsView.xaml + /// </summary> + public partial class JobRunsView : UserControl + { + private int _lastSelectedGridItemIndex; + public JobRunsView() + { + InitializeComponent(); + _lastSelectedGridItemIndex = -1; + } + + + private void Button_Click(object sender, RoutedEventArgs e) + { + selectMachineButton.IsChecked = true; + e.Handled = true; + } + + private void JobRunSourcesButton_Click(object sender, RoutedEventArgs e) + { + selectJobRunSources.IsChecked = true; + e.Handled = true; + } + private void IsGradientButton_Click(object sender, RoutedEventArgs e) + { + selectIsGradient.IsChecked = true; + e.Handled = true; + } + private void JobRunStatusButton_Click(object sender, RoutedEventArgs e) + { + selectJobRunStatus.IsChecked = true; + e.Handled = true; + } + + private async void TextBox_GotFocus(object sender, RoutedEventArgs e) + { + await Task.Delay(200); + TextBox txtBox = sender as TextBox; + txtBox.SelectAll(); + } + + private void TextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + } + + private void SelectMachineButton_Click(object sender, RoutedEventArgs e) + { + selectThreadsButton.IsChecked = true; + e.Handled = true; + } + + private void IsHeadCleaningButton_Click(object sender, RoutedEventArgs e) + { + isHeadCleaningToggleButton.IsChecked = true; + e.Handled = true; + } + + private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + DataGrid dataGrid = sender as DataGrid; + _lastSelectedGridItemIndex = -1; + if (e.AddedItems != null && e.AddedItems.Count > 0) + { + DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromItem(e.AddedItems[0]); + if (row != null) + { + _lastSelectedGridItemIndex = row.GetIndex(); + } + } + } + + private void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if(datePickerObj != null && datePickerObj.SelectedDate != null && endDatePicker.SelectedDate != null) + { + if(datePickerObj.SelectedDate> endDatePicker.SelectedDate) + { + BindingExpression start_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(StartDateExpiredRule, start_be); + validationError.ErrorContent = "The start time must be less than or equal to end time."; + Validation.MarkInvalid(start_be, validationError); + } + else if (Validation.GetHasError(endDatePicker)) + { + BindingExpression end_be = endDatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(end_be); + } + } + } + + private void EndDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj.SelectedDate != null && startdatePicker.SelectedDate != null ) + { + if(datePickerObj != null && datePickerObj.SelectedDate < startdatePicker.SelectedDate) + { + BindingExpression end_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(EndDateExpiredRule, end_be); + validationError.ErrorContent = "The end time must be greater than or equal to the start time."; + Validation.MarkInvalid(end_be, validationError); + } + else if (Validation.GetHasError(startdatePicker)) + { + BindingExpression start_be = startdatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(start_be); + } + } + } + + private void CheckBox_PreventUndoCheck(object sender, RoutedEventArgs e) + { + if( sender is CheckBox) + { + CheckBox cb = sender as CheckBox; + if (cb.IsChecked == false) + { + cb.IsChecked = true; + e.Handled = true; + return; + } + } + e.Handled = false; + } + private void CheckBox_StayChecked(object sender, RoutedEventArgs e) + { + if (sender is CheckBox) + { + CheckBox cb = sender as CheckBox; + if (cb.IsChecked == false) + { + var col = cb.Tag; + Type type = col.GetType(); + if (col != null && col.GetType().GetGenericTypeDefinition() == typeof(SelectedObjectCollection<>)) + { + dynamic dSynchedSource = type.GetProperty("SynchedSource").GetValue(col); + if(dSynchedSource != null && dSynchedSource.GetType().GetGenericTypeDefinition() == typeof(ObservableCollection<>) && dSynchedSource.Count == 0) + { + cb.IsChecked = true; + e.Handled = true; + return; + } + } + } + } + e.Handled = false; + } + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml index 55804c7b3..21c099db9 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml @@ -11,100 +11,28 @@ xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - <Grid IsEnabled="{Binding IsFree}"> + <Grid> <Grid.RowDefinitions> - <RowDefinition Height="80"/> - <RowDefinition Height="337*"/> + <RowDefinition Height="1*"/> + <RowDefinition Height="20"/> </Grid.RowDefinitions> - - <StackPanel Margin="60 20 0 0" VerticalAlignment="Center" HorizontalAlignment="Left" Orientation="Horizontal"> - <StackPanel> - <TextBlock FontSize="10">Start Date:</TextBlock> - <DatePicker DisplayDateStart="{Binding MinDate}" DisplayDateEnd="{Binding MaxDate}" SelectedDate="{Binding StartDate}" materialDesign:HintAssist.Hint="Pick start date" Width="200" VerticalAlignment="Bottom" FontSize="16"></DatePicker> - </StackPanel> - - <StackPanel Margin="40 0 0 0"> - <TextBlock FontSize="10">End Date:</TextBlock> - <DatePicker DisplayDateStart="{Binding MinDate}" DisplayDateEnd="{Binding MaxDate}" SelectedDate="{Binding EndDate}" materialDesign:HintAssist.Hint="Pick end date" Width="200" VerticalAlignment="Bottom" FontSize="16"></DatePicker> - </StackPanel> - </StackPanel> - - <UniformGrid Columns="3" Margin="50 20 50 50" Rows="2" Grid.Row="1"> - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding TimelineJobStatusSeries.Title}"></TextBlock> - <lvc:CartesianChart Series="{Binding TimelineJobStatusSeries.SeriesCollection}" LegendLocation="Bottom" SeriesColors="{Binding TimelineJobStatusSeries.SeriesColors}"> - <lvc:CartesianChart.DataTooltip> - <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> - </lvc:CartesianChart.DataTooltip> - <lvc:CartesianChart.AxisX> - <lvc:Axis Title="{Binding TimelineJobStatusSeries.LabelsTitle}" Labels="{Binding TimelineJobStatusSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> - <lvc:Axis.Separator> - <lvc:Separator Stroke="#A5A5A5" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisX> - <lvc:CartesianChart.AxisY> - <lvc:Axis Title="{Binding TimelineJobStatusSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > - <lvc:Axis.Separator> - <lvc:Separator Stroke="#B0B0B0" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisY> - </lvc:CartesianChart> - </DockPanel> - </Border> - - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PieJobFailedReasons.Title}"></TextBlock> - <UniformGrid Columns="2"> - <lvc:PieChart DataHover="PieChart_DataHover" Series="{Binding PieJobFailedReasons.SeriesCollection}" LegendLocation="None" SeriesColors="{Binding PieJobFailedReasons.SeriesColors}" Background="Transparent"> - <lvc:PieChart.Resources> - <Style TargetType="lvc:PieSeries"> - <Setter Property="Stroke" Value="#99F9F9F9"></Setter> - <Setter Property="StrokeThickness" Value="2"/> - </Style> - </lvc:PieChart.Resources> - <lvc:PieChart.DataTooltip> - <tooltips:PieChartTooltipControl Visibility="Hidden" /> - </lvc:PieChart.DataTooltip> - </lvc:PieChart> - - <TextBlock x:Name="txtPieTitle" TextWrapping="Wrap"></TextBlock> - </UniformGrid> - </DockPanel> - </Border> - - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PrintPerWeekSeries.Title}"></TextBlock> - <lvc:CartesianChart Series="{Binding PrintPerWeekSeries.SeriesCollection}" LegendLocation="Bottom" SeriesColors="{Binding PrintPerWeekSeries.SeriesColors}" > - <lvc:CartesianChart.Resources> - <Style TargetType="lvc:ColumnSeries"> - <Setter Property="Foreground" Value="{StaticResource DarkGrayBrush200}"></Setter> - </Style> - </lvc:CartesianChart.Resources> - <lvc:CartesianChart.AxisX> - <lvc:Axis Title="{Binding PrintPerWeekSeries.LabelsTitle}" Labels="{Binding PrintPerWeekSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> - <lvc:Axis.Separator> - <lvc:Separator Stroke="#A5A5A5" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisX> - <lvc:CartesianChart.AxisY> - <lvc:Axis Title="{Binding PrintPerWeekSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > - <lvc:Axis.Separator> - <lvc:Separator Stroke="#6F6F6F" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisY> - <lvc:CartesianChart.DataTooltip> - <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> - </lvc:CartesianChart.DataTooltip> - </lvc:CartesianChart> - </DockPanel> - </Border> - </UniformGrid> + <Grid Grid.Row="0" IsEnabled="{Binding IsFree}"> + <TabControl Background="Transparent" Margin="0,40,0,0" x:Name="chartsTabControl" Padding="0 25 0 0"> + <TabControl.Resources> + <Style TargetType="TabPanel"> + <Setter Property="HorizontalAlignment" Value="Center"/> + </Style> + <Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}"> + <Setter Property="Padding" Value="20,2"></Setter> + </Style> + </TabControl.Resources> + <TabItem Header="JOB RUNS" Margin="-100 0 0 0 "> + <local:JobRunsView x:Name="jobRunsView" DataContext="{Binding JobRunsViewVM}"/> + </TabItem> + <TabItem Header="STATS" Margin="-100 0 0 0 "> + <local:ChartsView x:Name="processParametersView" DataContext="{Binding ChartsViewVM}"/> + </TabItem> + </TabControl> + </Grid> </Grid> </UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs index 3948c4e5a..f0d1c39a7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs @@ -28,10 +28,6 @@ namespace Tango.MachineStudio.Statistics.Views InitializeComponent(); } - private void PieChart_DataHover(object sender, ChartPoint chartPoint) - { - var tooltip = ((chartPoint.ChartView as PieChart).DataTooltip as Tooltips.PieChartTooltipControl).Title; - txtPieTitle.Text = tooltip; - } + } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config index 31c5f029f..6938c8a4b 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> <package id="LiveCharts" version="0.9.7" targetFramework="net461" /> <package id="LiveCharts.Wpf" version="0.9.7" targetFramework="net461" /> <package id="MahApps.Metro" version="1.5.0" targetFramework="net461" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage_yjpbed13_wpftmp.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage_yjpbed13_wpftmp.csproj new file mode 100644 index 000000000..698c6fe82 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Storage/Tango.MachineStudio.Storage_yjpbed13_wpftmp.csproj @@ -0,0 +1,154 @@ +<?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>{5991F6B5-EA4E-41E9-A4F6-7D3A50010FD6}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.MachineStudio.Storage</RootNamespace> + <AssemblyName>Tango.MachineStudio.Storage</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\Machine Studio\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\Machine Studio\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="Converters\StorageItemToImageConverter.cs" /> + <Compile Include="Helpers\FileIconHelper.cs" /> + <Compile Include="Models\StorageFileHandlerModel.cs" /> + <Compile Include="Models\StorageFileHandlerType.cs" /> + <Compile Include="StorageModule.cs" /> + <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + </ItemGroup> + <ItemGroup> + <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> + <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.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.SharedUI\Tango.SharedUI.csproj"> + <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project> + <Name>Tango.SharedUI</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj"> + <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> + <Name>Tango.Transport</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Utilities\Tango.FirmwarePackageGenerator\Tango.FirmwarePackageGenerator.csproj"> + <Project>{43135fb9-41db-4f87-9771-cf2c762027c0}</Project> + <Name>Tango.FirmwarePackageGenerator</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.MachineStudio.Common\Tango.MachineStudio.Common.csproj"> + <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project> + <Name>Tango.MachineStudio.Common</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup /> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <ItemGroup> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Utilities\Debug\fpgen.exe" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MahApps.Metro.1.5.0\lib\net45\MahApps.Metro.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MaterialDesignColors.1.1.2\lib\net45\MaterialDesignColors.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\MaterialDesignThemes.2.3.1.953\lib\net45\MaterialDesignThemes.Wpf.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.Drawing.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\MahApps.Metro.1.5.0\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.Core.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\Machine Studio\Debug\Tango.MachineStudio.Common.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.Transport.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\WindowsBase.dll" /> + </ItemGroup> + <ItemGroup> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.Storage\obj\Debug\App.g.cs" /> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.Storage\obj\Debug\Views\MainView.g.cs" /> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\MachineStudio\Modules\Tango.MachineStudio.Storage\obj\Debug\GeneratedInternalTypeHelper.g.cs" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/BlowerElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/BlowerElementEditor.xaml index 524dd79c5..dae945940 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/BlowerElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/BlowerElementEditor.xaml @@ -56,8 +56,8 @@ </i:Interaction.Triggers> </visuals:AnalogSwitch> - <Border Background="{StaticResource DarkGrayBrush}" Margin="8" CornerRadius="3" Padding="5" Grid.Column="1"> - <Grid> + <Border Background="#1B1B1B" Margin="8" CornerRadius="3" Padding="5" Grid.Column="1"> + <Grid > <mahapps:NumericUpDown Style="{x:Null}" InterceptMouseWheel="True" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Right" HideUpDownButtons="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HasDecimals="True" Minimum="0" Maximum="10000" Padding="0" Value="{Binding HardwareBlower.Voltage,FallbackValue='0.0',Mode=TwoWay}" VerticalAlignment="Center" FontSize="44" FontFamily="{StaticResource digital-7}" Foreground="#FFD400" Margin="0 0 16 0"> <mahapps:NumericUpDown.Resources> <Style TargetType="TextBox"> @@ -72,7 +72,7 @@ <Button Style="{x:Null}" Grid.Column="2" Margin="8" Cursor="Hand" Command="{Binding SetCommand}"> <Button.Template> <ControlTemplate TargetType="Button"> - <Grid Background="{StaticResource GrayBrush280}"> + <Grid Background="#3E3E3E"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gainsboro" FontSize="16" FontWeight="SemiBold">SET</TextBlock> </Grid> <ControlTemplate.Triggers> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ControllerElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ControllerElementEditor.xaml index 27530ab10..e71f7e1e0 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ControllerElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ControllerElementEditor.xaml @@ -86,7 +86,7 @@ <RowDefinition Height="70*"/> <RowDefinition Height="90*"/> </Grid.RowDefinitions> - <Border Background="{StaticResource DarkGrayBrush}" Margin="0 3 0 0" CornerRadius="3" Padding="5"> + <Border Background="#1B1B1B" Margin="0 3 0 0" CornerRadius="3" Padding="5"> <Grid> <TextBlock Text="{Binding EffectiveValue,StringFormat=0.0,FallbackValue='0.0'}" Foreground="#FF6F78" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="44" FontFamily="{StaticResource digital-7}" Margin="0 0 12 0"> @@ -95,7 +95,7 @@ </Grid> </Border> - <Border Background="{StaticResource DarkGrayBrush}" Grid.Row="1" Margin="0 10 0 0" CornerRadius="3" Padding="5"> + <Border Background="#1B1B1B" Grid.Row="1" Margin="0 10 0 0" CornerRadius="3" Padding="5"> <Grid> <mahapps:NumericUpDown Style="{x:Null}" InterceptMouseWheel="True" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Right" HideUpDownButtons="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" StringFormat="0.0" HasDecimals="True" Minimum="{Binding ElementName=fader,Path=Minimum}" Maximum="{Binding ElementName=fader,Path=Maximum}" Padding="0" Value="{Binding Value,Mode=TwoWay,StringFormat=0.0,FallbackValue=0.0}" VerticalAlignment="Center" FontSize="44" FontFamily="{StaticResource digital-7}" Foreground="#FFD400" Margin="0 0 12 0"> <mahapps:NumericUpDown.Resources> @@ -111,7 +111,7 @@ <Button Style="{x:Null}" Grid.Row="2" VerticalAlignment="Bottom" Height="60" Cursor="Hand" Command="{Binding SetCommand}"> <Button.Template> <ControlTemplate TargetType="Button"> - <Grid Background="{StaticResource GrayBrush280}"> + <Grid Background="#1B1B1B"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gainsboro" FontSize="16" FontWeight="SemiBold">SET</TextBlock> </Grid> <ControlTemplate.Triggers> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/DispenserElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/DispenserElementEditor.xaml index 90e18d43e..e0da8aa03 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/DispenserElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/DispenserElementEditor.xaml @@ -170,7 +170,7 @@ </Grid> <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 -65 0"> - <Border Background="{StaticResource DarkGrayBrush}" CornerRadius="3" Padding="3"> + <Border Background="#1B1B1B" CornerRadius="3" Padding="3"> <mahapps:NumericUpDown BorderThickness="0" Background="Transparent" HideUpDownButtons="True" HasDecimals="False" Minimum="0" Maximum="10000" StringFormat="0" Value="{Binding Speed,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat=0,FallbackValue=5000}" HorizontalAlignment="Center" HorizontalContentAlignment="Center" FontSize="22" VerticalAlignment="Center" Foreground="{StaticResource RedBrush400}" FontFamily="{StaticResource digital-7}"></mahapps:NumericUpDown> </Border> <visuals:Knob Width="50" Height="50" TicksHighlightBrush="{StaticResource RedBrush400}" KnobType="MetroDark" TicksWidth="2" Margin="0 5 0 0" TicksHeight="5" Minimum="0" Maximum="5000" Value="{Binding Speed,Mode=TwoWay}" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/HeaterElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/HeaterElementEditor.xaml index 190b4d3c8..ffeb1f134 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/HeaterElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/HeaterElementEditor.xaml @@ -48,7 +48,7 @@ </Grid> <Grid Grid.Row="1"> - <Border Background="{StaticResource DarkGrayBrush}" Margin="0 3 0 0" CornerRadius="3" Padding="5"> + <Border Background="#1B1B1B" Margin="0 3 0 0" CornerRadius="3" Padding="5"> <Grid> <TextBlock Text="{Binding HeaterState.CurrentValue,StringFormat=0.00,FallbackValue='0.00'}" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="80" FontFamily="{StaticResource digital-7}" Margin="0 0 12 0"> <TextBlock.Style> @@ -75,7 +75,7 @@ <Image Source="../Images/temperature.png" Margin="0 10 20 10" RenderOptions.BitmapScalingMode="Fant"></Image> - <Border Background="{StaticResource DarkGrayBrush}" Margin="0 3 0 0" CornerRadius="3" Padding="5" Grid.Column="1"> + <Border Background="#1B1B1B" Margin="0 3 0 0" CornerRadius="3" Padding="5" Grid.Column="1"> <Grid> <mahapps:NumericUpDown x:Name="txtSetPoint" InterceptMouseWheel="True" IsHitTestVisible="{Binding IsEditing}" InterceptArrowKeys="True" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Right" HideUpDownButtons="True" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" HasDecimals="True" Minimum="0" Maximum="400" Padding="0" Value="{Binding SetPoint,FallbackValue='0.0',Mode=TwoWay}" VerticalAlignment="Center" FontSize="44" FontFamily="{StaticResource digital-7}" Foreground="#FFD400" Margin="0 0 12 0"> <mahapps:NumericUpDown.Resources> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/JobRunnerElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/JobRunnerElementEditor.xaml index 5165e9819..b57db3d3f 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/JobRunnerElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/JobRunnerElementEditor.xaml @@ -43,7 +43,7 @@ <!--Content--> <Grid> - <Border Padding="10" BorderThickness="1" BorderBrush="{StaticResource DarkGrayBrush}" Background="#88FFFFFF" CornerRadius="5"> + <Border Padding="10" BorderThickness="1" BorderBrush="{StaticResource DarkGrayBrush}" Background="{StaticResource TransparentBackgroundBrush}" CornerRadius="5"> <DockPanel> <TextBox Foreground="{StaticResource DarkGrayBrush}" FontSize="14" DockPanel.Dock="Top" Text="{Binding Job.Name}"></TextBox> <ItemsControl Margin="0 10 0 0" DockPanel.Dock="Top" ItemsSource="{Binding BrushStop.LiquidVolumes}" VerticalAlignment="Center"> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/MotorElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/MotorElementEditor.xaml index 7c3728d1e..77cccaf8f 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/MotorElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/MotorElementEditor.xaml @@ -154,7 +154,7 @@ </Viewbox> <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 -65 5"> - <Border Background="{StaticResource DarkGrayBrush}" CornerRadius="3" Padding="3"> + <Border Background="#1B1B1B" CornerRadius="3" Padding="3"> <mahapps:NumericUpDown BorderThickness="0" Background="Transparent" HideUpDownButtons="True" HasDecimals="False" Minimum="0" Maximum="10000" StringFormat="0" Value="{Binding Speed,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat=0,FallbackValue=5000}" HorizontalAlignment="Center" HorizontalContentAlignment="Center" FontSize="22" VerticalAlignment="Center" Foreground="{StaticResource RedBrush400}" FontFamily="{StaticResource digital-7}"></mahapps:NumericUpDown> </Border> <visuals:Knob Width="50" Height="50" TicksHighlightBrush="{StaticResource RedBrush400}" KnobType="MetroDark" TicksWidth="2" Margin="0 5 0 0" TicksHeight="5" Minimum="0" Maximum="5000" Value="{Binding Speed,Mode=TwoWay}" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ProcessParametersElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ProcessParametersElementEditor.xaml index 3c4373097..b86f52688 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ProcessParametersElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ProcessParametersElementEditor.xaml @@ -57,8 +57,8 @@ <Grid Margin="0 2" Focusable="False" Background="Transparent" Style="{StaticResource draggableDroppableGrid}" dragAndDrop:DragAndDropService.Drop="OnProcessParametersDropped" dragAndDrop:DragAndDropService.DraggingSurface="{Binding RelativeSource={RelativeSource AncestorType=editors:ParameterizedEditor},Path=DraggingSurface}"> <ContentControl Focusable="False"> <DockPanel Focusable="False"> - <TextBlock Focusable="False" Width="150" FontSize="12" Foreground="{StaticResource DarkGrayBrush}" DockPanel.Dock="Left" IsHitTestVisible="False" Margin="0 5 0 5" Text="{Binding Name}"></TextBlock> - <mahapps:NumericUpDown FontSize="14" Minimum="0" Margin="0 0 5 0" HorizontalContentAlignment="Left" HideUpDownButtons="True" Maximum="10000" StringFormat="0.0" InterceptArrowKeys="True" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}" Background="#6EFFFFFF"></mahapps:NumericUpDown> + <TextBlock Focusable="False" Width="150" FontSize="12" Foreground="#1B1B1B" DockPanel.Dock="Left" IsHitTestVisible="False" Margin="0 5 0 5" Text="{Binding Name}"></TextBlock> + <mahapps:NumericUpDown FontSize="14" Minimum="0" Margin="0 0 5 0" HorizontalContentAlignment="Left" HideUpDownButtons="True" Maximum="10000" StringFormat="0.0" InterceptArrowKeys="True" InterceptMouseWheel="True" HasDecimals="True" Value="{Binding Value,Mode=TwoWay}" Background="{StaticResource TransparentBackgroundBrush600}"></mahapps:NumericUpDown> </DockPanel> </ContentControl> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ThreadMotionElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ThreadMotionElementEditor.xaml index ac440ad64..d59a8ddbb 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ThreadMotionElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ThreadMotionElementEditor.xaml @@ -68,7 +68,7 @@ </Viewbox> <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 -65 5"> - <Border Background="{StaticResource DarkGrayBrush}" CornerRadius="3" Padding="3"> + <Border Background="#1B1B1B" CornerRadius="3" Padding="3"> <mahapps:NumericUpDown BorderThickness="0" Background="Transparent" HideUpDownButtons="True" HasDecimals="False" Minimum="0" Maximum="10000" StringFormat="0" Value="{Binding Speed,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat=0,FallbackValue=5000}" HorizontalAlignment="Center" HorizontalContentAlignment="Center" FontSize="22" VerticalAlignment="Center" Foreground="{StaticResource RedBrush400}" FontFamily="{StaticResource digital-7}"></mahapps:NumericUpDown> </Border> <visuals:Knob Width="50" Height="50" TicksHighlightBrush="{StaticResource RedBrush400}" KnobType="MetroDark" TicksWidth="2" Margin="0 5 0 0" TicksHeight="5" Minimum="0" Maximum="5000" Value="{Binding Speed,Mode=TwoWay}" /> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ValveElementEditor.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ValveElementEditor.xaml index 59b9fa2af..20e4b46ff 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ValveElementEditor.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Editors/ValveElementEditor.xaml @@ -46,7 +46,7 @@ <Button Margin="8" Cursor="Hand" Command="{Binding SetCommand}" CommandParameter="{Binding TechValve.State1}"> <Button.Style> <Style TargetType="Button"> - <Setter Property="Background" Value="{StaticResource GrayBrush280}"></Setter> + <Setter Property="Background" Value="#3E3E3E"></Setter> <Setter Property="IsEnabled" Value="True"></Setter> </Style> </Button.Style> @@ -80,7 +80,7 @@ </Button.Template> </Button> - <Border Background="{StaticResource DarkGrayBrush}" Margin="8" CornerRadius="3" Padding="5" Grid.Column="1"> + <Border Background="#1B1B1B" Margin="8" CornerRadius="3" Padding="5" Grid.Column="1"> <StackPanel> <TextBlock FontFamily="{StaticResource digital-7}" Text="Valve Controller" FontSize="13" Foreground="#E94A4A" HorizontalAlignment="Center"></TextBlock> <Image Source="../Images/valve.png" RenderOptions.BitmapScalingMode="Fant" Margin="10" Stretch="Uniform" Height="36" /> @@ -90,7 +90,7 @@ <Button Margin="8" Cursor="Hand" Grid.Column="2" Command="{Binding SetCommand}" CommandParameter="{Binding TechValve.State2}"> <Button.Style> <Style TargetType="Button"> - <Setter Property="Background" Value="{StaticResource GrayBrush280}"></Setter> + <Setter Property="Background" Value="#3E3E3E"></Setter> <Setter Property="IsEnabled" Value="True"></Setter> </Style> </Button.Style> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs index f6b8a35df..8f5c67f96 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs @@ -41,6 +41,7 @@ using RealTimeGraphX.WPF; using Tango.Core.ExtensionMethods; using System.Diagnostics; using Tango.BL.Builders; +using Tango.Core; namespace Tango.MachineStudio.Technician.ViewModels { @@ -79,6 +80,12 @@ namespace Tango.MachineStudio.Technician.ViewModels private DateTime _last_time = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0); private Machine _machine; private List<PackColor> _packsColors; + private int _diagnostics_index = 0; + private DateTime _diagnosticsStartTime; + private DateTime _diagnosticsNowTime; + + private ProducerConsumerQueue<StartDiagnosticsResponse> _framesQueue; + private Thread _populateFramesThread; #region Properties @@ -113,6 +120,8 @@ namespace Tango.MachineStudio.Technician.ViewModels { _selectedTab.IsSelected = true; } + + EnableRenderingForSelectedTabGraphs(); } } @@ -309,6 +318,8 @@ namespace Tango.MachineStudio.Technician.ViewModels /// <param name="notificationProvider">The notification provider.</param> public MachineTechViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IEventLogger eventLogger) { + _framesQueue = new ProducerConsumerQueue<StartDiagnosticsResponse>(); + Tabs = new ObservableCollection<MachineTechTabVM>(); Tabs.Add(new MachineTechTabVM() { IsSelected = true, Name = "Untitled" }); SelectedTab = Tabs.First(); @@ -411,7 +422,7 @@ namespace Tango.MachineStudio.Technician.ViewModels PackColor pc = new PackColor(); pc.Index = pack.PackIndex; pc.Name = pack.LiquidType.Name; - + if (pack.LiquidType.LiquidTypeColor == Colors.Black) { pc.Color = Colors.Gray; @@ -443,26 +454,52 @@ namespace Tango.MachineStudio.Technician.ViewModels /// <param name="response">The response.</param> private void DiagnosticsFrameProvider_FrameReceived(object sender, StartDiagnosticsResponse response) { - PopulateDiagnosticsData(response); + _framesQueue.BlockEnqueue(response); } #endregion #region Populate Diagnostics Data + private void PopulateFramesThreadMethod() + { + while (!ApplicationManager.IsShuttingDown) + { + var frame = _framesQueue.BlockDequeue(); + PopulateDiagnosticsData(frame); + } + } + /// <summary> /// Populates the diagnostics data to the proper elements. /// </summary> /// <param name="data">The data.</param> private void PopulateDiagnosticsData(StartDiagnosticsResponse data) { - if (data.Monitors == null) return; + if (data.Monitors == null || _machineOperator == null || _machineOperator.DeviceInformation == null) return; + + _diagnostics_index++; + uint interval = _machineOperator.DeviceInformation.DiagnosticsInterval; TimeSpan delta_base = DateTime.Now - _start_time; TimeSpan delta = (DateTime.Now - _last_time); - double delta_mili = delta.TotalMilliseconds; _last_time = DateTime.Now; + if (data.ElapsedMilli > 0) + { + _diagnosticsNowTime = DateTime.ParseExact(data.DateTime, "MM/dd/yyyy HH:mm:ss.fff", null); //_diagnosticsNowTime.Add(TimeSpan.FromMilliseconds(data.ElapsedMilli)); + //var now = _diagnosticsStartTime.Add(TimeSpan.FromMilliseconds(interval * _diagnostics_index)); + //Debug.WriteLine("DeltaBase Before: " + delta_base); + delta_base = _diagnosticsNowTime - _start_time; + //Debug.WriteLine("DeltaBase After: " + delta_base); + + //Debug.WriteLine("Delta Before: " + delta); + delta = TimeSpan.FromMilliseconds(data.ElapsedMilli); + //Debug.WriteLine("Delta After: " + delta); + } + + double delta_mili = delta.TotalMilliseconds; + if (DateTime.Now > _lastDiagnosticsResponseUpdate.AddMilliseconds(MIN_DIAGNOSTICS_UPDATE_MILI)) { CurrentDiagnosticsResponse = data; @@ -479,7 +516,11 @@ namespace Tango.MachineStudio.Technician.ViewModels if (prop != null) { var points = GetDataArray(techMonitor, prop.GetValue(data.Monitors)); - sr.PushData(points, delta_base, delta); + + if (points.Count > 0) + { + sr.PushData(points, delta_base, delta); + } } } @@ -492,15 +533,20 @@ namespace Tango.MachineStudio.Technician.ViewModels if (prop != null) { var points = GetDataMatrix(techMonitor, prop.GetValue(data.Monitors)); - mr.PushData(points, delta_base, delta); + if (points.Count > 0) + { + mr.PushData(points, delta_base, delta); + } } } lock (_elementsLock) { var elements = Tabs.SelectMany(x => x.Elements).ToList(); + var selectedTabElements = SelectedTab.Elements.ToList(); - foreach (var item in elements.Select(x => x.HostedElement as TechItem)) + //Can be updated only when visible + foreach (var item in selectedTabElements.Select(x => x.HostedElement as TechItem)) { if (item.GetType() == typeof(MonitorItem)) { @@ -530,7 +576,79 @@ namespace Tango.MachineStudio.Technician.ViewModels } } } - else if (item.GetType() == typeof(SingleGraphItem)) + else if (item.GetType() == typeof(DigitalOutItem)) + { + DigitalOutItem digitalOutItem = item as DigitalOutItem; + + var digitalPin = data.DigitalInterfaceStates.SingleOrDefault(x => x.InterfaceIO == (InterfaceIOs)digitalOutItem.TechIo.Code); + + if (digitalPin != null) + { + digitalOutItem.EffectiveValue = digitalPin.Value; + } + } + else if (item.GetType() == typeof(DigitalInItem)) + { + DigitalInItem digitalInItem = item as DigitalInItem; + + var digitalPin = data.DigitalInterfaceStates.SingleOrDefault(x => x.InterfaceIO == (InterfaceIOs)digitalInItem.TechIo.Code); + + if (digitalPin != null) + { + digitalInItem.Value = digitalPin.Value; + } + } + else if (item.GetType() == typeof(HeaterItem)) + { + HeaterItem heaterItem = item as HeaterItem; + + var heaterState = data.HeatersStates.SingleOrDefault(x => x.HeaterType == (HeaterType)heaterItem.TechHeater.Code); + + if (heaterState != null) + { + heaterItem.HeaterState = heaterState; + } + } + else if (item.GetType() == typeof(ValveItem)) + { + ValveItem valveItem = item as ValveItem; + + var valveState = data.ValvesStates.SingleOrDefault(x => x.ValveType == (ValveType)valveItem.TechValve.Code); + + if (valveState != null) + { + valveItem.EffectiveState = valveState.State; + } + } + else if (item.GetType() == typeof(BlowerItem)) + { + BlowerItem blowerItem = item as BlowerItem; + + if (data.Monitors.BlowerVoltage.Count > 0) + { + blowerItem.EffectiveActive = data.Monitors.BlowerVoltage.Last() > 0; + } + } + else if (item.GetType() == typeof(ControllerItem)) + { + ControllerItem controllerItem = item as ControllerItem; + + if (DateTime.Now > controllerItem.LastUpdateTime.AddMilliseconds(controllerItem.UpdateInterval)) + { + var componentState = data.ComponentsStates.SingleOrDefault(x => (int)x.Component == controllerItem.TechController.Code); + + if (componentState != null) + { + controllerItem.EffectiveValue = componentState.Value; + } + } + } + } + + //Must be updated all the time. + foreach (var item in elements.Select(x => x.HostedElement as TechItem)) + { + if (item.GetType() == typeof(SingleGraphItem)) { SingleGraphItem graphItem = item as SingleGraphItem; @@ -544,20 +662,23 @@ namespace Tango.MachineStudio.Technician.ViewModels { var points = GetDataArray(graphItem.TechMonitor, prop.GetValue(data.Monitors)); - List<TimeSpanDataPoint> times = new List<TimeSpanDataPoint>(); - var dPoints = points.Select(x => new DoubleDataPoint(x)).ToList(); - - for (int i = 0; i < points.Count; i++) + if (points.Count > 0) { - times.Add(delta_base.Add(TimeSpan.FromMilliseconds((delta_mili / points.Count) * i))); - } + List<TimeSpanDataPoint> times = new List<TimeSpanDataPoint>(); + var dPoints = points.Select(x => new DoubleDataPoint(x)).ToList(); - controller.PushData(times, dPoints); + for (int i = 0; i < points.Count; i++) + { + times.Add(delta_base.Add(TimeSpan.FromMilliseconds((delta_mili / points.Count) * i))); + } - var _graph_recording = _single_graphs_recordings.SingleOrDefault(x => x.Tag == graphItem); - if (_graph_recording != null) - { - _graph_recording.PushData(points, delta_base, delta); + controller.PushData(times, dPoints); + + var _graph_recording = _single_graphs_recordings.SingleOrDefault(x => x.Tag == graphItem); + if (_graph_recording != null) + { + _graph_recording.PushData(points, delta_base, delta); + } } } } @@ -620,70 +741,82 @@ namespace Tango.MachineStudio.Technician.ViewModels } } } - else if (item.GetType() == typeof(DigitalOutItem)) - { - DigitalOutItem digitalOutItem = item as DigitalOutItem; + } + } + } - var digitalPin = data.DigitalInterfaceStates.SingleOrDefault(x => x.InterfaceIO == (InterfaceIOs)digitalOutItem.TechIo.Code); + #endregion - if (digitalPin != null) - { - digitalOutItem.EffectiveValue = digitalPin.Value; - } - } - else if (item.GetType() == typeof(DigitalInItem)) - { - DigitalInItem digitalInItem = item as DigitalInItem; + #region Private Methods - var digitalPin = data.DigitalInterfaceStates.SingleOrDefault(x => x.InterfaceIO == (InterfaceIOs)digitalInItem.TechIo.Code); + private void EnableRenderingForSelectedTabGraphs() + { + if (SelectedTab != null) + { + lock (_elementsLock) + { + var elements = Tabs.SelectMany(x => x.Elements).ToList(); - if (digitalPin != null) - { - digitalInItem.Value = digitalPin.Value; - } - } - else if (item.GetType() == typeof(HeaterItem)) + foreach (var element in elements) { - HeaterItem heaterItem = item as HeaterItem; + if (SelectedTab.Elements.Contains(element)) + { + var item = element.HostedElement as TechItem; - var heaterState = data.HeatersStates.SingleOrDefault(x => x.HeaterType == (HeaterType)heaterItem.TechHeater.Code); + if (item != null) + { + if (item.GetType() == typeof(SingleGraphItem)) + { + SingleGraphItem graphItem = item as SingleGraphItem; - if (heaterState != null) - { - heaterItem.HeaterState = heaterState; - } - } - else if (item.GetType() == typeof(ValveItem)) - { - ValveItem valveItem = item as ValveItem; + TechGraphController controller = null; - var valveState = data.ValvesStates.SingleOrDefault(x => x.ValveType == (ValveType)valveItem.TechValve.Code); + if (_singleControllers.TryGetValue(graphItem, out controller)) + { + controller.DisableRendering = false; + } + } + else if (item.GetType() == typeof(MultiGraphItem)) + { + MultiGraphItem graphItem = item as MultiGraphItem; - if (valveState != null) - { - valveItem.EffectiveState = valveState.State; - } - } - else if (item.GetType() == typeof(BlowerItem)) - { - BlowerItem blowerItem = item as BlowerItem; + TechGraphController controller = null; - if (data.Monitors.BlowerVoltage.Count > 0) - { - blowerItem.EffectiveActive = data.Monitors.BlowerVoltage.Last() > 0; + if (_multiControllers.TryGetValue(graphItem, out controller)) + { + controller.DisableRendering = false; + } + } + } } - } - else if (item.GetType() == typeof(ControllerItem)) - { - ControllerItem controllerItem = item as ControllerItem; - - if (DateTime.Now > controllerItem.LastUpdateTime.AddMilliseconds(controllerItem.UpdateInterval)) + else { - var componentState = data.ComponentsStates.SingleOrDefault(x => (int)x.Component == controllerItem.TechController.Code); + var item = element.HostedElement as TechItem; - if (componentState != null) + if (item != null) { - controllerItem.EffectiveValue = componentState.Value; + if (item.GetType() == typeof(SingleGraphItem)) + { + SingleGraphItem graphItem = item as SingleGraphItem; + + TechGraphController controller = null; + + if (_singleControllers.TryGetValue(graphItem, out controller)) + { + controller.DisableRendering = true; + } + } + else if (item.GetType() == typeof(MultiGraphItem)) + { + MultiGraphItem graphItem = item as MultiGraphItem; + + TechGraphController controller = null; + + if (_multiControllers.TryGetValue(graphItem, out controller)) + { + controller.DisableRendering = true; + } + } } } } @@ -691,10 +824,6 @@ namespace Tango.MachineStudio.Technician.ViewModels } } - #endregion - - #region Private Methods - /// <summary> /// Gets the last data point from a protobuf repeated field. /// </summary> @@ -1251,7 +1380,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, String.Format("Error executing technician set valve state command on '{0}'.", item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician set valve state command on '{0}'.", item.TechName)); } }; } @@ -1272,7 +1400,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, $"Error executing SetBlowerState command for blower {item.HardwareBlower.HardwareBlowerType.Name}."); - _eventLogger.Log(ex, $"Error executing SetBlowerState command for blower {item.HardwareBlower.HardwareBlowerType.Name}."); } }; } @@ -1293,7 +1420,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, $"Error executing SetHeaterState command for heater {item.TechHeater.Name}."); - _eventLogger.Log(ex, $"Error executing SetHeaterState command for heater {item.TechHeater.Name}."); } }; } @@ -1390,7 +1516,6 @@ namespace Tango.MachineStudio.Technician.ViewModels item.HomingProgress = 0; item.HomingMaximumProgress = 0; LogManager.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); } }; } @@ -1488,7 +1613,6 @@ namespace Tango.MachineStudio.Technician.ViewModels item.HomingProgress = 0; item.HomingMaximumProgress = 0; LogManager.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); } }; } @@ -1642,7 +1766,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, String.Format(String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName))); - _eventLogger.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); } }; } @@ -1726,7 +1849,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician command '{0}' on item '{1}'.", action, item.TechName)); } }; } @@ -1747,7 +1869,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, String.Format("Error executing technician set digital out command on '{0}'.", item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician set digital out command on '{0}'.", item.TechName)); } }; } @@ -1772,7 +1893,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { LogManager.Log(ex, String.Format("Error executing technician set value component command on '{0}'.", item.TechName)); - _eventLogger.Log(ex, String.Format("Error executing technician set value component command on '{0}'.", item.TechName)); } }; } @@ -1798,7 +1918,6 @@ namespace Tango.MachineStudio.Technician.ViewModels catch (Exception ex) { String msg = "Error uploading process parameters:" + Environment.NewLine + parameters.ToJsonString(); - _eventLogger.Log(ex, msg); LogManager.Log(ex, msg); _notification.ShowError("Could not upload process parameters." + Environment.NewLine + ex.Message); } @@ -2097,16 +2216,41 @@ namespace Tango.MachineStudio.Technician.ViewModels { var to_remove = Tabs.ToList(); - if (AddNewTab()) + var name = _notification.ShowTextInput("Enter project name", "Project Name", "untitled"); + + if (String.IsNullOrWhiteSpace(name)) { - _singleControllers.Clear(); - _multiControllers.Clear(); + return; + } - foreach (var tab in to_remove) - { - Tabs.Remove(tab); - } + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Title = "Select Technician Project Location"; + dlg.Filter = "Technician Project File|*.tpf"; + dlg.DefaultExt = ".tpf"; + dlg.FileName = name; + + if (!dlg.ShowDialog().Value) + { + return; } + + _singleControllers.Clear(); + _multiControllers.Clear(); + _multi_graph_recordings.Clear(); + _multi_monitors_recordings.Clear(); + _single_graphs_recordings.Clear(); + _single_monitors_recordings.Clear(); + + foreach (var tab in to_remove) + { + Tabs.Remove(tab); + } + + AddNewTab(name); + + _lastTechProjectFile = dlg.FileName; + File.AppendAllText(_lastTechProjectFile, ""); + SaveProject(); } /// <summary> @@ -2179,7 +2323,12 @@ namespace Tango.MachineStudio.Technician.ViewModels public override void OnApplicationReady() { - + if (_populateFramesThread == null) + { + _populateFramesThread = new Thread(PopulateFramesThreadMethod); + _populateFramesThread.IsBackground = true; + _populateFramesThread.Start(); + } } #endregion diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Converters/RoleEnumToVisibleConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Converters/RoleEnumToVisibleConverter.cs new file mode 100644 index 000000000..350257fdd --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Converters/RoleEnumToVisibleConverter.cs @@ -0,0 +1,32 @@ +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 Tango.BL.Enumerations; + +namespace Tango.MachineStudio.UsersAndRoles.Converters +{ + public class RoleEnumToVisibleConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value.GetType().IsEnum && Enum.IsDefined(typeof(Roles), value)) + { + Roles roleEnum = (Roles)value; + if (roleEnum.ToString().StartsWith("FSE")) + return Visibility.Collapsed; + } + + return Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/login.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/login.png Binary files differnew file mode 100644 index 000000000..9f7d0b9ba --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/login.png diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj index 82376b751..687544c1b 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj @@ -49,6 +49,9 @@ <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> </Reference> + <Reference Include="SimpleValidator, Version=0.6.1.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\SimpleValidator.0.6.1.0\lib\net40\SimpleValidator.dll</HintPath> + </Reference> <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> @@ -72,6 +75,7 @@ <Compile Include="..\..\..\Versioning\GlobalVersionInfo.cs"> <Link>GlobalVersionInfo.cs</Link> </Compile> + <Compile Include="Converters\RoleEnumToVisibleConverter.cs" /> <Compile Include="Navigation\UsersAndRolesNavigationManager.cs" /> <Compile Include="Navigation\UsersAndRolesNavigationView.cs" /> <Compile Include="Providers\PlaceAddress.cs" /> @@ -80,6 +84,7 @@ <Compile Include="UsersAndRolesModule.cs" /> <Compile Include="ViewModelLocator.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="ViewModels\UserCreationDialogVM.cs" /> <Compile Include="Views\AddressView.xaml.cs"> <DependentUpon>AddressView.xaml</DependentUpon> </Compile> @@ -95,6 +100,9 @@ <Compile Include="Views\OrganizationSelectionView.xaml.cs"> <DependentUpon>OrganizationSelectionView.xaml</DependentUpon> </Compile> + <Compile Include="Views\UserCreationDialog.xaml.cs"> + <DependentUpon>UserCreationDialog.xaml</DependentUpon> + </Compile> <Compile Include="Views\UserManagementView.xaml.cs"> <DependentUpon>UserManagementView.xaml</DependentUpon> </Compile> @@ -120,7 +128,9 @@ <Generator>ResXFileCodeGenerator</Generator> <LastGenOutput>Resources.Designer.cs</LastGenOutput> </EmbeddedResource> - <None Include="app.config" /> + <None Include="app.config"> + <SubType>Designer</SubType> + </None> <None Include="packages.config" /> <None Include="Properties\Settings.settings"> <Generator>SettingsSingleFileGenerator</Generator> @@ -186,6 +196,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\UserCreationDialog.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\UserManagementView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -210,6 +224,9 @@ <ItemGroup> <Resource Include="Images\roles.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\login.png" /> + </ItemGroup> <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs index a46d5f456..16395d6bc 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs @@ -15,6 +15,10 @@ using Tango.MachineStudio.UsersAndRoles.Providers; using Tango.SharedUI; using System.Data.Entity; using Tango.BL.Builders; +using Tango.BL.ActionLogs; +using Tango.BL.DTO; +using Tango.BL.Enumerations; +using Tango.MachineStudio.Common.Authentication; namespace Tango.MachineStudio.UsersAndRoles.ViewModels { @@ -25,6 +29,10 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels private ObservablesContext _userContext; private UsersAndRolesNavigationManager _navigation; private INotificationProvider _notification; + private IActionLogManager _actionLogManager; + private OrganizationDTO _organizationBeforeSave; + private IAuthenticationProvider _authenticationProvider; + private UserDTO _userBeforeSave; private ObservableCollection<Organization> _organizations; public ObservableCollection<Organization> Organizations @@ -105,6 +113,21 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels } } + private bool _showDeleted; + public bool ShowDeleted + { + get { return _showDeleted; } + set + { + _showDeleted = value; + if (_showDeleted) + { + //ShowDeletedUsers(); + } + } + } + + public RelayCommand ManageOrganizationCommand { get; set; } public RelayCommand BackToOrganizationsCommand { get; set; } @@ -123,14 +146,18 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels public RelayCommand SaveManagedUserCommand { get; set; } + public RelayCommand RestoreAndSaveManagedUserCommand { get; set; } + public RelayCommand AddUserCommand { get; set; } public RelayCommand RemoveUserCommand { get; set; } - public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification) + public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification, IActionLogManager actionLogManager, IAuthenticationProvider authenticationProvider) { _navigation = navigation; _notification = notification; + _actionLogManager = actionLogManager; + _authenticationProvider = authenticationProvider; ManageOrganizationCommand = new RelayCommand(LoadSelectedOrganization, () => SelectedOrganization != null); BackToOrganizationsCommand = new RelayCommand(BackToOrganizations); @@ -141,8 +168,10 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels BackToManagedOrganizationCommand = new RelayCommand(BackToManagedOrganization); RemoveRoleCommand = new RelayCommand<Role>(RemoveUserRole); SaveManagedUserCommand = new RelayCommand(SaveManagedUser); + RestoreAndSaveManagedUserCommand = new RelayCommand(RestoreAndSaveManagedUser); AddUserCommand = new RelayCommand(AddNewUser); RemoveUserCommand = new RelayCommand(RemoveSelectedUser, () => SelectedUser != null); + _showDeleted = false; } public override void OnApplicationReady() @@ -164,6 +193,7 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels org.Contact = new Contact(); _organizationsContext.Organizations.Add(org); await org.SaveAsync(_organizationsContext); + _actionLogManager.InsertLog(ActionLogType.OrganizationCreated, _authenticationProvider.CurrentUser, org.Name, org, "Organization created using Machine Studio."); Organizations = _organizationsContext.Organizations.ToObservableCollection(); SelectedOrganization = org; LoadSelectedOrganization(); @@ -178,6 +208,7 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels using (_notification.PushTaskItem("Removing organization...")) { await SelectedOrganization.DeleteCascadeAsync(_organizationsContext); + _actionLogManager.InsertLog(ActionLogType.OrganizationDeleted, _authenticationProvider.CurrentUser, SelectedOrganization.Name, SelectedOrganization, "Organization deleted using Machine Studio."); await LoadOrganizations(); } } @@ -187,7 +218,13 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels { using (_notification.PushTaskItem("Saving organization address and contact...")) { + var organizationAfter = OrganizationDTO.FromObservable(ManagedOrganization); + await ManagedOrganization.SaveAsync(_manageContext); + _actionLogManager.InsertLog(ActionLogType.OrganizationSaved, _authenticationProvider.CurrentUser, ManagedOrganization.Name, _organizationBeforeSave, organizationAfter, "Organization saved using Machine Studio."); + + _organizationBeforeSave = organizationAfter; + await LoadOrganizations(); SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); } @@ -202,8 +239,10 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels _userContext = ObservablesContext.CreateDefault(); Roles = new RolesCollectionBuilder(_userContext).SetAll().WithPermission().Build(); - ManagedUser = new UserBuilder(_userContext).Set(SelectedUser.Guid).WithRolesAndPermissions().Build(); + ManagedUser = new UserBuilder(_userContext).WithDeleted().Set(SelectedUser.Guid).WithRolesAndPermissions().Build(); ManagedUserRoles = ManagedUser.Roles.ToObservableCollection(); + + _userBeforeSave = UserDTO.FromObservable(ManagedUser); }); _navigation.NavigateTo(UsersAndRolesNavigationView.UserManagementView); @@ -235,6 +274,11 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels try { ManagedUser.Validate(_userContext); + + if (ManagedUser.Roles.GroupBy(x => x.RoleEnum).Any(x => x.Count() > 1)) + { + throw new InvalidOperationException("Cannot save user with duplicate roles."); + } } catch (Exception ex) { @@ -244,11 +288,45 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels using (_notification.PushTaskItem("Saving user details...")) { + var userAfter = UserDTO.FromObservable(ManagedUser); await ManagedUser.SaveAsync(_userContext); + _actionLogManager.InsertLog(ActionLogType.UserSaved, _authenticationProvider.CurrentUser, ManagedUser.Email, _userBeforeSave, userAfter, "User saved using Machine Studio."); + _userBeforeSave = userAfter; LoadSelectedOrganization(); } } + private async void RestoreAndSaveManagedUser() + { + try + { + ManagedUser.Validate(_userContext); + + if (ManagedUser.Roles.GroupBy(x => x.RoleEnum).Any(x => x.Count() > 1)) + { + throw new InvalidOperationException("Cannot save user with duplicate roles."); + } + } + catch (Exception ex) + { + _notification.ShowError(ex.Message); + return; + } + if (_notification.ShowQuestion("Are you sure you wish to re-activate this account?")) + { + using (_notification.PushTaskItem("Saving user details...")) + { + ManagedUser.Deleted = false; + + var userAfter = UserDTO.FromObservable(ManagedUser); + await ManagedUser.SaveAsync(_userContext); + _actionLogManager.InsertLog(ActionLogType.UserRestored, _authenticationProvider.CurrentUser, ManagedUser.Email, _userBeforeSave, userAfter, "User restored using Machine Studio."); + _userBeforeSave = userAfter; + LoadSelectedOrganization(); + } + } + } + private async void LoadSelectedOrganization() { using (_notification.PushTaskItem("Loading organization...")) @@ -257,7 +335,9 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels { _manageContext = ObservablesContext.CreateDefault(); - ManagedOrganization = new OrganizationBuilder(_manageContext).Set(SelectedOrganization.Guid).WithUsers().Build(); + ManagedOrganization = new OrganizationBuilder(_manageContext).Set(SelectedOrganization.Guid).WithUsers(true).Build(); + + _organizationBeforeSave = OrganizationDTO.FromObservable(ManagedOrganization); }); _navigation.NavigateTo(UsersAndRolesNavigationView.OrganizationManagementView); @@ -294,25 +374,25 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels using (_notification.PushTaskItem("Removing user...")) { await SelectedUser.DeleteCascadeAsync(_manageContext); + _actionLogManager.InsertLog(ActionLogType.UserDeleted, _authenticationProvider.CurrentUser, SelectedUser.Email, SelectedUser, "User deleted using Machine Studio."); LoadSelectedOrganization(); } } } - private async void AddNewUser() + private void AddNewUser() { - String email = _notification.ShowTextInput("Enter user email", "email"); - - if (!String.IsNullOrWhiteSpace(email)) + _notification.ShowModalDialog<UserCreationDialogVM>(async (vm) => { User user = new User(); - user.Email = email; - user.Password = "1111"; + user.Email = vm.Email; + user.Password = User.GetPasswordHash(vm.Password); + user.PasswordChangeRequired = true; user.Contact = new Contact() { - FirstName = "Twine", - LastName = "User", - Email = email, + FirstName = vm.FirstName, + LastName = vm.LastName, + Email = vm.Email, }; user.Address = new Address(); @@ -323,9 +403,25 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels Role = _manageContext.Roles.SingleOrDefault(x => x.Code == (int)BL.Enumerations.Roles.User) }); + user.UsersRoles.Add(new UsersRole() + { + User = user, + Role = _manageContext.Roles.SingleOrDefault(x => x.Code == (int)BL.Enumerations.Roles.MachineStudioUser) + }); + + user.UsersRoles.Add(new UsersRole() + { + User = user, + Role = _manageContext.Roles.SingleOrDefault(x => x.Code == (int)BL.Enumerations.Roles.PPCUser) + }); + try { - user.Validate(_manageContext); + if (!user.Validate(_manageContext)) + { + _notification.ShowError(String.Join(Environment.NewLine, user.ValidationErrors)); + return; + } } catch (Exception ex) { @@ -338,10 +434,13 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels using (_notification.PushTaskItem("Adding new user...")) { await ManagedOrganization.SaveAsync(_manageContext); + _actionLogManager.InsertLog(ActionLogType.UserCreated, _authenticationProvider.CurrentUser, user.Email, user, "User created using Machine Studio."); await LoadOrganizations(); SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); + SelectedUser = user; + LoadSelectedUser(); } - } + }); } private void SetUserPlace(Place place) diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/UserCreationDialogVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/UserCreationDialogVM.cs new file mode 100644 index 000000000..08762ac96 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/UserCreationDialogVM.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SimpleValidator.Extensions; +using Tango.SharedUI; + +namespace Tango.MachineStudio.UsersAndRoles.ViewModels +{ + public class UserCreationDialogVM : DialogViewVM + { + private static Random rnd = new Random(); + + private String _email; + [Required(ErrorMessage = "Email is required")] + [EmailAddress(ErrorMessage = "Please provide a valid email")] + public String Email + { + get { return _email; } + set { _email = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _password; + public String Password + { + get { return _password; } + set { _password = value; RaisePropertyChangedAuto(); } + } + + private String _firstName; + [Required(ErrorMessage = "First name is required")] + public String FirstName + { + get { return _firstName; } + set { _firstName = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private String _lastName; + [Required(ErrorMessage = "Last name is required")] + public String LastName + { + get { return _lastName; } + set { _lastName = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + protected override void Accept() + { + if (Validate()) + { + base.Accept(); + } + } + + public override void OnShow() + { + base.OnShow(); + Password = GetRandomPassword(4); + } + + private String GetRandomPassword(int count) + { + String pass = String.Empty; + + for (int i = 0; i < count; i++) + { + pass += rnd.Next(0, 9).ToString(); + } + + return pass; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml index d5a5d41d7..a14d59949 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml @@ -82,6 +82,10 @@ </Button> </StackPanel> </Grid> + <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" VerticalAlignment="Center" Margin="0 10 0 5" HorizontalAlignment="Left"> + <CheckBox Name="cbShowDeleted" IsChecked="{Binding ShowDeleted}" VerticalAlignment="Center"></CheckBox> + <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" Text="Show deleted accounts" FontSize="16" FontWeight="Normal"></TextBlock> + </StackPanel> <Grid DockPanel.Dock="Bottom"> <StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Left" Margin="0 0 0 0"> <Button Margin="0 0 10 0" MinWidth="160" Height="50" Background="{StaticResource RedBrush300}" BorderBrush="{StaticResource RedBrush300}" Command="{Binding RemoveUserCommand}"> @@ -113,6 +117,28 @@ <Setter Property="BorderThickness" Value="0"/> <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="Visibility" Value="Visible" /> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding ElementName=cbShowDeleted, Path=IsChecked}" Value="False"/> + <Condition Binding="{Binding Deleted}" Value="True"/> + </MultiDataTrigger.Conditions> + <MultiDataTrigger.Setters> + <Setter Property="Visibility" Value="Collapsed" /> + </MultiDataTrigger.Setters> + </MultiDataTrigger> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding ElementName=cbShowDeleted, Path=IsChecked}" Value="true"/> + <Condition Binding="{Binding Deleted}" Value="True"/> + </MultiDataTrigger.Conditions> + <MultiDataTrigger.Setters> + <Setter Property="Visibility" Value="Visible" /> + <Setter Property="Foreground" Value="{StaticResource RedBrush100}" /> + </MultiDataTrigger.Setters> + </MultiDataTrigger> + </Style.Triggers> </Style> </DataGrid.CellStyle> <DataGrid.Columns> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.xaml new file mode 100644 index 000000000..7433d3768 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.xaml @@ -0,0 +1,53 @@ +<UserControl x:Class="Tango.MachineStudio.UsersAndRoles.Views.UserCreationDialog" + 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:global="clr-namespace:Tango.MachineStudio.UsersAndRoles" + xmlns:vm="clr-namespace:Tango.MachineStudio.UsersAndRoles.ViewModels" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.MachineStudio.UsersAndRoles.Views" + mc:Ignorable="d" + d:DesignHeight="400" d:DesignWidth="700" Height="400" Width="700" Background="{StaticResource WhiteBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:UserCreationDialogVM, IsDesignTimeCreatable=False}"> + <Grid Margin="10"> + <DockPanel> + <Grid DockPanel.Dock="Top"> + <StackPanel Orientation="Horizontal"> + <Grid> + <Image Source="../Images/login.png" Width="80" RenderOptions.BitmapScalingMode="Fant"></Image> + <materialDesign:PackIcon HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 -14 -10" Kind="PlusCircle" Foreground="#15C315" Width="42" Height="42" /> + </Grid> + <TextBlock Margin="30 0 0 0" VerticalAlignment="Bottom" FontSize="22">NEW USER</TextBlock> + </StackPanel> + </Grid> + + <Grid DockPanel.Dock="Bottom"> + <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" DockPanel.Dock="Bottom"> + <Button Command="{Binding CloseCommand}" Width="140" Height="40" Margin="0 0 10 0"> + CANCEL + </Button> + <Button Command="{Binding OKCommand}" IsDefault="True" Width="140" Height="40"> + CREATE + </Button> + </StackPanel> + </Grid> + + <Grid> + <StackPanel Width="400" HorizontalAlignment="Center" Margin="20"> + <controls:TableGrid RowHeight="40"> + <TextBlock>EMAIL</TextBlock> + <TextBox Text="{Binding Email,UpdateSourceTrigger=LostFocus,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + <TextBlock>FIRST NAME</TextBlock> + <TextBox Text="{Binding FirstName,UpdateSourceTrigger=LostFocus,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + <TextBlock>LAST NAME</TextBlock> + <TextBox Text="{Binding LastName,UpdateSourceTrigger=LostFocus,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + </controls:TableGrid> + + <TextBox Margin="0 -15 0 0" Style="{x:Null}" BorderThickness="0" FontSize="30" HorizontalAlignment="Center" Text="{Binding Password}" IsReadOnly="True"></TextBox> + <TextBlock HorizontalAlignment="Center" Margin="0 5 0 0" Foreground="{StaticResource GrayBrush}">Provide this password to the user</TextBlock> + </StackPanel> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.xaml.cs new file mode 100644 index 000000000..cfa389ed1 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserCreationDialog.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.MachineStudio.UsersAndRoles.Views +{ + /// <summary> + /// Interaction logic for UserCreationDialog.xaml + /// </summary> + public partial class UserCreationDialog : UserControl + { + public UserCreationDialog() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml index bb003f525..2a8621e5c 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml @@ -14,11 +14,15 @@ xmlns:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" xmlns:local="clr-namespace:Tango.MachineStudio.UsersAndRoles.Views" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:localconverters="clr-namespace:Tango.MachineStudio.UsersAndRoles.Converters" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <UserControl.Resources> <providers:PlacesProvider x:Key="PlacesProvider" /> + <converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"></converters:BooleanToVisibilityConverter> + <converters:BooleanToVisibilityInverseConverter x:Key="BooleanToVisibilityInverseConverter"></converters:BooleanToVisibilityInverseConverter> + <localconverters:RoleEnumToVisibleConverter x:Key="RoleEnumToVisibleConverter"/> </UserControl.Resources> <Grid> @@ -48,7 +52,7 @@ <StackPanel> <TextBlock FontSize="16" FontWeight="SemiBold">LOGIN</TextBlock> <Border Width="300" BorderThickness="1" BorderBrush="Gray" Margin="0 5 0 0" Padding="15 5" Height="150" Background="{StaticResource TransparentBackgroundBrush500}"> - <local:UserView FontSize="10" DataContext="{Binding ManagedUser}" /> + <local:UserView VerticalAlignment="Top" Margin="0 15 0 0" FontSize="10" DataContext="{Binding ManagedUser}" /> </Border> </StackPanel> <StackPanel Margin="10 0 0 0"> @@ -74,12 +78,18 @@ </Grid> </Grid> <Grid DockPanel.Dock="Bottom"> - <Button Margin="0 10 0 0" MinWidth="200" Height="60" Command="{Binding SaveManagedUserCommand}" HorizontalAlignment="Right"> + <Button Margin="0 10 0 0" MinWidth="200" Height="60" Command="{Binding SaveManagedUserCommand}" HorizontalAlignment="Right" Visibility="{Binding Path=ManagedUser.Deleted, Converter={StaticResource BooleanToVisibilityInverseConverter}}"> <StackPanel Orientation="Horizontal"> <TextBlock FontSize="18" VerticalAlignment="Center">SAVE</TextBlock> <materialDesign:PackIcon Margin="5 0 0 0" Kind="ContentSave" Width="30" Height="30" /> </StackPanel> </Button> + <Button Margin="0 10 0 0" MinWidth="200" Height="60" Background="{StaticResource OrangeBrush300}" BorderBrush="{StaticResource OrangeBrush300}" Command="{Binding RestoreAndSaveManagedUserCommand}" HorizontalAlignment="Right" Visibility="{Binding Path=ManagedUser.Deleted, Converter={StaticResource BoolToVisibilityConverter}}"> + <StackPanel Orientation="Horizontal"> + <TextBlock FontSize="18" VerticalAlignment="Center" Text="RESTORE & SAVE"/> + <materialDesign:PackIcon Margin="5 0 0 0" Kind="ContentSave" Width="30" Height="30" /> + </StackPanel> + </Button> </Grid> <Grid> <DockPanel Margin="0 20 0 0"> @@ -95,7 +105,7 @@ </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate DataType="{x:Type entities:Role}"> - <Grid> + <Grid Visibility="{Binding RoleEnum, Converter={StaticResource RoleEnumToVisibleConverter}}"> <Grid.ToolTip> <StackPanel Background="Transparent"> <TextBlock Text="{Binding Description}" FontSize="10" Margin="0 0 0 10"></TextBlock> @@ -167,7 +177,7 @@ <ListBox ItemsSource="{Binding Roles}" ItemContainerStyle="{StaticResource basicListBoxItem}" HorizontalContentAlignment="Stretch" Background="Transparent"> <ListBox.ItemTemplate> <DataTemplate> - <Grid Background="Transparent" IsHitTestVisible="True" Style="{StaticResource draggableGrid}" dragAndDrop:DragAndDropService.DraggableBorderBrush="{StaticResource AccentColorBrush}" dragAndDrop:DragAndDropService.Draggable="True" dragAndDrop:DragAndDropService.DraggingSurface="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DraggingSurface}"> + <Grid Background="Transparent" IsHitTestVisible="True" Style="{StaticResource draggableGrid}" dragAndDrop:DragAndDropService.DraggableBorderBrush="{StaticResource AccentColorBrush}" dragAndDrop:DragAndDropService.Draggable="True" dragAndDrop:DragAndDropService.DraggingSurface="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DraggingSurface}" Visibility="{Binding RoleEnum, Converter={StaticResource RoleEnumToVisibleConverter}}"> <Grid.ToolTip> <StackPanel Background="Transparent"> <TextBlock Text="{Binding Description}" FontSize="10" Margin="0 0 0 10"></TextBlock> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml index 0858d7e08..37f649a7a 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml @@ -16,8 +16,6 @@ <controls:TableGrid> <TextBlock Text="EMAIL"></TextBlock> <TextBox Text="{Binding Email}"></TextBox> - <TextBlock Text="PASSWORD"></TextBlock> - <PasswordBox MaxLength="30" pass:PasswordHelper.Attach="True" pass:PasswordHelper.Password="{Binding PasswordGateWay,Mode=TwoWay}"></PasswordBox> </controls:TableGrid> </Grid> </UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config index fe4f26e87..8696cb880 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config @@ -7,4 +7,5 @@ <package id="MaterialDesignColors" version="1.1.2" targetFramework="net46" /> <package id="MaterialDesignThemes" version="2.3.1.953" targetFramework="net46" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> + <package id="SimpleValidator" version="0.6.1.0" targetFramework="net461" /> </packages>
\ No newline at end of file |
