From 63f0d770be42d9b0b8213e72c1f2acde1cf1874d Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Wed, 20 Sep 2017 16:13:28 +0200 Subject: [PATCH] add certification number and digest values output and check to verify results view, splitting up into multiple files --- HashingTool/HashingTool.csproj | 9 +- HashingTool/Helper/HashingHelper.cs | 1 + HashingTool/ViewModel/ComponentEntry.cs | 4 + .../ViewModel/HashComponentDataViewModel.cs | 2 +- HashingTool/ViewModel/HashedXMLFile.cs | 381 ---------------- .../ViewModel/UserControl/HashedXMLFile.cs | 26 ++ .../UserControl/ManufacturerReportXMLFile.cs | 232 ++++++++++ .../ViewModel/UserControl/ReportXMLFile.cs | 140 ++++++ .../ViewModel/UserControl/VectoJobFile.cs | 170 ++++++++ .../ViewModel/UserControl/VectoXMLFile.cs | 155 +++++++ .../{XMLFile.cs => XMLFileSelector.cs} | 7 +- .../VerifyComponentInputDataViewModel.cs | 3 +- .../ViewModel/VerifyJobInputDataViewModel.cs | 2 +- .../ViewModel/VerifyResultDataViewModel.cs | 41 +- .../UserControl/VectoXMLFileSelector.xaml.cs | 10 +- HashingTool/Views/VerifyJobInputData.xaml | 353 ++++++++------- HashingTool/Views/VerifyResults.xaml | 409 +++++++++++++++++- HashingTool/Views/VerifyResults.xaml.cs | 1 + .../VectoHashing/Properties/AssemblyInfo.cs | 74 ++-- VectoCommon/VectoHashing/VectoHash.cs | 32 +- 20 files changed, 1416 insertions(+), 636 deletions(-) delete mode 100644 HashingTool/ViewModel/HashedXMLFile.cs create mode 100644 HashingTool/ViewModel/UserControl/HashedXMLFile.cs create mode 100644 HashingTool/ViewModel/UserControl/ManufacturerReportXMLFile.cs create mode 100644 HashingTool/ViewModel/UserControl/ReportXMLFile.cs create mode 100644 HashingTool/ViewModel/UserControl/VectoJobFile.cs create mode 100644 HashingTool/ViewModel/UserControl/VectoXMLFile.cs rename HashingTool/ViewModel/UserControl/{XMLFile.cs => XMLFileSelector.cs} (97%) diff --git a/HashingTool/HashingTool.csproj b/HashingTool/HashingTool.csproj index 89e5566db3..043b5f7e02 100644 --- a/HashingTool/HashingTool.csproj +++ b/HashingTool/HashingTool.csproj @@ -67,6 +67,7 @@ <SubType>Designer</SubType> </ApplicationDefinition> <Compile Include="Helper\CollectionConverter.cs" /> + <Compile Include="Helper\CultureAwareBinding.cs" /> <Compile Include="Helper\HashingHelper.cs" /> <Compile Include="Helper\IOService.cs" /> <Compile Include="Properties\Annotations.cs" /> @@ -76,16 +77,20 @@ <DesignTime>True</DesignTime> </Compile> <Compile Include="ViewModel\ComponentEntry.cs" /> - <Compile Include="ViewModel\HashedXMLFile.cs" /> <Compile Include="ViewModel\HomeViewModel.cs" /> <Compile Include="ViewModel\IMainView.cs" /> <Compile Include="ViewModel\ApplicationViewModel.cs" /> <Compile Include="ViewModel\ObservableObject.cs" /> <Compile Include="ViewModel\RelayCommand.cs" /> <Compile Include="ViewModel\HashComponentDataViewModel.cs" /> + <Compile Include="ViewModel\UserControl\HashedXMLFile.cs" /> + <Compile Include="ViewModel\UserControl\ManufacturerReportXMLFile.cs" /> + <Compile Include="ViewModel\UserControl\ReportXMLFile.cs" /> + <Compile Include="ViewModel\UserControl\VectoJobFile.cs" /> + <Compile Include="ViewModel\UserControl\VectoXMLFile.cs" /> <Compile Include="ViewModel\VerifyJobInputDataViewModel.cs" /> <Compile Include="ViewModel\VerifyComponentInputDataViewModel.cs" /> - <Compile Include="ViewModel\UserControl\XMLFile.cs" /> + <Compile Include="ViewModel\UserControl\XMLFileSelector.cs" /> <Compile Include="Util\XMLValidator.cs" /> <Compile Include="ViewModel\VerifyResultDataViewModel.cs" /> <Compile Include="Views\AboutDialog.xaml.cs"> diff --git a/HashingTool/Helper/HashingHelper.cs b/HashingTool/Helper/HashingHelper.cs index c3bebafe4d..8ad87f1e91 100644 --- a/HashingTool/Helper/HashingHelper.cs +++ b/HashingTool/Helper/HashingHelper.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Xml; using HashingTool.ViewModel; +using HashingTool.ViewModel.UserControl; using TUGraz.VectoCommon.Resources; using TUGraz.VectoHashing; diff --git a/HashingTool/ViewModel/ComponentEntry.cs b/HashingTool/ViewModel/ComponentEntry.cs index 2a28208886..38a76fe9cd 100644 --- a/HashingTool/ViewModel/ComponentEntry.cs +++ b/HashingTool/ViewModel/ComponentEntry.cs @@ -1,3 +1,5 @@ +using System; + namespace HashingTool.ViewModel { public class ComponentEntry @@ -8,5 +10,7 @@ namespace HashingTool.ViewModel public string[] CanonicalizationMethod { get; set; } public string DigestMethod { get; set; } public bool Valid { get; set; } + public string CertificationNumber { get; set; } + public DateTime CertificationDate { get; set; } } } diff --git a/HashingTool/ViewModel/HashComponentDataViewModel.cs b/HashingTool/ViewModel/HashComponentDataViewModel.cs index 7d9df0b825..af4409bec9 100644 --- a/HashingTool/ViewModel/HashComponentDataViewModel.cs +++ b/HashingTool/ViewModel/HashComponentDataViewModel.cs @@ -62,7 +62,7 @@ namespace HashingTool.ViewModel private void SourceChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == "Document" || e.PropertyName == "IsValid") { + if (e.PropertyName == "UPDATED") { DoComputeHash(); } } diff --git a/HashingTool/ViewModel/HashedXMLFile.cs b/HashingTool/ViewModel/HashedXMLFile.cs deleted file mode 100644 index cd02b40d9d..0000000000 --- a/HashingTool/ViewModel/HashedXMLFile.cs +++ /dev/null @@ -1,381 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using System.Xml; -using HashingTool.Helper; -using HashingTool.ViewModel.UserControl; -using TUGraz.VectoHashing; - -namespace HashingTool.ViewModel -{ - public class VectoXMLFile : ObservableObject - { - protected readonly XMLFile _xmlFile; - - protected string _digestValueComputed; - protected bool? _valid; - protected string _name; - protected string _tooltip; - protected string _componentType; - protected readonly Action<XmlDocument, VectoXMLFile> _validateHashes; - private string _digestMethod; - - - public VectoXMLFile(string name, bool validate, Func<XmlDocument, Collection<string>, bool?> contentCheck, - Action<XmlDocument, VectoXMLFile> hashValidation = null) - { - _validateHashes = hashValidation; - _xmlFile = new XMLFile(IoService, validate, contentCheck); - _xmlFile.PropertyChanged += FileChanged; - Name = name; - CanonicalizationMethods = new ObservableCollection<string>(); - - Valid = null; - ValidTooltip = HashingHelper.ToolTipNone; - } - - protected virtual void FileChanged(object sender, PropertyChangedEventArgs e) - { - if (_xmlFile.IsValid == XmlFileStatus.ValidXML) { - if (_xmlFile.HasContentValidation) { - Valid = _xmlFile.ContentValid; - if (Valid != null && Valid.Value) { - ValidTooltip = HashingHelper.ToolTipOk; - } else { - ValidTooltip = HashingHelper.ToolTipInvalidFileType; - } - } else { - ValidTooltip = HashingHelper.ToolTipOk; - } - } else { - Valid = false; - ValidTooltip = HashingHelper.ToolTipXMLValidationFailed; - } - - if (Valid != null && Valid.Value && _validateHashes != null) { - _validateHashes(_xmlFile.Document, this); - } - } - - - public XMLFile XMLFile - { - get { return _xmlFile; } - } - - public string Name - { - get { return _name; } - private set { - if (_name == value) { - return; - } - _name = value; - RaisePropertyChanged("Name"); - } - } - - public ObservableCollection<string> CanonicalizationMethods { get; private set; } - - public void SetCanonicalizationMethod(IEnumerable<string> c14NMethods) - { - CanonicalizationMethods.Clear(); - foreach (var c14N in c14NMethods) { - CanonicalizationMethods.Add(c14N); - } - RaisePropertyChanged("CanonicalizationMethods"); - } - - public string DigestMethod - { - get { return _digestMethod; } - set { - if (_digestMethod == value) { - return; - } - _digestMethod = value; - RaisePropertyChanged("DigestMethod"); - } - } - - - public string DigestValueComputed - { - get { return _digestValueComputed; } - internal set { - if (_digestValueComputed == value) { - return; - } - _digestValueComputed = value; - RaisePropertyChanged("DigestValueComputed"); - } - } - - - public bool? Valid - { - get { return _valid; } - internal set { - if (_valid == value) { - return; - } - _valid = value; - RaisePropertyChanged("Valid"); - } - } - - public string ValidTooltip - { - get { return _tooltip; } - set { - if (_tooltip == value) { - return; - } - _tooltip = value; - RaisePropertyChanged("ValidTooltip"); - } - } - - public string Component - { - get { return _componentType; } - set { - if (_componentType == value) { - return; - } - _componentType = value; - RaisePropertyChanged("Component"); - } - } - } - - public class HashedXMLFile : VectoXMLFile - { - protected string _digestValueRead; - - public HashedXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, - Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, true, contentCheck, hashValidation) {} - - public string DigestValueRead - { - get { return _digestValueRead; } - internal set { - if (_digestValueRead == value) { - return; - } - _digestValueRead = value; - RaisePropertyChanged("DigestValueRead"); - } - } - } - - public class ReportXMLFile : HashedXMLFile - { - private string _jobDigestValueReadRead; - private string _jobDigestMethodRead; - private string[] _jobCanonicalizationMethodRead; - private string _jobDigestComputed; - private bool _jobDigestValid; - - public ReportXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, - Action<XmlDocument, VectoXMLFile> hashValidation = null) - : base(name, contentCheck, hashValidation) - { - _xmlFile.PropertyChanged += ReadJobDigest; - } - - private void ReadJobDigest(object sender, PropertyChangedEventArgs e) - { - var jobDigest = ""; - var jobDigestMethod = ""; - var jobc14NMethod = new string[] { }; - - if (e.PropertyName != "Document") { - return; - } - if (_xmlFile.Document != null && _xmlFile.Document.DocumentElement != null) { - var digestValueNode = - _xmlFile.Document.SelectSingleNode("//*[local-name()='InputDataSignature']//*[local-name()='DigestValue']"); - if (digestValueNode != null) { - jobDigest = digestValueNode.InnerText; - } - var digestMethodNode = - _xmlFile.Document.SelectSingleNode( - "//*[local-name()='InputDataSignature']//*[local-name()='DigestMethod']/@Algorithm"); - if (digestMethodNode != null) { - jobDigestMethod = digestMethodNode.InnerText; - } - - var c14NtMethodNodes = - _xmlFile.Document.SelectNodes("//*[local-name()='InputDataSignature']//*[local-name()='Transform']/@Algorithm"); - if (c14NtMethodNodes != null) { - jobc14NMethod = (from XmlNode node in c14NtMethodNodes select node.InnerText).ToArray(); - } - } - JobCanonicalizationMethodRead = jobc14NMethod; - JobDigestMethodRead = jobDigestMethod; - JobDigestValueRead = jobDigest; - } - - public string JobDigestMethodRead - { - get { return _jobDigestMethodRead; } - set { - if (_jobDigestMethodRead == value) { - return; - } - _jobDigestMethodRead = value; - RaisePropertyChanged("JobDigestMethodRead"); - } - } - - public string[] JobCanonicalizationMethodRead - { - get { return _jobCanonicalizationMethodRead; } - set { - if (_jobCanonicalizationMethodRead == value) { - return; - } - _jobCanonicalizationMethodRead = value; - RaisePropertyChanged("JobCanonicalizationMethodRead"); - } - } - - public string JobDigestValueRead - { - get { return _jobDigestValueReadRead; } - internal set { - if (_jobDigestValueReadRead == value) { - return; - } - _jobDigestValueReadRead = value; - RaisePropertyChanged("JobDigestValueRead"); - } - } - - public string JobDigestValueComputed - { - get { return _jobDigestComputed; } - set { - if (_jobDigestComputed == value) { - return; - } - _jobDigestComputed = value; - RaisePropertyChanged("JobDigestValueComputed"); - JobDigestValid = JobDigestValueComputed == JobDigestValueRead; - } - } - - public bool JobDigestValid - { - get { return _jobDigestValid; } - set { - if (_jobDigestValid == value) { - return; - } - _jobDigestValid = value; - RaisePropertyChanged("JobDigestValid"); - } - } - } - - public class VectoJobFile : VectoXMLFile - { - private bool _componentDataValid; - private string _jobValidToolTip; - - - public VectoJobFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, - Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, true, contentCheck, hashValidation) - { - _xmlFile.PropertyChanged += JobFilechanged; - Components = new ObservableCollection<ComponentEntry>(); - } - - public ObservableCollection<ComponentEntry> Components { get; private set; } - - public bool JobDataValid - { - get { return _componentDataValid; } - set { - if (_componentDataValid == value) { - return; - } - _componentDataValid = value; - JobValidToolTip = value ? HashingHelper.ToolTipComponentHashInvalid : HashingHelper.ToolTipOk; - RaisePropertyChanged("JobDataValid"); - } - } - - public string JobValidToolTip - { - get { return _jobValidToolTip; } - set { - if (_jobValidToolTip == value) { - return; - } - _jobValidToolTip = value; - RaisePropertyChanged("JobValidToolTip"); - } - } - - private void JobFilechanged(object sender, PropertyChangedEventArgs e) - { - DoValidateHash(); - } - - private void DoValidateHash() - { - if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null || - !_xmlFile.ContentValid.Value) { - Components.Clear(); - DigestValueComputed = ""; - DigestMethod = ""; - SetCanonicalizationMethod(new string[] { }); - JobDataValid = false; - return; - } - try { - Components.Clear(); - _xmlFile.XMLValidationErrors.Clear(); - var h = VectoHash.Load(_xmlFile.Document); - var allValid = true; - var components = h.GetContainigComponents().GroupBy(s => s) - .Select(g => new { Entry = g.Key, Count = g.Count() }); - foreach (var component in components) { - if (component.Entry == VectoComponents.Vehicle) { - continue; - } - for (var i = 0; i < component.Count; i++) { - var entry = new ComponentEntry(); - entry.Component = component.Count == 1 - ? component.Entry.XMLElementName() - : string.Format("{0} ({1})", component.Entry.XMLElementName(), i + 1); - entry.Valid = h.ValidateHash(component.Entry, i); - entry.CanonicalizationMethod = h.GetCanonicalizationMethods(component.Entry, i).ToArray(); - entry.DigestMethod = h.GetDigestMethod(component.Entry, i); - entry.DigestValueRead = h.ReadHash(component.Entry, i); - entry.DigestValueComputed = h.ComputeHash(component.Entry, i); - if (!entry.Valid) { - _xmlFile.XMLValidationErrors.Add( - string.Format( - "Digest Value mismatch for component \"{0}\". Read digest value: \"{1}\", computed digest value \"{2}\"", - entry.Component, entry.DigestValueRead, entry.DigestValueComputed)); - } - Components.Add(entry); - allValid &= entry.Valid; - } - } - - DigestValueComputed = h.ComputeHash(); - JobDataValid = allValid; - } catch (Exception e) { - DigestValueComputed = ""; - JobDataValid = false; - _xmlFile.XMLValidationErrors.Add(e.Message); - } - } - } -} diff --git a/HashingTool/ViewModel/UserControl/HashedXMLFile.cs b/HashingTool/ViewModel/UserControl/HashedXMLFile.cs new file mode 100644 index 0000000000..25a7fd9ae8 --- /dev/null +++ b/HashingTool/ViewModel/UserControl/HashedXMLFile.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.ObjectModel; +using System.Xml; + +namespace HashingTool.ViewModel.UserControl +{ + public class HashedXMLFile : VectoXMLFile + { + protected string _digestValueRead; + + public HashedXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, + Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, true, contentCheck, hashValidation) {} + + public string DigestValueRead + { + get { return _digestValueRead; } + internal set { + if (_digestValueRead == value) { + return; + } + _digestValueRead = value; + RaisePropertyChanged("DigestValueRead"); + } + } + } +} diff --git a/HashingTool/ViewModel/UserControl/ManufacturerReportXMLFile.cs b/HashingTool/ViewModel/UserControl/ManufacturerReportXMLFile.cs new file mode 100644 index 0000000000..da8afd23c4 --- /dev/null +++ b/HashingTool/ViewModel/UserControl/ManufacturerReportXMLFile.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Xml; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Resources; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoHashing; + +namespace HashingTool.ViewModel.UserControl +{ + public class ManufacturerReportXMLFile : ReportXMLFile + { + private ViewModel.ComponentEntry[] _jobComponents; + + public ManufacturerReportXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, + Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, contentCheck, hashValidation) + { + _xmlFile.PropertyChanged += UpdateComponents; + } + + public ViewModel.ComponentEntry[] JobComponents + { + set { + if (_jobComponents == value) { + return; + } + _jobComponents = value; + DoUpdateComponents(); + RaisePropertyChanged("JobComponents"); + RaisePropertyChanged("ManufacturerReportValid"); + } + private get { return _jobComponents; } + } + + private void UpdateComponents(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "UPDATED") { + return; + } + DoUpdateComponents(); + RaisePropertyChanged("ManufacturerReportValid"); + RaisePropertyChanged("UPDATED"); + } + + private void DoUpdateComponents() + { + if (_xmlFile.Document == null || _xmlFile.Document.DocumentElement == null) { + Components = new ComponentEntry[] { }; + VehicleIdentificationNumber = ""; + RaisePropertyChanged("Components"); + RaisePropertyChanged("VehicleIdentificationNumber"); + return; + } + var components = GetContainigComponents().GroupBy(s => s) + .Select(g => new { Entry = g.Key, Count = g.Count() }); + var componentData = new List<ComponentEntry>(); + foreach (var component in components) { + if (component.Entry == XMLNames.Component_Vehicle) { + continue; + } + for (var i = 0; i < component.Count; i++) { + var node = GetNodes(component.Entry, i); + var entry = new ComponentEntry { + Component = component.Count == 1 + ? component.Entry + : string.Format("{0} ({1})", component.Entry, i + 1), + DigestValue = ReadElementValue(node, XMLNames.DI_Signature_Reference_DigestValue), + CertificationMethod = ReadElementValue(node, XMLNames.Report_Component_CertificationMethod), + }; + if (entry.Component.StartsWith("Axle ")) { + entry.Component = entry.Component.Replace("Axle", "Tyre"); + entry.CertificationNumber = ReadElementValue(node, XMLNames.Report_Tyre_TyreCertificationNumber); + entry.DigestValue = "Not Available"; + } else { + entry.CertificationNumber = ReadElementValue(node, XMLNames.Report_Component_CertificationNumber) ?? + ReadElementValue(node, XMLNames.Report_Component_CertificationMethod); + } + if (JobComponents != null) { + var jobComponent = JobComponents.Where( + x => x.Component == entry.Component).ToArray(); + if (jobComponent.Any()) { + entry.DigestValueMatchesJobComponent = entry.Component.StartsWith("Tyre ") + ? (bool?)null + : (jobComponent.First().DigestValueRead == entry.DigestValue); + entry.DigestValueExpected = jobComponent.First().DigestValueRead; + if (entry.CertificationMethod != CertificationMethod.StandardValues.ToXMLFormat()) { + entry.CertificationNumberMatchesJobComponent = jobComponent.First().CertificationNumber == + entry.CertificationNumber; + entry.CertificationNumberExpected = jobComponent.First().CertificationNumber; + } + } + } + componentData.Add(entry); + } + } + Components = componentData.ToArray(); + VehicleIdentificationNumber = GetVehicleIdentificationNumber(); + + RaisePropertyChanged("Components"); + RaisePropertyChanged("VehicleIdentificationNumber"); + } + + private string GetVehicleIdentificationNumber() + { + if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null || + !_xmlFile.ContentValid.Value) { + return ""; + } + var node = _xmlFile.Document.SelectSingleNode(string.Format("//*[local-name()='{0}']", XMLNames.Vehicle_VIN)); + if (node == null) { + return ""; + } + return node.InnerText; + } + + public bool ManufacturerReportValid + { + get { + var componentsValid = JobComponents != null && JobComponents.Length > 0; + if (Components == null || JobComponents == null || JobComponents.Length == 0) { + return false; + } + + foreach (var entry in Components) { + // certification number is optional (iff standard values are used) + var entryCertificationNbr = entry.CertificationNumberMatchesJobComponent == null || + entry.CertificationNumberMatchesJobComponent.Value; + if (!entryCertificationNbr) { + var msg = string.Format("Certification number for component {0} does not match! Job-File: {1}, Report: {2}", + entry.Component, entry.CertificationNumberExpected, entry.CertificationNumber); + if (!_xmlFile.XMLValidationErrors.Contains(msg)) { + _xmlFile.XMLValidationErrors.Add(msg); + } + } + componentsValid &= entryCertificationNbr; + // digest value is mandatory (except for tires) + if (entry.Component.StartsWith("Tyre ")) { + continue; + } + + var entryDigest = entry.DigestValueMatchesJobComponent != null && entry.DigestValueMatchesJobComponent.Value; + if (!entryDigest) { + var msg = string.Format("Digest value for component {0} does not match! Job-File: {1}, Report: {2}", + entry.Component, entry.DigestValueExpected, entry.DigestValue); + if (!_xmlFile.XMLValidationErrors.Contains(msg)) { + _xmlFile.XMLValidationErrors.Add(msg); + } + } + componentsValid &= entryDigest; + } + return JobDigestValid && componentsValid; + } + } + + private string ReadElementValue(XmlNode xmlNode, string elementName) + { + var node = xmlNode.SelectSingleNode(string.Format("./*[local-name()='{0}']", elementName)); + if (node == null) { + return null; + } + return node.InnerText; + } + + protected XmlNode GetNodes(string component, int index) + { + var nodes = _xmlFile.Document.SelectNodes(GetComponentQueryString(component)); + if (nodes == null || nodes.Count == 0) { + throw new Exception(component == null + ? "No component found" + : string.Format("Component {0} not found", component)); + } + if (index >= nodes.Count) { + throw new Exception(string.Format("index exceeds number of components found! index: {0}, #components: {1}", index, + nodes.Count)); + } + return nodes[index]; + } + + protected static string GetComponentQueryString(string component = null) + { + if (component == null) { + return "(//*[@id])[1]"; + } + return string.Format("//*[local-name()='{0}']", component); + } + + protected IList<string> GetContainigComponents() + { + var retVal = new List<string>(); + foreach (var component in EnumHelper.GetValues<VectoComponents>()) { + var nodes = _xmlFile.Document.SelectNodes(string.Format("//*[local-name()='{0}']//*[local-name()='{1}']", + XMLNames.VectoManufacturerReport, component.XMLElementName())); + var count = nodes == null ? 0 : nodes.Count; + for (var i = 0; i < count; i++) { + retVal.Add(component.XMLElementName()); + } + } + foreach (var component in new[] { XMLNames.AxleWheels_Axles_Axle }) { + var nodes = _xmlFile.Document.SelectNodes(string.Format("//*[local-name()='{0}']//*[local-name()='{1}']", + XMLNames.VectoManufacturerReport, component)); + var count = nodes == null ? 0 : nodes.Count; + for (var i = 0; i < count; i++) { + retVal.Add(component); + } + } + return retVal; + } + + public string VehicleIdentificationNumber { get; private set; } + + public ComponentEntry[] Components { get; private set; } + + public class ComponentEntry + { + public string Component { get; set; } + + public string CertificationNumber { get; set; } + + public string DigestValue { get; set; } + + public string CertificationMethod { get; set; } + + public bool? DigestValueMatchesJobComponent { get; set; } + public bool? CertificationNumberMatchesJobComponent { get; set; } + public string DigestValueExpected { get; set; } + public string CertificationNumberExpected { get; set; } + } + } +} \ No newline at end of file diff --git a/HashingTool/ViewModel/UserControl/ReportXMLFile.cs b/HashingTool/ViewModel/UserControl/ReportXMLFile.cs new file mode 100644 index 0000000000..3c830404cc --- /dev/null +++ b/HashingTool/ViewModel/UserControl/ReportXMLFile.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Xml; + +namespace HashingTool.ViewModel.UserControl +{ + public class ReportXMLFile : HashedXMLFile + { + private string _jobDigestValueReadRead; + private string _jobDigestMethodRead; + private string[] _jobCanonicalizationMethodRead; + private string _jobDigestComputed; + private bool _jobDigestValid; + private DateTime? _creationDate; + + public ReportXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, + Action<XmlDocument, VectoXMLFile> hashValidation = null) + : base(name, contentCheck, hashValidation) + { + _xmlFile.PropertyChanged += ReadJobDigest; + } + + private void ReadJobDigest(object sender, PropertyChangedEventArgs e) + { + var jobDigest = ""; + var jobDigestMethod = ""; + var jobc14NMethod = new string[] { }; + DateTime? creationDate = null; + + if (e.PropertyName != "UPDATED") { + return; + } + if (_xmlFile.Document != null && _xmlFile.Document.DocumentElement != null) { + var digestValueNode = + _xmlFile.Document.SelectSingleNode("//*[local-name()='InputDataSignature']//*[local-name()='DigestValue']"); + if (digestValueNode != null) { + jobDigest = digestValueNode.InnerText; + } + var digestMethodNode = + _xmlFile.Document.SelectSingleNode( + "//*[local-name()='InputDataSignature']//*[local-name()='DigestMethod']/@Algorithm"); + if (digestMethodNode != null) { + jobDigestMethod = digestMethodNode.InnerText; + } + + var c14NtMethodNodes = + _xmlFile.Document.SelectNodes("//*[local-name()='InputDataSignature']//*[local-name()='Transform']/@Algorithm"); + if (c14NtMethodNodes != null) { + jobc14NMethod = (from XmlNode node in c14NtMethodNodes select node.InnerText).ToArray(); + } + var dateNode = + _xmlFile.Document.SelectSingleNode("//*[local-name()='ApplicationInformation']/*[local-name()='Date']"); + creationDate = dateNode != null + ? XmlConvert.ToDateTime(dateNode.InnerText, XmlDateTimeSerializationMode.RoundtripKind) + : (DateTime?)null; + } + JobCanonicalizationMethodRead = jobc14NMethod; + JobDigestMethodRead = jobDigestMethod; + JobDigestValueRead = jobDigest; + CreationDate = creationDate; + RaisePropertyChanged("UPDATED"); + } + + public string JobDigestMethodRead + { + get { return _jobDigestMethodRead; } + set { + if (_jobDigestMethodRead == value) { + return; + } + _jobDigestMethodRead = value; + RaisePropertyChanged("JobDigestMethodRead"); + } + } + + public string[] JobCanonicalizationMethodRead + { + get { return _jobCanonicalizationMethodRead; } + set { + if (_jobCanonicalizationMethodRead == value) { + return; + } + _jobCanonicalizationMethodRead = value; + RaisePropertyChanged("JobCanonicalizationMethodRead"); + } + } + + public string JobDigestValueRead + { + get { return _jobDigestValueReadRead; } + internal set { + if (_jobDigestValueReadRead == value) { + return; + } + _jobDigestValueReadRead = value; + RaisePropertyChanged("JobDigestValueRead"); + } + } + + public string JobDigestValueComputed + { + get { return _jobDigestComputed; } + set { + if (_jobDigestComputed == value) { + JobDigestValid = _jobDigestComputed == JobDigestValueRead; + return; + } + _jobDigestComputed = value; + RaisePropertyChanged("JobDigestValueComputed"); + JobDigestValid = _jobDigestComputed == JobDigestValueRead; + } + } + + public bool JobDigestValid + { + get { return _jobDigestValid; } + set { + if (_jobDigestValid == value) { + return; + } + _jobDigestValid = value; + RaisePropertyChanged("JobDigestValid"); + } + } + + public DateTime? CreationDate + { + get { return _creationDate; } + set { + if (_creationDate == value) { + return; + } + _creationDate = value; + RaisePropertyChanged("CreationDate"); + } + } + } +} \ No newline at end of file diff --git a/HashingTool/ViewModel/UserControl/VectoJobFile.cs b/HashingTool/ViewModel/UserControl/VectoJobFile.cs new file mode 100644 index 0000000000..a964950128 --- /dev/null +++ b/HashingTool/ViewModel/UserControl/VectoJobFile.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Xml; +using HashingTool.Helper; +using TUGraz.VectoCommon.Resources; +using TUGraz.VectoHashing; + +namespace HashingTool.ViewModel.UserControl +{ + public class VectoJobFile : VectoXMLFile + { + private bool _componentDataValid; + private string _jobValidToolTip; + private string _vin; + private DateTime? _jobDate; + + + public VectoJobFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck, + Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, true, contentCheck, hashValidation) + { + _xmlFile.PropertyChanged += JobFilechanged; + Components = new ObservableCollection<ComponentEntry>(); + } + + public ObservableCollection<ComponentEntry> Components { get; private set; } + + public bool JobDataValid + { + get { return _componentDataValid; } + set { + if (_componentDataValid == value) { + return; + } + _componentDataValid = value; + JobValidToolTip = value ? HashingHelper.ToolTipComponentHashInvalid : HashingHelper.ToolTipOk; + RaisePropertyChanged("JobDataValid"); + } + } + + public string JobValidToolTip + { + get { return _jobValidToolTip; } + set { + if (_jobValidToolTip == value) { + return; + } + _jobValidToolTip = value; + RaisePropertyChanged("JobValidToolTip"); + } + } + + public string VehicleIdentificationNumber + { + get { return _vin; } + set { + if (_vin == value) { + return; + } + _vin = value; + RaisePropertyChanged("VehicleIdentificationNumber"); + } + } + + public DateTime? JobCreationDate + { + get { return _jobDate; } + set { + if (_jobDate == value) { + return; + } + _jobDate = value; + RaisePropertyChanged("JobCreationDate"); + } + } + + private void JobFilechanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "UPDATED") { + return; + } + DoValidateHash(); + VehicleIdentificationNumber = DoReadVIN(); + JobCreationDate = DoReadJobDate(); + + RaisePropertyChanged("UPDATED"); + } + + private DateTime? DoReadJobDate() + { + if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null || + !_xmlFile.ContentValid.Value) { + return null; + } + var nodes = _xmlFile.Document.SelectNodes(string.Format("//*[local-name()='{0}']", XMLNames.Component_Date)); + if (nodes == null || nodes.Count == 0) { + return null; + } + return XmlConvert.ToDateTime(nodes[0].InnerText, XmlDateTimeSerializationMode.RoundtripKind); + } + + private string DoReadVIN() + { + if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null || + !_xmlFile.ContentValid.Value) { + return ""; + } + var node = _xmlFile.Document.SelectSingleNode(string.Format("//*[local-name()='{0}']", XMLNames.Vehicle_VIN)); + if (node == null) { + return ""; + } + return node.InnerText; + } + + private void DoValidateHash() + { + if (_xmlFile.Document == null || _xmlFile.IsValid != XmlFileStatus.ValidXML || _xmlFile.ContentValid == null || + !_xmlFile.ContentValid.Value) { + Components.Clear(); + DigestValueComputed = ""; + DigestMethod = ""; + SetCanonicalizationMethod(new string[] { }); + JobDataValid = false; + return; + } + try { + Components.Clear(); + _xmlFile.XMLValidationErrors.Clear(); + var h = VectoHash.Load(_xmlFile.Document); + var allValid = true; + var components = h.GetContainigComponents().GroupBy(s => s) + .Select(g => new { Entry = g.Key, Count = g.Count() }); + foreach (var component in components) { + if (component.Entry == VectoComponents.Vehicle) { + continue; + } + for (var i = 0; i < component.Count; i++) { + var entry = new ComponentEntry(); + entry.Component = component.Count == 1 + ? component.Entry.XMLElementName() + : string.Format("{0} ({1})", component.Entry.XMLElementName(), i + 1); + entry.Valid = h.ValidateHash(component.Entry, i); + entry.CanonicalizationMethod = h.GetCanonicalizationMethods(component.Entry, i).ToArray(); + entry.DigestMethod = h.GetDigestMethod(component.Entry, i); + entry.DigestValueRead = h.ReadHash(component.Entry, i); + entry.DigestValueComputed = h.ComputeHash(component.Entry, i); + entry.CertificationNumber = h.GetCertificationNumber(component.Entry, i); + entry.CertificationDate = h.GetCertificationDate(component.Entry, i); + if (!entry.Valid) { + _xmlFile.XMLValidationErrors.Add( + string.Format( + "Digest Value mismatch for component \"{0}\". Read digest value: \"{1}\", computed digest value \"{2}\"", + entry.Component, entry.DigestValueRead, entry.DigestValueComputed)); + } + Components.Add(entry); + allValid &= entry.Valid; + } + } + + DigestValueComputed = h.ComputeHash(); + JobDataValid = allValid; + } catch (Exception e) { + DigestValueComputed = ""; + JobDataValid = false; + _xmlFile.XMLValidationErrors.Add(e.Message); + } + } + } +} \ No newline at end of file diff --git a/HashingTool/ViewModel/UserControl/VectoXMLFile.cs b/HashingTool/ViewModel/UserControl/VectoXMLFile.cs new file mode 100644 index 0000000000..e96209319d --- /dev/null +++ b/HashingTool/ViewModel/UserControl/VectoXMLFile.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Xml; +using HashingTool.Helper; + +namespace HashingTool.ViewModel.UserControl +{ + public class VectoXMLFile : ObservableObject + { + protected readonly XMLFileSelector _xmlFile; + + protected string _digestValueComputed; + protected bool? _valid; + protected string _name; + protected string _tooltip; + protected string _componentType; + protected readonly Action<XmlDocument, VectoXMLFile> _validateHashes; + private string _digestMethod; + + + public VectoXMLFile(string name, bool validate, Func<XmlDocument, Collection<string>, bool?> contentCheck, + Action<XmlDocument, VectoXMLFile> hashValidation = null) + { + _validateHashes = hashValidation; + _xmlFile = new XMLFileSelector(IoService, validate, contentCheck); + _xmlFile.PropertyChanged += FileChanged; + Name = name; + CanonicalizationMethods = new ObservableCollection<string>(); + + Valid = null; + ValidTooltip = HashingHelper.ToolTipNone; + } + + protected virtual void FileChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "UPDATED") { + return; + } + + if (_xmlFile.IsValid == XmlFileStatus.ValidXML) { + if (_xmlFile.HasContentValidation) { + Valid = _xmlFile.ContentValid; + if (Valid != null && Valid.Value) { + ValidTooltip = HashingHelper.ToolTipOk; + } else { + ValidTooltip = HashingHelper.ToolTipInvalidFileType; + } + } else { + ValidTooltip = HashingHelper.ToolTipOk; + } + } else { + Valid = false; + ValidTooltip = HashingHelper.ToolTipXMLValidationFailed; + } + + if (Valid != null && Valid.Value && _validateHashes != null) { + _validateHashes(_xmlFile.Document, this); + } + RaisePropertyChanged("UPDATED"); + } + + + public XMLFileSelector XMLFile + { + get { return _xmlFile; } + } + + public string Name + { + get { return _name; } + private set { + if (_name == value) { + return; + } + _name = value; + RaisePropertyChanged("Name"); + } + } + + public ObservableCollection<string> CanonicalizationMethods { get; private set; } + + public void SetCanonicalizationMethod(IEnumerable<string> c14NMethods) + { + CanonicalizationMethods.Clear(); + foreach (var c14N in c14NMethods) { + CanonicalizationMethods.Add(c14N); + } + RaisePropertyChanged("CanonicalizationMethods"); + } + + public string DigestMethod + { + get { return _digestMethod; } + set { + if (_digestMethod == value) { + return; + } + _digestMethod = value; + RaisePropertyChanged("DigestMethod"); + } + } + + + public string DigestValueComputed + { + get { return _digestValueComputed; } + internal set { + if (_digestValueComputed == value) { + return; + } + _digestValueComputed = value; + RaisePropertyChanged("DigestValueComputed"); + } + } + + + public bool? Valid + { + get { return _valid; } + internal set { + if (_valid == value) { + return; + } + _valid = value; + RaisePropertyChanged("Valid"); + } + } + + public string ValidTooltip + { + get { return _tooltip; } + set { + if (_tooltip == value) { + return; + } + _tooltip = value; + RaisePropertyChanged("ValidTooltip"); + } + } + + public string Component + { + get { return _componentType; } + set { + if (_componentType == value) { + return; + } + _componentType = value; + RaisePropertyChanged("Component"); + } + } + } +} \ No newline at end of file diff --git a/HashingTool/ViewModel/UserControl/XMLFile.cs b/HashingTool/ViewModel/UserControl/XMLFileSelector.cs similarity index 97% rename from HashingTool/ViewModel/UserControl/XMLFile.cs rename to HashingTool/ViewModel/UserControl/XMLFileSelector.cs index 57096aba1e..3dec80d376 100644 --- a/HashingTool/ViewModel/UserControl/XMLFile.cs +++ b/HashingTool/ViewModel/UserControl/XMLFileSelector.cs @@ -21,7 +21,7 @@ namespace HashingTool.ViewModel.UserControl ValidXML // green } - public class XMLFile : ObservableObject + public class XMLFileSelector : ObservableObject { private string _source; private XmlFileStatus _isValid; @@ -34,7 +34,7 @@ namespace HashingTool.ViewModel.UserControl private bool? _contentValid; private RelayCommand _browseFileCommand; - public XMLFile(IOService ioservice, bool validate = false, + public XMLFileSelector(IOService ioservice, bool validate = false, Func<XmlDocument, Collection<string>, bool?> contentCheck = null) { IoService = ioservice; @@ -199,11 +199,12 @@ namespace HashingTool.ViewModel.UserControl XMLValidationErrors.Add(e.Message); fileValid = XmlFileStatus.Invalid; } finally { - IsValid = fileValid; ContentValid = contentValid; _busy = false; _browseFileCommand.RaiseCanExecuteChanged(); + + RaisePropertyChanged("UPDATED"); } } diff --git a/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs b/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs index a2479bbc86..60a099abf1 100644 --- a/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs +++ b/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Windows; using System.Windows.Input; using HashingTool.Helper; +using HashingTool.ViewModel.UserControl; using TUGraz.VectoHashing; namespace HashingTool.ViewModel @@ -40,7 +41,7 @@ namespace HashingTool.ViewModel private void ComponentFilechanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == "Document" || e.PropertyName == "ContentValid") { + if (e.PropertyName == "UPDATED") { DoValidateHash(); } } diff --git a/HashingTool/ViewModel/VerifyJobInputDataViewModel.cs b/HashingTool/ViewModel/VerifyJobInputDataViewModel.cs index a3b3cb8af7..03a69aadff 100644 --- a/HashingTool/ViewModel/VerifyJobInputDataViewModel.cs +++ b/HashingTool/ViewModel/VerifyJobInputDataViewModel.cs @@ -14,7 +14,7 @@ namespace HashingTool.ViewModel get { return ApplicationViewModel.HomeView; } } - public XMLFile JobFile + public XMLFileSelector JobFile { get { return _xmlFile; } } diff --git a/HashingTool/ViewModel/VerifyResultDataViewModel.cs b/HashingTool/ViewModel/VerifyResultDataViewModel.cs index f0a1b843be..47c181900f 100644 --- a/HashingTool/ViewModel/VerifyResultDataViewModel.cs +++ b/HashingTool/ViewModel/VerifyResultDataViewModel.cs @@ -1,9 +1,10 @@ using System; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Linq; using System.Windows.Input; -using System.Xml; using HashingTool.Helper; +using HashingTool.ViewModel.UserControl; using TUGraz.VectoHashing; namespace HashingTool.ViewModel @@ -12,13 +13,13 @@ namespace HashingTool.ViewModel { private readonly VectoJobFile _jobFile; private readonly ReportXMLFile _customerReport; - private readonly ReportXMLFile _manufacturerReport; + private readonly ManufacturerReportXMLFile _manufacturerReport; public VerifyResultDataViewModel() { _jobFile = new VectoJobFile("Job File", HashingHelper.IsJobFile, HashingHelper.HashJobFile); - _manufacturerReport = new ReportXMLFile("Manufacturer Report", HashingHelper.IsManufacturerReport, + _manufacturerReport = new ManufacturerReportXMLFile("Manufacturer Report", HashingHelper.IsManufacturerReport, HashingHelper.ValidateDocumentHash); _customerReport = new ReportXMLFile("Customer Report", HashingHelper.IsCustomerReport, HashingHelper.ValidateDocumentHash); @@ -32,10 +33,12 @@ namespace HashingTool.ViewModel private void Update(object sender, PropertyChangedEventArgs e) { - //RaisePropertyChanged("ManufacturerReportValid"); - //RaisePropertyChanged("CustomerReportReportValid"); + if (e.PropertyName != "UPDATED") + return; UpdateReportJobDigest(_manufacturerReport); UpdateReportJobDigest(_customerReport); + + _manufacturerReport.JobComponents = _jobFile.Components.ToArray(); } @@ -60,16 +63,14 @@ namespace HashingTool.ViewModel get { return _customerReport; } } - public ReportXMLFile ManufacturerReport + public ManufacturerReportXMLFile ManufacturerReport { get { return _manufacturerReport; } } public ObservableCollection<VectoXMLFile> Files { get; private set; } - //public bool ManufacturerReportValid - //{ - // get { + private void UpdateReportJobDigest(ReportXMLFile reportXML) { if (reportXML.Valid == null || !reportXML.Valid.Value || _jobFile.XMLFile.Document == null) { @@ -81,29 +82,9 @@ namespace HashingTool.ViewModel var jobDigest = h.ComputeHash(reportXML.JobCanonicalizationMethodRead, reportXML.JobDigestMethodRead); reportXML.JobDigestValueComputed = jobDigest; - } catch (Exception e) { + } catch (Exception ) { reportXML.JobDigestValueComputed = ""; } } - - // } - //} - - //public bool CustomerReportReportValid - //{ - // get { - // if (_customerReport.Valid == null || !_customerReport.Valid.Value) { - // return false; - // } - // try { - // var h = VectoHash.Load(_jobFile.XMLFile.Document); - // var jobDigest = h.ComputeHash(_customerReport.JobCanonicalizationMethodRead, _customerReport.JobDigestMethodRead); - // _customerReport.JobDigestValueComputed = jobDigest; - // return _customerReport.JobDigestValueRead == jobDigest; - // } catch (Exception e) { - // return false; - // } - // } - //} } } diff --git a/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs index 6833ffc72f..3fa92323b3 100644 --- a/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs +++ b/HashingTool/Views/UserControl/VectoXMLFileSelector.xaml.cs @@ -7,9 +7,10 @@ namespace HashingTool.Views /// <summary> /// Interaction logic for VectoXMLFileSelector.xaml /// </summary> - public partial class VectoXMLFileSelector + public partial class VectoXMLFileSelector { - public static readonly DependencyProperty XMLFileProperty = DependencyProperty.Register("XMLFile", typeof(XMLFile), + public static readonly DependencyProperty XMLFileProperty = DependencyProperty.Register("XMLFile", + typeof(XMLFileSelector), typeof(VectoXMLFileSelector)); @@ -19,9 +20,9 @@ namespace HashingTool.Views (Content as FrameworkElement).DataContext = this; } - public XMLFile XMLFile + public XMLFileSelector XMLFile { - get { return (XMLFile)GetValue(XMLFileProperty); } + get { return (XMLFileSelector)GetValue(XMLFileProperty); } set { SetValue(XMLFileProperty, value); } } @@ -32,6 +33,5 @@ namespace HashingTool.Views dialog.ShowDialog(); } - } } diff --git a/HashingTool/Views/VerifyJobInputData.xaml b/HashingTool/Views/VerifyJobInputData.xaml index ff20b83691..66ce598d87 100644 --- a/HashingTool/Views/VerifyJobInputData.xaml +++ b/HashingTool/Views/VerifyJobInputData.xaml @@ -6,6 +6,7 @@ xmlns:viewModel="clr-namespace:HashingTool.ViewModel" xmlns:views="clr-namespace:HashingTool.Views" xmlns:helper="clr-namespace:HashingTool.Helper" + xmlns:globalization="clr-namespace:System.Globalization;assembly=mscorlib" x:Class="HashingTool.Views.VerifyJobInputData" mc:Ignorable="d" d:DesignHeight="657" d:DesignWidth="534"> @@ -15,7 +16,7 @@ <UserControl.DataContext> <viewModel:VerifyJobInputDataViewModel /> </UserControl.DataContext> - + <DockPanel> <Label DockPanel.Dock="Top" Name="lblHeader" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Top" @@ -26,164 +27,204 @@ Width="75" Height="22" VerticalAlignment="Bottom" /> <ScrollViewer> <DockPanel> - <Label x:Name="lblFileSelect" DockPanel.Dock="Top" Content="Job data:" HorizontalAlignment="Left" Margin="10,0,0,0" - VerticalAlignment="Top" /> - <views:VectoXMLFileSelector Margin="10,0,10,0" DockPanel.Dock="Top" VerticalAlignment="Top" XMLFile="{Binding JobFile}" - Height="80" /> - <Grid DockPanel.Dock="Top" Margin="0,0,0,0"> - <Grid.RowDefinitions> - <RowDefinition Height="*"/> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - - <Label Grid.Row="1" Grid.Column="0" Content="Canonicalization methods:" /> - <TextBox Grid.Row="1" Grid.Column="1" - Text="{Binding CanonicalizationMethods , Converter={StaticResource CollectionConverter}, Mode=OneWay}" - Margin="10,2" IsReadOnly="True" /> + <Label x:Name="lblFileSelect" DockPanel.Dock="Top" Content="Job data:" HorizontalAlignment="Left" Margin="10,0,0,0" + VerticalAlignment="Top" /> + <views:VectoXMLFileSelector Margin="10,0,10,0" DockPanel.Dock="Top" VerticalAlignment="Top" + XMLFile="{Binding JobFile}" + Height="80" /> + <Grid DockPanel.Dock="Top" Margin="10,10,0,10"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" MinWidth="100" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + <Label Grid.Row="0" Grid.Column="0" Content="Vehicle" FontWeight="Bold" Margin="0,0,10,0" /> + <Label Grid.Row="0" Grid.Column="1" Content="VIN:" /> + <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding VehicleIdentificationNumber, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="0" Grid.Column="3" Content="Date:" /> + <TextBox Grid.Row="0" Grid.Column="4" + Text="{helper:CultureAwareBinding Path=JobCreationDate, Mode=OneWay, StringFormat='g'}" + Margin="10,2" IsReadOnly="True" /> + </Grid> + + <Grid DockPanel.Dock="Top" Margin="0,0,0,0"> + <Grid.RowDefinitions> + <RowDefinition Height="*" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + + <Label Grid.Row="1" Grid.Column="0" Content="Canonicalization methods:" /> + <TextBox Grid.Row="1" Grid.Column="1" + Text="{Binding CanonicalizationMethods , Converter={StaticResource CollectionConverter}, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> <Label Grid.Row="2" Grid.Column="0" Content="Digest method:" /> <TextBox Grid.Row="2" Grid.Column="1" - Text="{Binding DigestMethod, Mode=OneWay}" - Margin="10,2" IsReadOnly="True" /> - - <Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:" Style="{StaticResource DigestValueLabelStyle}" /> - <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" - IsReadOnly="True" Style="{StaticResource DigestValueTextboxStyle}" /> - <ContentControl Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,10,0,0" - VerticalAlignment="Top" Width="50" Height="50"> - <ContentControl.LayoutTransform> - <ScaleTransform ScaleX="1.5" ScaleY="1.5" /> - </ContentControl.LayoutTransform> - <ContentControl.Style> - <Style TargetType="ContentControl"> - <Setter Property="Content" Value="" /> - <Setter Property="ToolTip" Value="" /> - <Style.Triggers> - <DataTrigger Binding="{Binding JobDataValid}" Value="True"> - <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> - <Setter Property="ToolTip" Value="Component data validates against schema" /> - </DataTrigger> - <DataTrigger Binding="{Binding JobDataValid}" Value="False"> - <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> - <Setter Property="ToolTip" Value="Component data does NOT validat against schema" /> - </DataTrigger> - </Style.Triggers> - </Style> - </ContentControl.Style> - </ContentControl> - - - <ScrollViewer Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" - Background="{x:Static SystemColors.ControlLightBrush}" - Margin="10,0,10,10"> - <ItemsControl Margin="3" x:Name="ComponentListing" ItemsSource="{Binding Components}" MinHeight="300"> - <ItemsControl.ItemContainerStyle> - <Style> - <Setter Property="FrameworkElement.Margin" Value="0,2" /> - </Style> - </ItemsControl.ItemContainerStyle> - <ItemsControl.ItemTemplate> - <DataTemplate> - <Border BorderBrush="White" BorderThickness="1" CornerRadius="2"> - <Expander Margin="4" Header="{Binding}" Style="{DynamicResource HeaderStretchExpanderStyle}"> - <Expander.HeaderTemplate> - <DataTemplate> - <DockPanel HorizontalAlignment="Stretch"> - <ContentControl DockPanel.Dock="Right" Width="35" Height="35" Margin="0,0,10,0"> - <ContentControl.LayoutTransform> - <ScaleTransform ScaleX=".4" ScaleY=".4" /> - </ContentControl.LayoutTransform> - <ContentControl.Style> - <Style TargetType="ContentControl"> - <Setter Property="Content" Value="" /> - <Style.Triggers> - <DataTrigger Binding="{Binding Valid}" Value="True"> - <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> - </DataTrigger> - <DataTrigger Binding="{Binding Valid}" Value="False"> - <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> - </DataTrigger> - </Style.Triggers> - </Style> - </ContentControl.Style> - </ContentControl> - <TextBlock DockPanel.Dock="Left" Text="{Binding Component}" Margin="4,0" FontSize="16" FontWeight="Bold" /> - </DockPanel> - </DataTemplate> - </Expander.HeaderTemplate> - <Expander.Content> - <Grid Margin="0,5,0,0"> - <Grid.RowDefinitions> - <RowDefinition /> - <RowDefinition /> - <RowDefinition /> - <RowDefinition/> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="*"/> - </Grid.ColumnDefinitions> - - <Label Grid.Row="0" Grid.Column="0" Content="Canonicalization methods:" /> - <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding CanonicalizationMethod , Converter={StaticResource CollectionConverter}}" - Margin="10,2" IsReadOnly="True" /> - - <Label Grid.Row="1" Grid.Column="0" Content="Digest method:" /> - <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DigestMethod}" - Margin="10,2" IsReadOnly="True" /> - - <Label Grid.Row="2" Grid.Column="0" Content="Digest Value read:" Style="{StaticResource DigestValueLabelStyle}" /> - <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding DigestValueRead}" - Margin="10,2" IsReadOnly="True"> - <TextBox.Style> - <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> - <Style.Triggers> - <DataTrigger Binding="{Binding Valid}" Value="True"> - <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}"/> - </DataTrigger> - <DataTrigger Binding="{Binding Valid}" Value="False"> - <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}"/> - </DataTrigger> - </Style.Triggers> - </Style> - </TextBox.Style> - </TextBox> - - <Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:" Style="{StaticResource DigestValueLabelStyle}" /> - <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" - Margin="10,2" IsReadOnly="True" > - <TextBox.Style> - <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> - <Style.Triggers> - <DataTrigger Binding="{Binding Valid}" Value="True"> - <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}"/> - </DataTrigger> - <DataTrigger Binding="{Binding Valid}" Value="False"> - <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}"/> - </DataTrigger> - </Style.Triggers> - </Style> - </TextBox.Style> - </TextBox> - - </Grid> - - </Expander.Content> - </Expander> - </Border> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - </ScrollViewer> - - </Grid> + Text="{Binding DigestMethod, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" + IsReadOnly="True" Style="{StaticResource DigestValueTextboxStyle}" /> + <ContentControl Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,10,0,0" + VerticalAlignment="Top" Width="50" Height="50"> + <ContentControl.LayoutTransform> + <ScaleTransform ScaleX="1.5" ScaleY="1.5" /> + </ContentControl.LayoutTransform> + <ContentControl.Style> + <Style TargetType="ContentControl"> + <Setter Property="Content" Value="" /> + <Setter Property="ToolTip" Value="" /> + <Style.Triggers> + <DataTrigger Binding="{Binding JobDataValid}" Value="True"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> + <Setter Property="ToolTip" Value="Component data validates against schema" /> + </DataTrigger> + <DataTrigger Binding="{Binding JobDataValid}" Value="False"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> + <Setter Property="ToolTip" Value="Component data does NOT validat against schema" /> + </DataTrigger> + </Style.Triggers> + </Style> + </ContentControl.Style> + </ContentControl> + + + <ScrollViewer Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" + Background="{x:Static SystemColors.ControlLightBrush}" + Margin="10,0,10,10"> + <ItemsControl Margin="3" x:Name="ComponentListing" ItemsSource="{Binding Components}" MinHeight="300"> + <ItemsControl.ItemContainerStyle> + <Style> + <Setter Property="FrameworkElement.Margin" Value="0,2" /> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border BorderBrush="White" BorderThickness="1" CornerRadius="2"> + <Expander Margin="4" Header="{Binding}" Style="{DynamicResource HeaderStretchExpanderStyle}"> + <Expander.HeaderTemplate> + <DataTemplate> + <DockPanel HorizontalAlignment="Stretch"> + <ContentControl DockPanel.Dock="Right" Width="35" Height="35" Margin="0,0,10,0"> + <ContentControl.LayoutTransform> + <ScaleTransform ScaleX=".4" ScaleY=".4" /> + </ContentControl.LayoutTransform> + <ContentControl.Style> + <Style TargetType="ContentControl"> + <Setter Property="Content" Value="" /> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </ContentControl.Style> + </ContentControl> + <TextBlock DockPanel.Dock="Left" Text="{Binding Component}" Margin="4,0" FontSize="16" FontWeight="Bold" /> + </DockPanel> + </DataTemplate> + </Expander.HeaderTemplate> + <Expander.Content> + <Grid Margin="0,5,0,0"> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="Certification Number:" /> + <TextBox Grid.Row="0" Grid.Column="1" + Text="{Binding CertificationNumber}" + Margin="10,2" IsReadOnly="True" /> + <Label Grid.Row="0" Grid.Column="2" Content="Date:" /> + <TextBox Grid.Row="0" Grid.Column="3" + Text="{helper:CultureAwareBinding Path=CertificationDate, StringFormat='g'}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="1" Grid.Column="0" Content="Canonicalization methods:" /> + <TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" + Text="{Binding CanonicalizationMethod , Converter={StaticResource CollectionConverter}}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="2" Grid.Column="0" Content="Digest method:" /> + <TextBox Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding DigestMethod}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="3" Grid.Column="0" Content="Digest Value read:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding DigestValueRead}" + Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + <Label Grid.Row="4" Grid.Column="0" Content="Digest Value computed:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding DigestValueComputed}" + Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + </Grid> + + </Expander.Content> + </Expander> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </ScrollViewer> + + </Grid> </DockPanel> </ScrollViewer> </DockPanel> diff --git a/HashingTool/Views/VerifyResults.xaml b/HashingTool/Views/VerifyResults.xaml index b42b13e957..455f9ec4df 100644 --- a/HashingTool/Views/VerifyResults.xaml +++ b/HashingTool/Views/VerifyResults.xaml @@ -6,6 +6,7 @@ xmlns:viewModel="clr-namespace:HashingTool.ViewModel" xmlns:views="clr-namespace:HashingTool.Views" xmlns:helper="clr-namespace:HashingTool.Helper" + xmlns:userControl="clr-namespace:HashingTool.ViewModel.UserControl" x:Class="HashingTool.Views.VerifyResults" mc:Ignorable="d"> <UserControl.DataContext> @@ -14,11 +15,10 @@ <UserControl.Resources> <helper:CollectionConverter x:Key="CollectionConverter" /> - <DataTemplate x:Key="ExpanderHeader" DataType="viewModel:VectoXMLFile"> + <DataTemplate x:Key="ExpanderHeader" DataType="userControl:VectoXMLFile"> <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="top" MinWidth="450"> <TextBlock DockPanel.Dock="Top" Text="{Binding Name}" FontWeight="Bold" /> - <ContentControl DockPanel.Dock="Right" Width="35" Height="35" Margin="10,-10,10,0" - ToolTip="{Binding JobValidToolTip}"> + <ContentControl DockPanel.Dock="Right" Width="35" Height="35" Margin="10,-10,10,0"> <ContentControl.LayoutTransform> <ScaleTransform ScaleX=".4" ScaleY=".4" /> </ContentControl.LayoutTransform> @@ -42,7 +42,7 @@ </DockPanel> </DataTemplate> - <DataTemplate x:Key="ExpanderHeaderJobFile" DataType="viewModel:VectoJobFile"> + <DataTemplate x:Key="ExpanderHeaderJobFile" DataType="userControl:VectoJobFile"> <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="top" MinWidth="450"> <TextBlock DockPanel.Dock="Top" Text="{Binding Name}" FontWeight="Bold" /> @@ -67,11 +67,38 @@ </ContentControl> <views:VectoXMLFileSelector DockPanel.Dock="Left" Margin="0,0,0,0" VerticalAlignment="Top" XMLFile="{Binding XMLFile}" Height="1" /> + </DockPanel> + </DataTemplate> + + <DataTemplate x:Key="ExpanderHeaderManufacturerReport" DataType="userControl:ManufacturerReportXMLFile"> + <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="top" MinWidth="450"> + <TextBlock DockPanel.Dock="Top" Text="{Binding Name}" FontWeight="Bold" /> + <ContentControl DockPanel.Dock="Right" Width="35" Height="35" Margin="10,-10,10,0"> + <ContentControl.LayoutTransform> + <ScaleTransform ScaleX=".4" ScaleY=".4" /> + </ContentControl.LayoutTransform> + <ContentControl.Style> + <Style TargetType="ContentControl"> + <Setter Property="Content" Value="" /> + <Style.Triggers> + <DataTrigger Binding="{Binding ManufacturerReportValid}" Value="True"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> + </DataTrigger> + <DataTrigger Binding="{Binding ManufacturerReportValid}" Value="False"> + <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </ContentControl.Style> + </ContentControl> + <views:VectoXMLFileSelector DockPanel.Dock="Left" Margin="0,0,0,0" VerticalAlignment="Top" + XMLFile="{Binding XMLFile}" Height="1" /> </DockPanel> </DataTemplate> - <DataTemplate x:Key="ExpanderContentJobFile" DataType="viewModel:VectoXMLFile"> + + <DataTemplate x:Key="ExpanderContentJobFile" DataType="userControl:VectoJobFile"> <Grid Grid.IsSharedSizeScope="True"> <Grid.RowDefinitions> <RowDefinition /> @@ -128,19 +155,104 @@ <Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:" Style="{StaticResource DigestValueLabelStyle}" /> <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" IsReadOnly="True" Style="{StaticResource DigestValueTextboxStyle}" /> + + <!--<Expander Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="4" Header="Components">--> + <GroupBox Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" Header="Vehicle Components" + Style="{DynamicResource CustomGroupboxStyle}"> + <Grid IsSharedSizeScope="True" Margin="10,10,0,0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="ComponentLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="certificationNbrLabel" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateField" MinWidth="150" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="Vehicle" FontWeight="Bold" Margin="0,0,10,0" /> + <Label Grid.Row="0" Grid.Column="1" Content="VIN:" /> + <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding VehicleIdentificationNumber, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="0" Grid.Column="3" Content="Date:" /> + <TextBox Grid.Row="0" Grid.Column="4" + Text="{helper:CultureAwareBinding Path=JobCreationDate, StringFormat='g', Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + + <ItemsControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" DockPanel.Dock="Bottom" + ItemsSource="{Binding Components}" Margin="0,5,0,0"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Grid Margin="0, 5"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="ComponentLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="certificationNbrLabel" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateField" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="{Binding Component}" FontWeight="Bold" Margin="0,0,10,0" /> + <Label Grid.Row="0" Grid.Column="1" Content="Certification Number:" /> + <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding CertificationNumber}" + Margin="10,2" IsReadOnly="True" /> + <Label Grid.Row="0" Grid.Column="3" Content="Date:" /> + <TextBox Grid.Row="0" Grid.Column="4" + Text="{helper:CultureAwareBinding Path=CertificationDate, StringFormat='g'}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="1" Grid.Column="1" Content="Digest Value:" /> + <TextBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="3" Text="{Binding DigestValueRead}" + Margin="10,2" > + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}"/> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}"/> + <Setter Property="ToolTip"> + <Setter.Value> + <TextBlock Text="{Binding DigestValueComputed, StringFormat='{}Computed digest value: {0}'}"></TextBlock> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + </Grid> + </DataTemplate> + </ItemsControl.ItemTemplate> + + </ItemsControl> + <!--</Expander>--> + </Grid> + </GroupBox> </Grid> </DataTemplate> - <DataTemplate x:Key="ExpanderContentReport" DataType="viewModel:ReportXMLFile"> + <DataTemplate x:Key="ExpanderContentReport" DataType="userControl:ReportXMLFile"> <Grid Grid.IsSharedSizeScope="True"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> + <RowDefinition /> </Grid.RowDefinitions> - <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"> - <Label> + <DockPanel Grid.Row="0" Grid.Column="0"> + + <Label DockPanel.Dock="Left"> <Label.Content> <TextBlock Text="{Binding XMLFile.XMLValidationErrors.Count, StringFormat='{}{0} Warnings/Errors'}" /> </Label.Content> @@ -155,7 +267,8 @@ </Style> </Label.Style> </Label> - <Button Margin="10,0,0,0" Content="Details..." HorizontalAlignment="Left" Width="91" Click="Button_Click"> + <Button DockPanel.Dock="Left" Margin="10,0,0,0" Content="Details..." HorizontalAlignment="Left" Width="91" + Click="Button_Click"> <Button.Style> <Style TargetType="Button"> <Setter Property="IsEnabled" Value="True" /> @@ -167,9 +280,14 @@ </Style> </Button.Style> </Button> - </StackPanel> - <GroupBox Grid.Row="1" Header="Report Integrity" Margin="0,0,0,5" Style="{DynamicResource CustomGroupboxStyle}"> + <TextBox DockPanel.Dock="Right" Text="{helper:CultureAwareBinding Path=CreationDate, StringFormat='g'}" + Margin="10,2,20,2" IsReadOnly="True" MinWidth="150" /> + <Label DockPanel.Dock="Right" Content="Creation Date:" HorizontalAlignment="Right" /> + + </DockPanel> + + <GroupBox Grid.Row="2" Header="Report Integrity" Margin="0,0,0,5" Style="{DynamicResource CustomGroupboxStyle}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" /> @@ -224,7 +342,8 @@ </TextBox> </Grid> </GroupBox> - <GroupBox Grid.Row="2" Header="Job Integrity" Style="{DynamicResource CustomGroupboxStyle}"> + + <GroupBox Grid.Row="3" Header="Job Integrity" Style="{DynamicResource CustomGroupboxStyle}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" /> @@ -281,6 +400,256 @@ </Grid> </DataTemplate> + <DataTemplate x:Key="ExpanderContentManufacturerReport" DataType="userControl:ManufacturerReportXMLFile"> + <Grid Grid.IsSharedSizeScope="True"> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <DockPanel Grid.Row="0" Grid.Column="0"> + + <Label DockPanel.Dock="Left"> + <Label.Content> + <TextBlock Text="{Binding XMLFile.XMLValidationErrors.Count, StringFormat='{}{0} Warnings/Errors'}" /> + </Label.Content> + <Label.Style> + <Style TargetType="Label"> + <Setter Property="Foreground" Value="Red" /> + <Style.Triggers> + <DataTrigger Binding="{Binding XMLFile.XMLValidationErrors.Count}" Value="0"> + <Setter Property="Foreground" Value="Black" /> + </DataTrigger> + </Style.Triggers> + </Style> + </Label.Style> + </Label> + <Button DockPanel.Dock="Left" Margin="10,0,0,0" Content="Details..." HorizontalAlignment="Left" Width="91" + Click="Button_Click"> + <Button.Style> + <Style TargetType="Button"> + <Setter Property="IsEnabled" Value="True" /> + <Style.Triggers> + <DataTrigger Binding="{Binding XMLFile.XMLValidationErrors.Count}" Value="0"> + <Setter Property="IsEnabled" Value="False" /> + </DataTrigger> + </Style.Triggers> + </Style> + </Button.Style> + </Button> + + <TextBox DockPanel.Dock="Right" Text="{helper:CultureAwareBinding Path=CreationDate, StringFormat='g'}" + Margin="10,2,20,2" MinWidth="150" /> + <Label DockPanel.Dock="Right" Content="Creation Date:" HorizontalAlignment="Right" /> + + </DockPanel> + <GroupBox Grid.Row="2" Header="Report Integrity" Margin="0,0,0,5" Style="{DynamicResource CustomGroupboxStyle}"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="Canonicalization methods:" /> + <TextBox Grid.Row="0" Grid.Column="1" + Text="{Binding CanonicalizationMethods, Mode=OneWay , Converter={StaticResource CollectionConverter}}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="1" Grid.Column="0" Content="Digest method:" /> + <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DigestMethod, Mode=OneWay}" Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="2" Grid.Column="0" Content="Digest Value read:" Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding DigestValueRead}" Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + <Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding Valid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + <DataTrigger Binding="{Binding Valid}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + </Grid> + </GroupBox> + + <GroupBox Grid.Row="3" Header="Job Integrity" Style="{DynamicResource CustomGroupboxStyle}"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + <Label Grid.Row="0" Grid.Column="0" Content="Job CanonicalizationMethod:" /> + <TextBox Grid.Row="0" Grid.Column="1" + Text="{Binding JobCanonicalizationMethodRead, Mode=OneWay, Converter={StaticResource CollectionConverter}}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="1" Grid.Column="0" Content="Job Digest Method:" /> + <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding JobDigestMethodRead, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + <Label Grid.Row="2" Grid.Column="0" Content="Job Digest Value Read:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding JobDigestValueRead, Mode=OneWay}" + Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + <Style.Triggers> + <DataTrigger Binding="{Binding JobDigestValid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + <Label Grid.Row="3" Grid.Column="0" Content="Job Digest Value Computed:" + Style="{StaticResource DigestValueLabelStyle}" /> + <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding JobDigestValueComputed, Mode=OneWay}" + Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + <Style.Triggers> + <DataTrigger Binding="{Binding JobDigestValid}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + </Grid> + </GroupBox> + + <GroupBox Grid.Row="4" Header="Vehicle Components" Style="{DynamicResource CustomGroupboxStyle}"> + <Grid Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" IsSharedSizeScope="True" Margin="10,10,0,0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="ComponentLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="certificationNbrLabel" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="dateField" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="Vehicle" FontWeight="Bold" Margin="0,0,10,0" /> + <Label Grid.Row="0" Grid.Column="1" Content="VIN:" /> + <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding VehicleIdentificationNumber, Mode=OneWay}" + Margin="10,2" IsReadOnly="True" /> + + <ItemsControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" DockPanel.Dock="Bottom" + ItemsSource="{Binding Components}" Margin="0,5,0,0"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Grid Margin="0,5"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" SharedSizeGroup="ComponentLabel" /> + <ColumnDefinition Width="Auto" SharedSizeGroup="certificationNbrLabel" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition /> + <RowDefinition /> + </Grid.RowDefinitions> + + <Label Grid.Row="0" Grid.Column="0" Content="{Binding Component}" FontWeight="Bold" Margin="0,0,10,0" /> + <Label Grid.Row="0" Grid.Column="1" Content="Certification Number:" /> + <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding CertificationNumber}" + Margin="10,2" IsReadOnly="True"> + <TextBox.Style> + <Style TargetType="TextBox"> + <Setter Property="IsEnabled" Value="True" /> + <Style.Triggers> + <DataTrigger Binding="{Binding CertificationMethod}" Value="Standard values"> + <Setter Property="IsEnabled" Value="False" /> + </DataTrigger> + <DataTrigger Binding="{Binding CertificationNumberMatchesJobComponent}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + <Setter Property="ToolTip"> + <Setter.Value> + <TextBlock + Text="{Binding CertificationNumberExpected, StringFormat='{}Expected Certification Number: {0}'}" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + <Label Grid.Row="1" Grid.Column="1" Content="Digest Value:" /> + <TextBox Grid.Row="1" Grid.Column="2" Text="{Binding DigestValue}" + Margin="10,2"> + <TextBox.Style> + <Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}"> + <Style.Triggers> + <DataTrigger Binding="{Binding DigestValueMatchesJobComponent}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" /> + </DataTrigger> + <DataTrigger Binding="{Binding DigestValueMatchesJobComponent}" Value="False"> + <Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" /> + <Setter Property="ToolTip"> + <Setter.Value> + <TextBlock Text="{Binding DigestValueExpected, StringFormat='{}Expected Digest Value: {0}'}" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBox.Style> + </TextBox> + + </Grid> + </DataTemplate> + </ItemsControl.ItemTemplate> + + </ItemsControl> + <!--</Expander>--> + </Grid> + </GroupBox> + </Grid> + </DataTemplate> + + <BorderGapMaskConverter x:Key="BorderGapMaskConverter" /> <Style x:Key="CustomGroupboxStyle" TargetType="{x:Type GroupBox}"> @@ -353,7 +722,7 @@ </Style> </ItemsControl.ItemContainerStyle> <ItemsControl.Resources> - <DataTemplate DataType="{x:Type viewModel:VectoJobFile}"> + <DataTemplate DataType="{x:Type userControl:VectoJobFile}"> <Border BorderBrush="White" BorderThickness="1" CornerRadius="2" Margin="0,0,3,0"> <Expander Margin="2" Header="{Binding}" HorizontalAlignment="Stretch" @@ -364,7 +733,7 @@ </Border> </DataTemplate> - <DataTemplate DataType="{x:Type viewModel:ReportXMLFile}"> + <DataTemplate DataType="{x:Type userControl:ReportXMLFile}"> <Border BorderBrush="White" BorderThickness="1" CornerRadius="2" Margin="0,0,3,0"> <Expander Margin="2" Header="{Binding}" HorizontalAlignment="Stretch" Style="{DynamicResource HeaderStretchExpanderStyle}" @@ -373,6 +742,16 @@ </Border> </DataTemplate> + <DataTemplate DataType="{x:Type userControl:ManufacturerReportXMLFile}"> + <Border BorderBrush="White" BorderThickness="1" CornerRadius="2" Margin="0,0,3,0"> + <Expander Margin="2" Header="{Binding}" HorizontalAlignment="Stretch" + Style="{DynamicResource HeaderStretchExpanderStyle}" + HeaderTemplate="{DynamicResource ExpanderHeaderManufacturerReport}" + ContentTemplate="{DynamicResource ExpanderContentManufacturerReport}" + Content="{Binding}" /> + </Border> + + </DataTemplate> </ItemsControl.Resources> </ItemsControl> @@ -426,7 +805,7 @@ <Style TargetType="ContentControl"> <Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" /> <Style.Triggers> - <DataTrigger Binding="{Binding ManufacturerReport.JobDigestValid}" Value="True"> + <DataTrigger Binding="{Binding ManufacturerReport.ManufacturerReportValid}" Value="True"> <Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" /> </DataTrigger> </Style.Triggers> diff --git a/HashingTool/Views/VerifyResults.xaml.cs b/HashingTool/Views/VerifyResults.xaml.cs index 557207dd44..005603e7cc 100644 --- a/HashingTool/Views/VerifyResults.xaml.cs +++ b/HashingTool/Views/VerifyResults.xaml.cs @@ -1,6 +1,7 @@ using System.Windows; using System.Windows.Controls; using HashingTool.ViewModel; +using HashingTool.ViewModel.UserControl; namespace HashingTool.Views { diff --git a/VectoCommon/VectoHashing/Properties/AssemblyInfo.cs b/VectoCommon/VectoHashing/Properties/AssemblyInfo.cs index 27c4ea3afa..b337fe1ec3 100644 --- a/VectoCommon/VectoHashing/Properties/AssemblyInfo.cs +++ b/VectoCommon/VectoHashing/Properties/AssemblyInfo.cs @@ -29,40 +29,40 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly: AssemblyTitle("VectoHashing")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("VectoHashing")] -[assembly: AssemblyCopyright("Copyright © 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly: Guid("334248fa-331e-4255-97fe-617e1a497f6f")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("VectoHashing")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("VectoHashing")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("334248fa-331e-4255-97fe-617e1a497f6f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] diff --git a/VectoCommon/VectoHashing/VectoHash.cs b/VectoCommon/VectoHashing/VectoHash.cs index 1f1654c230..29cd8453e9 100644 --- a/VectoCommon/VectoHashing/VectoHash.cs +++ b/VectoCommon/VectoHashing/VectoHash.cs @@ -34,6 +34,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Cryptography.X509Certificates; using System.Xml; using System.Xml.Linq; using TUGraz.VectoCommon.Resources; @@ -89,9 +90,9 @@ namespace TUGraz.VectoHashing { var retVal = new List<VectoComponents>(); foreach (var component in EnumHelper.GetValues<VectoComponents>()) { - var count = - Document.SelectNodes(string.Format("//*[local-name()='{0}']//*[local-name()='{1}']", - XMLNames.VectoInputDeclaration, component.XMLElementName())).Count; + var nodes = Document.SelectNodes(string.Format("//*[local-name()='{0}']//*[local-name()='{1}']", + XMLNames.VectoInputDeclaration, component.XMLElementName())); + var count = nodes == null ? 0 : nodes.Count; for (var i = 0; i < count; i++) { retVal.Add(component); } @@ -318,6 +319,27 @@ namespace TUGraz.VectoHashing return DoReadHash(component, index); } + public string GetCertificationNumber(VectoComponents component, int idx) + { + var nodes = GetNodes(component, idx); + return ReadElementValue(nodes[idx], XMLNames.Component_CertificationNumber); + } + + public DateTime GetCertificationDate(VectoComponents component, int idx) + { + var nodes = GetNodes(component, idx); + return XmlConvert.ToDateTime(ReadElementValue(nodes[idx], XMLNames.Component_Date), XmlDateTimeSerializationMode.RoundtripKind); + } + + private string ReadElementValue(XmlNode xmlNode, string elementName) + { + var node = xmlNode.SelectSingleNode(string.Format("./*[local-name()='{0}']", elementName)); + if (node == null) { + throw new Exception(string.Format("Node '{0}' not found!", elementName)); + } + return node.InnerText; + } + private string DoReadHash(VectoComponents? component, int index) { var nodes = GetNodes(component, index); @@ -352,7 +374,7 @@ namespace TUGraz.VectoHashing } - private static string GetComponentQueryString(VectoComponents? component = null) + protected static string GetComponentQueryString(VectoComponents? component = null) { if (component == null) { return "(//*[@id])[1]"; @@ -390,5 +412,7 @@ namespace TUGraz.VectoHashing } return nodes[0].InnerText; } + + } } -- GitLab