From 9af8f967a6184b0ae1c20c57133d54ed549a368d Mon Sep 17 00:00:00 2001 From: Michael Hoffmeister Date: Mon, 1 Jan 2024 17:20:51 +0100 Subject: [PATCH] * temp commit --- src/AasxCsharpLibrary/AdminShellUtil.cs | 6 +- .../Extensions/ExtendIReferable.cs | 12 + src/AasxCsharpLibrary/Extensions/ExtendKey.cs | 2 +- .../Extensions/ExtendReference.cs | 6 + .../AasForms/AasFormUtils.cs | 28 ++ src/AasxPackageExplorer.sln | 2 +- src/AasxPackageExplorer/debug.MIHO.script | 4 +- .../options-debug.MIHO.json | 16 +- src/AasxPackageLogic/DispEditHelperBasics.cs | 4 +- .../DispEditHelperMultiElement.cs | 40 +- src/AasxPackageLogic/ExplorerMenuFactory.cs | 2 +- ...hangeElementAttributesFlyoutAnyUiFlyout.cs | 104 ++++ .../Resources/no-contact-preview.png | Bin 2205 -> 2206 bytes .../AasxPluginDocumentShelf.csproj | 10 +- src/AasxPluginDocumentShelf/DocumentEntity.cs | 21 +- src/AasxPluginDocumentShelf/Plugin.cs | 8 +- .../Resources/bin-preview.png | Bin 0 -> 9159 bytes .../Resources/zip-preview.png | Bin 0 -> 2625 bytes .../ShelfAnyUiControl.cs | 233 +++++---- .../ShelfPreviewService.cs | 292 +++++++++++ .../AasxPredefinedConcepts.csproj | 1 + .../DefinitionsAssetInterfacesDescription.cs | 457 ++++++++++++++++++ .../ExportPredefinedConcepts.cs | 24 +- .../PredefinedConceptsClassMapper.cs | 449 +++++++++++++++++ src/AasxWpfControlLibrary/AnyUiWpf.cs | 13 +- src/AnyUi/AnyUiDialogueDataBase.cs | 14 +- src/BlazorExplorer/Pages/Index.razor | 9 + src/BlazorExplorer/options-debug.MIHO.json | 3 +- src/DefinitionsAssetInterfacesDescriptionX.cs | 450 +++++++++++++++++ 29 files changed, 2077 insertions(+), 133 deletions(-) create mode 100644 src/AasxPackageLogic/Flyouts/ChangeElementAttributesFlyoutAnyUiFlyout.cs create mode 100644 src/AasxPluginDocumentShelf/Resources/bin-preview.png create mode 100644 src/AasxPluginDocumentShelf/Resources/zip-preview.png create mode 100644 src/AasxPluginDocumentShelf/ShelfPreviewService.cs create mode 100644 src/AasxPredefinedConcepts/DefinitionsAssetInterfacesDescription.cs create mode 100644 src/AasxPredefinedConcepts/PredefinedConceptsClassMapper.cs create mode 100644 src/DefinitionsAssetInterfacesDescriptionX.cs diff --git a/src/AasxCsharpLibrary/AdminShellUtil.cs b/src/AasxCsharpLibrary/AdminShellUtil.cs index f4d0e2984..244844e6e 100644 --- a/src/AasxCsharpLibrary/AdminShellUtil.cs +++ b/src/AasxCsharpLibrary/AdminShellUtil.cs @@ -458,10 +458,14 @@ public static string ToSingleLineShortened(string str, int maxLen, string textNe /// Assert.AreEqual("someName", AdminShellUtil.FilterFriendlyName("someName")); /// Assert.AreEqual("some__name", AdminShellUtil.FilterFriendlyName("some!;name")); /// - public static string FilterFriendlyName(string src) + public static string FilterFriendlyName(string src, bool pascalCase = false) { if (src == null) return null; + + if (pascalCase && src.Length > 0) + src = char.ToUpper(src[0]) + src.Substring(1); + return Regex.Replace(src, @"[^a-zA-Z0-9\-_]", "_"); } diff --git a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs index eb451c9d0..860713b67 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs @@ -204,6 +204,18 @@ public static void BaseValidation(this IReferable referable, AasValidationRecord })); } + /// + /// Tells, if the IReferable can sub-structure more elements + /// + public static bool IsStructured(this IReferable rf) + { + return (rf is ISubmodel + || rf is ISubmodelElementCollection + || rf is ISubmodelElementList + || rf is IOperation + || rf is IEntity); + } + /// /// Tells, if the IReferable is used with an index instead of idShort. /// diff --git a/src/AasxCsharpLibrary/Extensions/ExtendKey.cs b/src/AasxCsharpLibrary/Extensions/ExtendKey.cs index af1753bbc..b02f3d5e5 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendKey.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendKey.cs @@ -16,7 +16,7 @@ namespace Extensions { public static class ExtendKey { - public static IKey CreateFrom(Reference r) + public static IKey CreateFrom(Reference r) { if (r == null || r.Count() != 1) return null; diff --git a/src/AasxCsharpLibrary/Extensions/ExtendReference.cs b/src/AasxCsharpLibrary/Extensions/ExtendReference.cs index c40db77ae..10a459f69 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendReference.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendReference.cs @@ -82,6 +82,12 @@ public static Reference CreateNew(List lk) return res; } + public static Reference CreateFromString(string id, KeyTypes keyType = KeyTypes.GlobalReference) + { + var k = new Key(keyType, id); + return new Reference(ReferenceTypes.ExternalReference, new List(new IKey[] { k })); + } + // TODO (Jui, 2023-01-05): Check why the generic Copy does not apply here?! public static Reference Copy(this Reference original) { diff --git a/src/AasxIntegrationBase/AasForms/AasFormUtils.cs b/src/AasxIntegrationBase/AasForms/AasFormUtils.cs index 234048f96..38fcc9adf 100644 --- a/src/AasxIntegrationBase/AasForms/AasFormUtils.cs +++ b/src/AasxIntegrationBase/AasForms/AasFormUtils.cs @@ -18,6 +18,26 @@ namespace AasxIntegrationBase.AasForms { public static class AasFormUtils { + public static FormMultiplicity? GetCardinality(List qs) + { + if (qs == null) + return null; + + var multiTrigger = new[] { "Multiplicity", "Cardinality", "SMT/Cardinality" }; + foreach (var mt in multiTrigger) + { + var q = qs?.FindQualifierOfType(mt); + if (q != null) + { + foreach (var m in (FormMultiplicity[])Enum.GetValues(typeof(FormMultiplicity))) + if (("" + q.Value) == Enum.GetName(typeof(FormMultiplicity), m)) + return m; + } + } + + return null; + } + private static void RecurseExportAsTemplate( List smwc, FormDescListOfElement tels, Aas.Environment env = null, List cds = null) @@ -115,6 +135,9 @@ private static void RecurseExportAsTemplate( if (q != null) tsme.FormEditDescription = q.Value.Trim().ToLower() == "true"; + // TODO (MIHO, 24-01-01): reorganize access to qualifiers + +#if __old__ var multiTrigger = new[] { "Multiplicity", "Cardinality", "SMT/Cardinality" }; foreach (var mt in multiTrigger) { @@ -126,6 +149,11 @@ private static void RecurseExportAsTemplate( tsme.Multiplicity = m; } } +#else + var mlc = GetCardinality(qs); + if (mlc.HasValue) + tsme.Multiplicity = mlc.Value; +#endif q = qs?.FindQualifierOfType("PresetValue"); if (q != null && tsme is FormDescProperty) diff --git a/src/AasxPackageExplorer.sln b/src/AasxPackageExplorer.sln index 7b8e4b608..b9c9e43a9 100644 --- a/src/AasxPackageExplorer.sln +++ b/src/AasxPackageExplorer.sln @@ -160,7 +160,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AasxPluginDigitalNameplate" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AasxPluginContactInformation", "AasxPluginContactInformation\AasxPluginContactInformation.csproj", "{938BB137-DC45-4A84-B0C9-AC46DA321FDB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AasxCore.Samm2_2_0", "AasxCore.Samm2_2_0\AasxCore.Samm2_2_0.csproj", "{DCFD6C2F-A7C5-4AA2-82F3-0D3856E7EA99}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AasxCore.Samm2_2_0", "AasxCore.Samm2_2_0\AasxCore.Samm2_2_0.csproj", "{DCFD6C2F-A7C5-4AA2-82F3-0D3856E7EA99}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/AasxPackageExplorer/debug.MIHO.script b/src/AasxPackageExplorer/debug.MIHO.script index 3ca941dec..2997bd867 100644 --- a/src/AasxPackageExplorer/debug.MIHO.script +++ b/src/AasxPackageExplorer/debug.MIHO.script @@ -9,7 +9,9 @@ // Tool("sammaspectimport", "File", "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\BatteryPass-spiel.ttl"); // Tool("sammaspectimport", "File", "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\Batch-MM-2_0_0.ttl"); Tool("editkey"); -Tool("sammaspectimport", "File", "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\Aspect_Example_SML_MLP.ttl"); +Select("Submodel", "First"); +// Tool("sammaspectimport", "File", "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\Aspect_Example_SML_MLP.ttl"); +Tool("exportpredefineconcepts", "File", "C:\HOMI\Develop\Aasx\repo\aid\new.txt"); // Tool("submodelinstancefromsmtconcepts"); // Select("ConceptDescription", "First"); // Select("ConceptDescription", "Next"); diff --git a/src/AasxPackageExplorer/options-debug.MIHO.json b/src/AasxPackageExplorer/options-debug.MIHO.json index 0bb7cf2b8..57406223f 100644 --- a/src/AasxPackageExplorer/options-debug.MIHO.json +++ b/src/AasxPackageExplorer/options-debug.MIHO.json @@ -32,6 +32,9 @@ // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\Test1.aasx", // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\SMT_and_SAMM_Showcase_v02.aasx", // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\samm-test\\Aspect_Example_SML_MLP.ttl", + // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\8001203_SPAU-P10R-T-R18M-L-PNLK-PNVBA-M8D_060ff64f-9fd2-422d-81ce-b17e49f007c5_work.aasx", + "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\aid\\2023_AID1.0_Template_Rework_MIHO.aasx", + // "AasxRepositoryFn": "C:\\HOMI\\Develop\\Aasx\\repo_Festo_demo_case_V3\\Festo-DemoCase-repo-V3-local.json", "WindowLeft": 200, "WindowTop": -1, "WindowWidth": 900, @@ -164,22 +167,21 @@ { "Path": "..\\..\\..\\..\\..\\..\\AasxPluginExportTable\\bin\\Debug\\net6.0-windows\\AasxPluginExportTable.dll", "Args": [] - } /* , -, + }, { - "Path": "..\\..\\..\\..\\..\\..\\AasxPluginWebBrowser\\bin\\x64\\Debug\\net6.0-windows\\AasxPluginWebBrowser.dll", + "Path": "..\\..\\..\\..\\..\\..\\AasxPluginWebBrowser\\bin\\x64\\Debug\\AasxPluginWebBrowser.dll", "Args": [] - } + }, // Festo specific from here on { - "Path": "..\\..\\..\\..\\..\\..\\..\\AasxFesto\\AasxFesto\\AasxPluginFluiddrawViewer\\bin\\Debug\\net6.0-windows\\AasxPluginFluiddrawViewer.dll", + "Path": "..\\..\\..\\..\\..\\..\\..\\..\\AasxFesto\\AasxFesto\\AasxPluginFluiddrawViewer\\bin\\Debug\\net6.0-windows\\AasxPluginFluiddrawViewer.dll", "Args": [] }, { - "Path": "..\\..\\..\\..\\..\\..\\..\\AasxFesto\\AasxFesto\\AasxPluginFluiddrawBom\\bin\\Debug\\net6.0-windows\\AasxPluginFluiddrawBom.dll", + "Path": "..\\..\\..\\..\\..\\..\\..\\..\\AasxFesto\\AasxFesto\\AasxPluginFluiddrawBom\\bin\\Debug\\net6.0-windows\\AasxPluginFluiddrawBom.dll", "Args": [] - } + } /* // Festo specific from here on { "Path": "..\\..\\..\\..\\..\\..\\..\\AasxFesto\\AasxFesto\\AasxPluginFluiddrawViewer\\bin\\Debug\\AasxPluginFluiddrawViewer.dll", diff --git a/src/AasxPackageLogic/DispEditHelperBasics.cs b/src/AasxPackageLogic/DispEditHelperBasics.cs index 83355d9ae..8d498238e 100644 --- a/src/AasxPackageLogic/DispEditHelperBasics.cs +++ b/src/AasxPackageLogic/DispEditHelperBasics.cs @@ -955,9 +955,9 @@ public void AddKeyListLangStr( // check here, if to hightlight if (tbStr != null && this.highlightField != null && this.highlightField.fieldHash == langStr[currentI].Text.GetHashCode() && - //(this.highlightField.containingObject == langStr[currentI])) + (this.highlightField.containingObject == (object) langStr[currentI])) //TODO (jtikekar, 0000-00-00): need to test - CompareUtils.Compare((IAbstractLangString)this.highlightField.containingObject, langStr[currentI])) + // CompareUtils.Compare((IAbstractLangString)this.highlightField.containingObject, langStr[currentI])) this.HighligtStateElement(tbStr, true); // button [-] diff --git a/src/AasxPackageLogic/DispEditHelperMultiElement.cs b/src/AasxPackageLogic/DispEditHelperMultiElement.cs index 267a18fb4..db78f44f5 100644 --- a/src/AasxPackageLogic/DispEditHelperMultiElement.cs +++ b/src/AasxPackageLogic/DispEditHelperMultiElement.cs @@ -254,18 +254,22 @@ public string PerformWildcardReplace(string input, string pattern) input = ""; } - if (p0 == '^') + if (pattern.Length >= 1 && pattern.StartsWith('>')) { - metaChar = true; - res += input.ToUpper(); - input = ""; - } + // greed variants with ^*, §* + if (p0 == '^') + { + metaChar = true; + res += input.ToUpper(); + input = ""; + } - if (p0 == '§') - { - metaChar = true; - res += input.ToLower(); - input = ""; + if (p0 == '§') + { + metaChar = true; + res += input.ToLower(); + input = ""; + } } // only with input @@ -278,6 +282,20 @@ public string PerformWildcardReplace(string input, string pattern) input = input.Remove(0, 1); } + // normal variant, not greedy + if (p0 == '^') + { + metaChar = true; + res += char.ToUpper(input[0]); + input = input.Remove(0, 1); + } + if (p0 == '§') + { + metaChar = true; + res += char.ToLower(input[0]); + input = input.Remove(0, 1); + } + if (p0 == '~') { metaChar = true; @@ -669,7 +687,7 @@ public void DisplayOrEditAasEntityMultipleElements( AddActionPanel(stack, "Actions:", repo: repo, superMenu: superMenu, ticketMenu: new AasxMenu() - .AddAction("aas-elem-cut", "Change attribute ..", + .AddAction("change-attr", "Change attribute ..", "Changes common attributes of multiple selected elements.") .AddAction("remove-extension", "Remove extensions ..", "Removes a specific selected extension from elements."), diff --git a/src/AasxPackageLogic/ExplorerMenuFactory.cs b/src/AasxPackageLogic/ExplorerMenuFactory.cs index 8a5f9afa4..eceae9aec 100644 --- a/src/AasxPackageLogic/ExplorerMenuFactory.cs +++ b/src/AasxPackageLogic/ExplorerMenuFactory.cs @@ -219,7 +219,7 @@ public static AasxMenu CreateMainMenu() .AddWpfBlazor(name: "ExportPredefineConcepts", header: "Export Submodel as snippet for PredefinedConcepts …", args: new AasxMenuListOfArgDefs() - .Add("File", "OPC UA Nodeset2.xml file to write.") + .Add("File", "Text file to write.") .Add("Location", "Location selection", hidden: true)) .AddWpfBlazor(name: "SubmodelTDExport", header: "Export Submodel as Thing Description JSON LD document", help: "Export Thing Description (TD) file in JSON LD format from an existing Submodel.", diff --git a/src/AasxPackageLogic/Flyouts/ChangeElementAttributesFlyoutAnyUiFlyout.cs b/src/AasxPackageLogic/Flyouts/ChangeElementAttributesFlyoutAnyUiFlyout.cs new file mode 100644 index 000000000..46cc9159d --- /dev/null +++ b/src/AasxPackageLogic/Flyouts/ChangeElementAttributesFlyoutAnyUiFlyout.cs @@ -0,0 +1,104 @@ +/* +Copyright (c) 2018-2023 Festo SE & Co. KG +Author: Michael Hoffmeister + +This source code is licensed under the Apache License 2.0 (see LICENSE.txt). + +This source code may use other Open Source software components (see LICENSE.txt). +*/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; +using System.Xml; +using System.Xml.Schema; +using AasxIntegrationBase; +using AasxIntegrationBase.AasForms; +using Newtonsoft.Json; +using Aas = AasCore.Aas3_0; +using AdminShellNS; +using Extensions; +using AnyUi; + +namespace AasxPackageLogic +{ + public static class ChangeElementAttributesFlyoutAnyUiFlyout + { + public static AnyUiDialogueDataModalPanel CreateModelDialogue( + AnyUiDialogueDataChangeElementAttributes innerDiaData) + { + // ok, go on .. + var uc = new AnyUiDialogueDataModalPanel(innerDiaData.Caption); + uc.ActivateRenderPanel(innerDiaData, + (uci) => + { + // create panel + var panel = new AnyUiStackPanel(); + var helper = new AnyUiSmallWidgetToolkit(); + + var g = helper.AddSmallGrid(5, 4, new[] { "220:", "3*", "100:", "1*" }, + padding: new AnyUiThickness(0, 5, 0, 5)); + g.RowDefinitions[1].MinHeight = 16.0; + g.RowDefinitions[3].MinHeight = 16.0; + panel.Add(g); + + // Row 0 : Attribute and language + helper.AddSmallLabelTo(g, 0, 0, content: "Attribute:", verticalCenter: true); + AnyUiUIElement.SetIntFromControl( + helper.Set( + helper.AddSmallComboBoxTo(g, 0, 1, + items: AnyUiDialogueDataChangeElementAttributes.AttributeNames, + selectedIndex: (int)innerDiaData.AttributeToChange), + minWidth: 400), + (i) => { innerDiaData.AttributeToChange = (AnyUiDialogueDataChangeElementAttributes.AttributeEnum)i; }); + + helper.AddSmallLabelTo(g, 0, 2, content: "Language:", verticalCenter: true); + AnyUiUIElement.SetStringFromControl( + helper.Set( + helper.AddSmallComboBoxTo(g, 0, 3, + text: innerDiaData.AttributeLang, + items: AasxLanguageHelper.GetLangCodes().ToArray(), + isEditable: true), + minWidth: 200), + (s) => { innerDiaData.AttributeLang = s; }); + + // Row 2 : Change pattern + helper.AddSmallLabelTo(g, 2, 0, content: "Change pattern:", verticalCenter: true); + AnyUiUIElement.SetStringFromControl( + helper.Set( + helper.AddSmallComboBoxTo(g, 2, 1, + text: innerDiaData.Pattern, + items: AnyUiDialogueDataChangeElementAttributes.PatternPresets, + isEditable: true), + minWidth: 600, + colSpan: 3), + (s) => { innerDiaData.Pattern = s; }); + + // Row 4 : Help + helper.AddSmallLabelTo(g, 4, 0, content: "Help:"); + helper.Set( + helper.AddSmallLabelTo(g, 4, 1, + margin: new AnyUiThickness(0, 2, 2, 2), + content: string.Join(System.Environment.NewLine, AnyUiDialogueDataChangeElementAttributes.HelpLines), + verticalAlignment: AnyUiVerticalAlignment.Top, + verticalContentAlignment: AnyUiVerticalAlignment.Top, + fontSize: 0.7, + wrapping: AnyUiTextWrapping.Wrap), + colSpan: 3, + minHeight: 100, + horizontalAlignment: AnyUiHorizontalAlignment.Stretch); + + // give back + return panel; + }); + return uc; + } + } +} diff --git a/src/AasxPluginContactInformation/Resources/no-contact-preview.png b/src/AasxPluginContactInformation/Resources/no-contact-preview.png index 84bf85284064296a5ed864a9232ce5ca56fa8d63..f084eb257e4b248fe081bbd8afa70d9d2229a7f4 100644 GIT binary patch delta 14 VcmbO$I8TtZGr-TCcO%P84geuO1T+8u delta 13 UcmbOyI9HIRGr-S%BkN2K03Ij=CjbBd diff --git a/src/AasxPluginDocumentShelf/AasxPluginDocumentShelf.csproj b/src/AasxPluginDocumentShelf/AasxPluginDocumentShelf.csproj index f296a7ec9..22dd84969 100644 --- a/src/AasxPluginDocumentShelf/AasxPluginDocumentShelf.csproj +++ b/src/AasxPluginDocumentShelf/AasxPluginDocumentShelf.csproj @@ -8,10 +8,12 @@ false - - - - + + + + + + diff --git a/src/AasxPluginDocumentShelf/DocumentEntity.cs b/src/AasxPluginDocumentShelf/DocumentEntity.cs index e2aa85ebb..2e4baab97 100644 --- a/src/AasxPluginDocumentShelf/DocumentEntity.cs +++ b/src/AasxPluginDocumentShelf/DocumentEntity.cs @@ -17,6 +17,7 @@ This source code may use other Open Source software components (see LICENSE.txt) using Extensions; using AnyUi; using System.Threading.Tasks; +using System.Reflection; namespace AasxPluginDocumentShelf { @@ -143,7 +144,25 @@ public AnyUiBitmapInfo LoadImageFromPath(string fn) } return null; } - } + + /// + /// This function needs to be called as part of tick-Thread in STA / UI thread + /// + public AnyUiBitmapInfo LoadImageFromResource(string path) + { + // convert here, as the tick-Thread in STA / UI thread + try + { + ImgContainerAnyUi.BitmapInfo = AnyUiGdiHelper.CreateAnyUiBitmapFromResource(path, + assembly: Assembly.GetExecutingAssembly()); + } + catch (Exception ex) + { + LogInternally.That.SilentlyIgnoredError(ex); + } + return null; + } + } public class ListOfDocumentEntity : List { diff --git a/src/AasxPluginDocumentShelf/Plugin.cs b/src/AasxPluginDocumentShelf/Plugin.cs index 0170aa542..6c7887ac7 100644 --- a/src/AasxPluginDocumentShelf/Plugin.cs +++ b/src/AasxPluginDocumentShelf/Plugin.cs @@ -30,6 +30,8 @@ public class AasxPlugin : AasxPluginBase private DocumentShelfOptions _options = new DocumentShelfOptions(); + private ShelfPreviewService _previewService = null; + public class Session : PluginSessionBase { public AasxPluginDocumentShelf.ShelfAnyUiControl AnyUiControl = null; @@ -60,6 +62,10 @@ public class Session : PluginSessionBase // index them! _options.IndexListOfRecords(_options.Records); + + // start preview service + _previewService = new ShelfPreviewService(); + _previewService.StartOperation(_log); } public new AasxPluginActionDescriptionBase[] ListActions() @@ -157,7 +163,7 @@ public class Session : PluginSessionBase var opContext = args[5] as PluginOperationContextBase; session.AnyUiControl = AasxPluginDocumentShelf.ShelfAnyUiControl.FillWithAnyUiControls( _log, args[0], args[1], _options, _eventStack, session, args[2], opContext, - args[3] as AnyUiContextPlusDialogs, this); + args[3] as AnyUiContextPlusDialogs, this, _previewService); // give object back var res = new AasxPluginResultBaseObject(); diff --git a/src/AasxPluginDocumentShelf/Resources/bin-preview.png b/src/AasxPluginDocumentShelf/Resources/bin-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..cf08da145be4af713726bddf4182b878874963d5 GIT binary patch literal 9159 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
sn}AE9?P|FPq%u4v)oV zO5geZCVw9Xfi^J6_~Kh!`84y!D6ff(ZsmYx2Tfl7NJdIT^qMFCOqvVY45e_06e#Oy z4u%UqFA-zrv;2)mwB8)+}-P`@iBIeG_V!@OhsRwXF6KqEi{jL+w>?-GWbZ({@^rQYv8Q1V#znB-Ov+)Z)2vnZTvtl3S+%CZ%l>H6LXulR!$S!Ow}d90lZ zWI*>Q{5SJD#|fW%`|1D@>l;kXcJ-F4aC2ofaL!nv4-6_dYX%zQj$B}m*V6{=;+!r+ zbf==J?n2-T1-j~fX1n<2ju$$(wMx;ZzjWt*#(+|9!iX13b?!g4TF}bRa#1d~AH;73 zhVX3k!rfk5t}e>G!u9egewtGFXoAF$|LtI1Vb?t|f)Z~SwN+n_H38g5!gZOT_d%+K zt=T?`JExhB;vmE602FQDXI1aJOut%~5P8jX5b(Y&CGqRq?Y4P@Xwt}ZH>zVt^V`|m z+b;n3@c`$Uh1}fCfU&vZ&z^j{ih3r>bdv2Uj)4`OSb+~zfo#EPHGJ=PdAxIN$9*-H z7C^l|7hUbFCd4~p%5ee#k?daC+`rW1aXkKpUW|K)>96y}+vlehy9Mby7iSkyjC3Nc z%DpXLPc=Y=X2$s&1&~qW`yc3Vk^QroEG87LK5;l5C2nY3GlL^A2#z?S^z(=f*r!>& z)9XQv;@tW~&#RG6YoUy#t=f(xQ{fP8I)Tt1i&fte7Nim<;E^9NW^(*tf}y7VP-uV{ zTJJ!f!85Gyh`an{*c9VH8^)YIvBrcRYX-y;xhD6HFEF`@%ZqP`RvH z1x^t;t80RJoknu~Hn-&Cm{j$S9LLlt9#bXyVxwJoSL}I-DmE8l7wTKb)-%lrH< z*u@Z=wk&{@p4$bdvu5p4*snCc775EdLrwgwHdc&+Q7DPw*gpO<6erClQLUrH$WIlp zOc{t(iKg+C3CHpKl?NJ2aNZ}t2F6*s*m{jaRmREjSyrtCQ2DF^$y#P z&j?FxQ;`&}u0=mS_Tl5V7pwg2HH;Of71h5i>?RaodmOKspau2@ON6k8iF%O*J}Im8 z+lN8?o-Xq!Dc-WG{Ad@ixvquT`=iQPtvzUcze(K7%i4t+#r0>0W(#QsX2#FN;r18-sr%s>x7lBDo~YS;(s0CB5_id z`{MzY!Q9LiBvr7KS;+@c8<)RjFkgQ3%(*N``I~K9*6NyHg7E?snFtr-(hH21d-xOO z9ojIBI=zmrLJsy2WRMN@6^Re-Ye*+D+3QGr7Cx&%R+i;?e(T1+BRDsx)JfHT?r{8QQ?-+_2~6tKas=%Eh^TrUpxH zdGN-qlq#3N_Z?}A83~^kJTlDusw=dg7VS<1jCfCjJBVq)$K`yzvN|#RbTK2#7-L$9 zfrbL0J|7v4=I&5BNqe5gswshSRD3VPoo)?6}Q^+IqJ}`Ot#Kc zs??Cdv!9p0`4D%+W=5+ti}xBLo>MbUyF#`~caHjebg+yopBhj{5LujtEaD`4L#b0n z=%c3O)8#cUf(PUj=PdM0_`x3fSE;geGQsi55)$u1RPFMqjQZ9c^@q7unZJJitP@Qm z;yM^+vj$5OFxt}1Z^SFx)pR1%&%;2fUlj3h#NBLrjd+E9-M!o~>qrx1s!-9mqMyIY z?5xsjK~2(kc2wGX$pFigwO4J)8`Uce0a(C208Pj`yJ;a<|q9g{v3;WYbg)ga9J5@rkRj2N5F}yM1wFB2~*nS!R z8Rk+H>!A&I)0&w_trs0!&x5?(5*Ra!ynBv^mS0dpMwn6{*?4Y9BCeDrsA%~R_oQmQ z+`ZZPkNHbYpL1Jw8Zym0ddfYFXrgr$qEM#tQ=t~oTY|cO11>3bvwLqy6@kmY0&ZZj zGIcGv8GZ^3To=1^o<%C$^{4EAVDP?SqS(ikiX)+rBH{DPwuwIxG$VVVHsMFMc}aqE zcoLQc&vn?ss3w+BmfNSQYaW9sg~1RRi#K?cdUIMVB=Rj14g|m(z557s!_w0Ksm%TN z2>Tz*Ku92g^zj8xZS&M?ZQy3e?7M;l#VD5f}2MAF8oM-v>%FXDKR>Hfu=4_QB5i`ghMwQ0?lUfnI%-PY)ZLd2=+ z>d`*c%bS>SK?lQ5nFBv`xH*aAH?Hsm(5yB9WW21j%Vs(@E9sfl;zM z>5ej^+aunul?Z#{+XONckoroU?PATkNBglymYO+-U#0V&yq3Y(+H9*IE&Aa1g!zL_ z6`;t2$;pM@-i2|F5T6;+#nn2bObhM)V|-g)((7}N2JFAe8NGMP-_r_j$+7Tuzg}(7 zu|cVN5^>}p;dWW8cv#-Ic0SlmrAD38ts+e@Fx9@M>)dF2`_JTiluUm~4+}&BYL}rN z(o%3Yd2dpUDHkrrkQKcLE^)voWl-VO;rzw0nHZhx`Dxldywvnmsvl~x)AlM$w@SxT zQu=WY-hmGT$A-?&1m}xZD;lZn2X#)PMd%VYxzgL<16GOZePXWdh)ml1j=0>s?V*UR zl#Oq!!LNo#TFQHg;F(Xb_-a*}t})!cE2e$RBv{M+*`*FX_~I9HJ5y7c~+$inaZZ|R-Y_0uO?FbqZoX)i?U zU>VYMvc#k~=oDpgs!ny9`PtO}lk!bNOz9(;KnD|&g7Lbe3h<31t#IR-aK01PtTf8{ z92sImOFlI>@`oU>nqyyZAs;+QVtuYkuaUjyH}rI9!W((#vR)Wq%(%DJzi;7VGIl(y zn5ghap2BwujTj+Z-MtIfNd)W5tqo4Ta@C58EuQt2lQQl7m$QJN*+ z@@b7S-G9};JIbZ)1Bd1R{B(!&NtjJF;s=*WQ%`GX#-7Qq-?3l)3Qs1^lvWD`x)^wk z63kbW-(9eJ+#z$~7R3>=21Gh{t8r^J2-K%M__4b%hR{r|gK5|Y&t=hkvh)1VrrKq$ zjV&EIqwh+F2Sowz~{b**W9yx`%n0zV^u4|FOCXvxFRjY+6B65BHi8O<}<>UJxe} z78oH>_wwwU7#xACuq0k6b05s z`)%bn+zt&XK!Q(hg_f$$G6fPXWg{v93Oj2#DFyr%iCPZ9SR#h zI%T;A2N}-G$XIM1EHhyj{e)l;YOO!K9OXYzvGK_8GIlib#tY<|XVq(lOEx?yp^JGs z$U72zHIpBK>h(U|$trlOzzQ9yon$k7|G5VJ)yr>ZK<6$T42v-rDaCn1GAYE<;<8SL z;MLW?(xP77KkmJilBhincP!=q{>SH@v;fx-t@xDS=wP@s7M`x59;#dBgV-M3<5y#? zl;3_T2t_#x0)88BzaV1~GJ`KI-}g*!vLiRX*XwOB&>Zg(cWsW68xaGjhc`}_jWD&V zmiB+BU8Q*Hg$)UHUYFITLuOf*P zI2J~YZ>kK-sYMSq+@z#fskQ!cybh62FHDDhZP=|sTP6+|{q?2g{Mo_gBpGr|CKF%Z zFXHJ;^R4RbdcT4**eM1J=sT;wx;WB>tg7}eRR#7NpN&2w^Lg(rF7|XPRs!tINzcfV zk`ve|Lae141D4eSf!iLEq>V-<)?$}S^r_UC!3n}K#-hvL+oHg8wz)j~87hB4C5VdL z2c(OUoY>>vPNINskCCgQbPa7`RR){EWMi-d+>a}v3lrm_vHeMSvd#DF0Z_-a&k^_B zF=8Whe#dq@mGDAve%n=leoFz($O)RBHwk7*kL4YCp6Wm4NR@3>J5<|`V1OI_%@1e^ zC6n6Jx?fy)FLhm)-tkQi0C{p1AQ^XZ20Wo@Qe2Ci+drqlm>=?&0AEW=Mc((ZwjIHi zZe;&2yI#Vp8ZJ9x8X;kQS4mdtYxag@K#rqQX@MTvSyCK_1stqq=@4Mc;k3K1wch5M z%|~EI#8jIk8{XprW!*}->8c!VjRa$y$jk*a6C|M|{0+kpfX5;80&ToWt_rDO&ayT` z{_|Cj=mRNHy50tdUeQ-SQ`HD?>Bns@dRUFNSs&5z|`XEK8b_ z{km$l@#AbQXpySywBZIh%>3u6XTCx8+KW6(g%}~yGu~x%> z#$n!`^F^AAa97@z4MxM<43ts-&G?4Fib^o!n?~#w6G*lX&!}zC02RpJ%YFNStKdav zW#rM8VMri44hGZtGrr3HrJtei@5;Rj5e3$6*UJN5_lVdoTqlL6ujp0qQ6`QCapo#F4=12E$YD}b&O9R7>*WyRc)uq3;h;Ss~ghKHY( z?x0D1>HK}tA?#+ijHd7T)riLk(_8Zuvw$yhpRShUTvxU42#ISszecid_L9|Ds+hs>_rKd=+M(O>GzuDb#G7y#S)gUeW?m~*RsAD=S3W8F z>n%ksFmH6d%DX?60YwuP$46!pVQq+Ir$Eua!xD)t$FDdgI4bi$I#-OhU1-bKGQ{?g zsVKVQUX&h{xVlTj+z%5&gI$44%=Vp8E%X3>yHaRwE!y+${MTik9zDISyt|;7rJ%%ZgA7I?N|%zyH2RmDLr1u4trPnh3xFNnDZ?6f_>T-E|cS#yyV}oTr5v1-1xMA5!{qN>i7p8{sU?rRb7LVr9QZ^ikS9pN!6s#}_bie%nwr~7bgGc-` zQTap_01(9Zt7}4j=je_J0D9(>We_(`PNpZE0ZZa$Li#d5oj!SJf~OAHKqSL`_emBU zFJ?W1_YM&eaf%k$NG8Mmm60F!wj{Q`Nb`PrHzzPxbYQsQUdoYZjx6*e62O9xUgScF zH_h^mP!-lQqN!>A^)!nH0muSk?i2O|rf${;2|#3%U7@DRYHB8|ug1)M2;6{flJI`x zborf=lQ{YH-R_Z`*n47y5}KR ztg^N;006ts&G`rbkeosQjgU`#HIn6uiaFxC8x*(c4$B29)XCim09J;|a*%>tuespn z8v}r9{mOtejrPOxnqZ%^)3G@J@z3t({5tSgC>dNm8XXyJtgV$!M;91fc3khdDf7Kq zK}x2vSMXu4&#`Hpyp6l&iVBJgB8|PgY&EMc9Yb`~?JY@@4<8JU%r2rC;U8q{GMz!D%U?jycN{$* zaCiT+=t{r*V+9=rGB3i`g~a6G;NbA^0w0ra(RQ-JzMX4oO(i#OUiPBmiNjXHhugQ2AoCxKX_}vX%Y+W znTTw%FURe{1n&Kd0RIy#=S&4vG|cM?vC>`5%sGzU>aZcqlc|YdZUSzGt0Kh8?~T}x zF~-8H{tt7Ad8Vd5-P)*A1?8g-o~{lS-t1(e#qqgLjM8dmmS+96b_MPA=h8sYD!KoA zsS}fB=CHvi;oN29YUWO5^|5c^v-+}P@tup(sq#`%_^_ns;DTXJF5CY;$?luS1y9~_ zGy*-h#E#U?ij7ZRYW{s~kLlt%-FN;B>dD1uuKsL$V}wM8zl?-ZyFL{MRI)}r7Kaw2 zXTLOLlbkl733RgL?hd^~bN^A=l|3-1H%U})F5}i~7N^9^)w`EtTE*v<45@zuh+ms# zBLcY5eUyk77cV`sWROv6ft0iV)aKtF@b{cY6KbFRrsapRJ*Bh}LR}r_G&dHac%}&E zwQ%5Op-9aDMZr2igASbxHqY#ErI|@YlVs`B$^ouR&q7x!X}F$beoTmbOFBE@9p#=l zQ-!CcOviF?gJbiwwnrnaHWEHbFNgW;9gc@ZSXkB|rs`iV5JTgq+0@d^7_9it zJ+q|Wi!0jH;dIeqLEPtH>f9E-_W+)ugW~zmAstgJ3CJJWV~Wbm@DMlN8f+Hg0uwa? zG2d~}t5D%DJ>6GisiN$W`qN)@cm{~DfrXOvECCKg@tV?_^R}E8 zzT&fN59QQILlci3-+>4VpS>76e)BB&KCV~6#j~Xx$>Muce+|_=z#Xq7&!F0Umvr;S zX(IQrQMMVYV#E4tAbVRRlTt`4%@lws8YjVtl@xt=8O``<;2&o{Asy?N!$Fo~5Sqb? zQ-o7RRYG%1#Z&{B(~nQ3#}H1!NYvZgjk6y0;%Xs| zNw!WBtkXq=^~$gNoczgm)cQzDk1;26;ZBE!?PpLtm~ymrX7G#4M%wL~p+keY+1589 zl>F(y`jms#jEt{V+CW3#?nH-HytA6{!AN)_G_f^^a`uX4?Ny)}gRCvr$?LfD6=Yi6 zgmTD+bjSsD!RO&he;GsQUS^mQj4Dx_(Smf(=z=zO_N?4kqutAaU!3Q_bLd|98M*2k z#2`U9c8LzMSlDa)+#a!`Ry-whwzQ>f8-)mz{^4a&NFK@BM!{FD7UCQj8k>}jg(g|U zPjzVnj;9CxtRY+J?so%3+$n-0 zj0$lqQG?6LFLadP=}=|qb6Q)jr9v%^rv=4*tg%@OUSsX@OEVxpg)$fLSkx!W?-Irk z|BybVCC5=`1}Xg9jR~7h7=ren!Hler6qL9r*xN4x#pGha^#ggJbYVR~Wx%7~Y<&M| z4xEP$%ph;cAxkUDa4W5>e14+48#m-Jg+p{&`TQ9b5gpiGiv?>q@PxW!EeL$O^cX*o zfW#qB5a3&lB`rwDQ|*9r=}M&~?2XJe0HggolF!Y&(NGM|B)ywuiF?M^2_|4cK7Q` zBixr0_=a3eS!Jai?G!_=cF6luvZOAFw(Wy-rtg+*z@*Hk27^*yB(HfIbH26^!saV6 zUWPojWEczsAz)1B)r~fHB&>DMT`=3b6K)O|_u=$BscYqN_bD-_(gZ19`~j5fuc==lXgxY*ouI+ z|A+{%ux!y|$Kjz*J{JIGh4lHOA-puRV-bMQ=S$I7eZKE5Q}i^^a&^Vy)U3;$KkuF; z+6b&4HGjRSXFuWr8&z%@(JCOZ*2H;UI^WvTB3?(>7D>76u)HhC+q&37+c8yGIyR=< z_(q4yK9c{crpCWeG;w4mw`$_j0ruayQfDHxV}c!xKNlGp85QMS__hw=+dMR#wmT?3 z{*$SMH!79v!~mSCuq*Yy_Wk1-e&Ebow 0 && - numDocEntitiesInPreview < maxDocEntitiesInPreview) + // new approach: push into preview service + if (_previewService != null) { - // pop - DocumentEntity ent = null; lock (theDocEntitiesToPreview) { - ent = theDocEntitiesToPreview[0]; - theDocEntitiesToPreview.RemoveAt(0); + foreach (var de in theDocEntitiesToPreview) + _previewService.Push(new ShelfPreviewService.RenderEntity(_package, de?.DigitalFile?.Path)); + theDocEntitiesToPreview.Clear(); } - - try + } + else + { +#if __old_approach + // each tick check for one image, if a preview shall be done + if (theDocEntitiesToPreview != null && theDocEntitiesToPreview.Count > 0 && + numDocEntitiesInPreview < maxDocEntitiesInPreview) { - // temp input - var inputFn = ent?.DigitalFile?.Path; - if (inputFn != null) + // pop + DocumentEntity ent = null; + lock (theDocEntitiesToPreview) { - // try check if Magick.NET library is available - var thumbBI = AnyUiGdiHelper.MakePreviewFromPackageOrUrl(_package, inputFn); - if (thumbBI != null) + ent = theDocEntitiesToPreview[0]; + theDocEntitiesToPreview.RemoveAt(0); + } + + try + { + // temp input + var inputFn = ent?.DigitalFile?.Path; + if (inputFn != null) { - // directly add this - if (referableHashToCachedBitmap != null - && !referableHashToCachedBitmap.ContainsKey(ent.ReferableHash)) + // try check if Magick.NET library is available + var thumbBI = AnyUiGdiHelper.MakePreviewFromPackageOrUrl(_package, inputFn); + if (thumbBI != null) { - if (ent.ImgContainerAnyUi != null) - ent.ImgContainerAnyUi.BitmapInfo = thumbBI; - referableHashToCachedBitmap[ent.ReferableHash] = thumbBI; - updateDisplay = true; + // directly add this + if (referableHashToCachedBitmap != null + && !referableHashToCachedBitmap.ContainsKey(ent.ReferableHash)) + { + if (ent.ImgContainerAnyUi != null) + ent.ImgContainerAnyUi.BitmapInfo = thumbBI; + referableHashToCachedBitmap[ent.ReferableHash] = thumbBI; + updateDisplay = true; + } } - } - else - { - // - // OLD way: use external program to convert - // - - // makes only sense under Windows - if (OperatingSystemHelper.IsWindows()) + else { - // from package? - if (CheckIfPackageFile(inputFn)) - inputFn = _package?.MakePackageFileAvailableAsTempFile(ent.DigitalFile.Path); + // + // OLD way: use external program to convert + // - // temp output - string outputFn = System.IO.Path.GetTempFileName().Replace(".tmp", ".png"); + // makes only sense under Windows + if (OperatingSystemHelper.IsWindows()) + { + // from package? + if (CheckIfPackageFile(inputFn)) + inputFn = _package?.MakePackageFileAvailableAsTempFile(ent.DigitalFile.Path); - // remember these for later deletion - ent.DeleteFilesAfterLoading = new[] { inputFn, outputFn }; + // temp output + string outputFn = System.IO.Path.GetTempFileName().Replace(".tmp", ".png"); - // start process - string arguments = string.Format( - "-flatten -density 75 \"{0}\"[0] \"{1}\"", inputFn, outputFn); - string exeFn = System.IO.Path.Combine( - System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - "convert.exe"); + // remember these for later deletion + ent.DeleteFilesAfterLoading = new[] { inputFn, outputFn }; - var startInfo = new ProcessStartInfo(exeFn, arguments) - { - WindowStyle = ProcessWindowStyle.Hidden - }; + // start process + string arguments = string.Format( + "-flatten -density 75 \"{0}\"[0] \"{1}\"", inputFn, outputFn); + string exeFn = System.IO.Path.Combine( + System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "convert.exe"); - var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; + var startInfo = new ProcessStartInfo(exeFn, arguments) + { + WindowStyle = ProcessWindowStyle.Hidden + }; - DocumentEntity lambdaEntity = ent; - string outputFnBuffer = outputFn; - process.Exited += (sender2, args) => - { - // release number of parallel processes - lock (mutexDocEntitiesInPreview) + var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; + + DocumentEntity lambdaEntity = ent; + string outputFnBuffer = outputFn; + process.Exited += (sender2, args) => { - numDocEntitiesInPreview--; + // release number of parallel processes + lock (mutexDocEntitiesInPreview) + { + numDocEntitiesInPreview--; + } + + // take over data? + if (lambdaEntity.ImgContainerAnyUi != null) + { + // trigger display image + lambdaEntity.ImageReadyToBeLoaded = outputFnBuffer; + } + }; + + try + { + process.Start(); } - - // take over data? - if (lambdaEntity.ImgContainerAnyUi != null) + catch (Exception ex) { - // trigger display image - lambdaEntity.ImageReadyToBeLoaded = outputFnBuffer; + AdminShellNS.LogInternally.That.Error( + ex, $"Failed to start the process: {startInfo.FileName} " + + $"with arguments {string.Join(" ", startInfo.Arguments)}"); } - }; - - try - { - process.Start(); - } - catch (Exception ex) - { - AdminShellNS.LogInternally.That.Error( - ex, $"Failed to start the process: {startInfo.FileName} " + - $"with arguments {string.Join(" ", startInfo.Arguments)}"); - } - // limit the number of parallel executions - lock (mutexDocEntitiesInPreview) - { - numDocEntitiesInPreview++; + // limit the number of parallel executions + lock (mutexDocEntitiesInPreview) + { + numDocEntitiesInPreview++; + } } } } } - } - catch (Exception ex) - { - AdminShellNS.LogInternally.That.SilentlyIgnoredError(ex); + catch (Exception ex) + { + AdminShellNS.LogInternally.That.SilentlyIgnoredError(ex); - if (_dispatcherNumException < 3) - _log?.Error(ex, "AasxPluginDocumentShelf / converting previews"); - else if (_dispatcherNumException == 3) - _log?.Info("AasxPluginDocumentShelf / stopping logging exceptions."); - _dispatcherNumException++; + if (_dispatcherNumException < 3) + _log?.Error(ex, "AasxPluginDocumentShelf / converting previews"); + else if (_dispatcherNumException == 3) + _log?.Info("AasxPluginDocumentShelf / stopping logging exceptions."); + _dispatcherNumException++; + } } +#endif } // over all items in order to check, if a prepared image shall be displayed @@ -1561,6 +1594,19 @@ private void DispatcherTimer_Tick(object sender, EventArgs e) if (de == null) continue; + // new approach + var re = _previewService?.Get(_package?.Filename, de?.DigitalFile?.Path); + if (re?.Bitmap != null + && referableHashToCachedBitmap != null + && !referableHashToCachedBitmap.ContainsKey(de.ReferableHash)) + { + if (de.ImgContainerAnyUi != null) + de.ImgContainerAnyUi.BitmapInfo = re.Bitmap; + referableHashToCachedBitmap[de.ReferableHash] = re.Bitmap; + updateDisplay = true; + } + +#if __old_approach if (de.ImageReadyToBeLoaded != null) { // never again @@ -1604,7 +1650,8 @@ private void DispatcherTimer_Tick(object sender, EventArgs e) _dispatcherNumException++; } } - } +#endif + } if (_eventStack != null && updateDisplay) _eventStack.PushEvent(new AasxPluginEventReturnUpdateAnyUi() @@ -1618,9 +1665,9 @@ private void DispatcherTimer_Tick(object sender, EventArgs e) _inDispatcherTimer = false; } - #endregion +#endregion - #region Utilities +#region Utilities //=============== private bool CheckIfPackageFile(string fn) @@ -1628,6 +1675,6 @@ private bool CheckIfPackageFile(string fn) return fn.StartsWith(@"/"); } - #endregion +#endregion } } diff --git a/src/AasxPluginDocumentShelf/ShelfPreviewService.cs b/src/AasxPluginDocumentShelf/ShelfPreviewService.cs new file mode 100644 index 000000000..848168a93 --- /dev/null +++ b/src/AasxPluginDocumentShelf/ShelfPreviewService.cs @@ -0,0 +1,292 @@ +/* +Copyright (c) 2018-2023 Festo SE & Co. KG +Author: Michael Hoffmeister + +This source code is licensed under the Apache License 2.0 (see LICENSE.txt). + +This source code may use other Open Source software components (see LICENSE.txt). +*/ + +using AasxIntegrationBase; +using AasxIntegrationBaseGdi; +using AdminShellNS; +using AnyUi; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace AasxPluginDocumentShelf +{ + /// + /// After many troubles with running the preview service (load or generate preview images + /// for files within AASX files) within the control, e.g. multiple instances, this is an + /// approach to create a singleton which is created only once for the overall application. + /// + public class ShelfPreviewService + { + // + // Start of service + // + + private LogInstance _log = new LogInstance(); + + private const int _timerTickMs = 300; + private System.Timers.Timer _dispatcherTimer = null; + + public void StartOperation(LogInstance log) + { + _log = log; + + _dispatcherTimer = new System.Timers.Timer(_timerTickMs); + _dispatcherTimer.Elapsed += DispatcherTimer_Tick; + _dispatcherTimer.Enabled = true; + _dispatcherTimer.Start(); + } + + // + // Render entities + // + + /// + /// Holds a single entity to render. The link to the (open) AASX package is cleared + /// as soon as possible to allow GC. The entities can be looked up by package filename + /// and inner file name. + /// + public class RenderEntity + { + public string PackageFn = null; + public string SupplFn = null; + + public AnyUiBitmapInfo Bitmap = null; + + public AdminShellPackageEnv Package = null; + + public DateTime LastUse = DateTime.Now; + + public RenderEntity(AdminShellPackageEnv package, string supplFn) + { + Package = package; + PackageFn = package?.Filename; + SupplFn = supplFn; + } + } + + /// + /// Incoming, from user + /// + protected List _toRenderEntities = new List(); + + /// + /// Popped from incoming, already available to be used + /// + protected Dictionary _renderedEntities = new Dictionary(); + + /// + /// Duplicated from _renderedEntities, to be frequently checked to be deleted + /// + protected List _toDeleteEntities = new List(); + + public void Push(RenderEntity ent) + { + lock (_toRenderEntities) + { + _toRenderEntities.Add(ent); + } + } + + public RenderEntity Get(string packageFn, string supplFn) + { + if (packageFn == null || supplFn == null) + return null; + var key = packageFn.Trim() + "|" + supplFn.Trim(); + if (!_renderedEntities.ContainsKey(key)) + return null; + var res = _renderedEntities[key]; + res.LastUse = DateTime.Now; + return res; + } + + protected void PushRendered(RenderEntity ent) + { + if (ent?.PackageFn == null || ent?.SupplFn == null) + return; + + // to output + var key = ent.PackageFn.Trim() + "|" + ent.SupplFn.Trim(); + ent.LastUse = DateTime.Now; + _renderedEntities.Add(key, ent); + + // also keep track to be deleted + _toDeleteEntities.Add(ent); + } + + // + // Service + // + + private object mutexDocEntitiesInPreview = new object(); + private int numDocEntitiesInPreview = 0; + + private const int maxDocEntitiesInPreview = 3; + + private const int maxMinutesToRetain = 3; + private const int maxRenderedEntitiesToKeep = 3; + + private bool _inDispatcherTimer = false; + + private void DispatcherTimer_Tick(object sender, EventArgs e) + { + // access + if (_toRenderEntities == null || _renderedEntities == null || _inDispatcherTimer) + return; + + _inDispatcherTimer = true; + + // each tick check for one image, if a preview shall be done + if (_toRenderEntities.Count > 0) + { + // pop + RenderEntity ent = null; + lock (_toRenderEntities) + { + ent = _toRenderEntities[0]; + _toRenderEntities.RemoveAt(0); + } + + // check, if valid entity is already in the output + var exist = Get(ent?.PackageFn, ent?.SupplFn); + if (exist != null) + return; + + // no, prepare + try + { + // temp input + if (ent?.Package != null && ent.PackageFn != null && ent.SupplFn != null) + { + // try check if Magick.NET library is available + var thumbBI = AnyUiGdiHelper.MakePreviewFromPackageOrUrl(ent.Package, ent.SupplFn); + if (thumbBI != null) + { + ent.Bitmap = thumbBI; + PushRendered(ent); + } + else + { + // + // OLD way: use external program to convert + // + + // makes only sense under Windows + if (OperatingSystemHelper.IsWindows()) + { + // from package? + var inputFn = ent.SupplFn; + if (inputFn.StartsWith("/")) + inputFn = ent.Package?.MakePackageFileAvailableAsTempFile(inputFn); + + // temp output + string outputFn = System.IO.Path.GetTempFileName().Replace(".tmp", ".png"); + + // start process + string arguments = string.Format( + "-flatten -density 75 \"{0}\"[0] \"{1}\"", inputFn, outputFn); + string exeFn = System.IO.Path.Combine( + System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "convert.exe"); + + var startInfo = new ProcessStartInfo(exeFn, arguments) + { + WindowStyle = ProcessWindowStyle.Hidden + }; + + var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; + + RenderEntity lambdaEntity = ent; + string inputFnBuffer = inputFn; + string outputFnBuffer = outputFn; + process.Exited += (sender2, args) => + { + // release number of parallel processes + lock (mutexDocEntitiesInPreview) + { + numDocEntitiesInPreview--; + } + + // try load + try + { + lambdaEntity.Bitmap = AnyUiGdiHelper.CreateAnyUiBitmapInfo(outputFnBuffer); + } + catch (Exception ex) + { + LogInternally.That.SilentlyIgnoredError(ex); + } + + // try delete + try + { + System.IO.File.Delete(inputFnBuffer); + System.IO.File.Delete(outputFnBuffer); + } + catch (Exception ex) + { + LogInternally.That.SilentlyIgnoredError(ex); + } + }; + + try + { + process.Start(); + } + catch (Exception ex) + { + AdminShellNS.LogInternally.That.Error( + ex, $"Failed to start the process: {startInfo.FileName} " + + $"with arguments {string.Join(" ", startInfo.Arguments)}"); + } + + // limit the number of parallel executions + lock (mutexDocEntitiesInPreview) + { + numDocEntitiesInPreview++; + } + } + } + } + } + catch (Exception ex) + { + AdminShellNS.LogInternally.That.SilentlyIgnoredError(ex); + } + } + + // check to release ressources? + if (_toDeleteEntities != null + && _toDeleteEntities.Count >= maxRenderedEntitiesToKeep + && (DateTime.Now - _toDeleteEntities[0].LastUse).TotalMinutes >= maxMinutesToRetain) + { + // remove + var toRem = _toDeleteEntities[0]; + + if (_renderedEntities != null + && _renderedEntities.ContainsValue(toRem)) + { + var item = _renderedEntities.FirstOrDefault(kvp => kvp.Value == toRem); + _renderedEntities.Remove(item.Key); + } + + _toDeleteEntities.RemoveAt(0); + } + + + // release mutex + _inDispatcherTimer = false; + + } + } +} diff --git a/src/AasxPredefinedConcepts/AasxPredefinedConcepts.csproj b/src/AasxPredefinedConcepts/AasxPredefinedConcepts.csproj index 2a7230050..de9bd3a70 100644 --- a/src/AasxPredefinedConcepts/AasxPredefinedConcepts.csproj +++ b/src/AasxPredefinedConcepts/AasxPredefinedConcepts.csproj @@ -17,6 +17,7 @@ + diff --git a/src/AasxPredefinedConcepts/DefinitionsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/DefinitionsAssetInterfacesDescription.cs new file mode 100644 index 000000000..cf30ee537 --- /dev/null +++ b/src/AasxPredefinedConcepts/DefinitionsAssetInterfacesDescription.cs @@ -0,0 +1,457 @@ +/* +Copyright (c) 2018-2023 Festo SE & Co. KG + +Author: Michael Hoffmeister + +This source code is licensed under the Apache License 2.0 (see LICENSE.txt). + +This source code may use other Open Source software components (see LICENSE.txt). + +This source code was auto-generated by the AASX Package Explorer. +*/ + +using AasxIntegrationBase; +using AdminShellNS; +using Extensions; +using System; +using System.Collections.Generic; +using Aas = AasCore.Aas3_0; + +namespace AasxPredefinedConcepts.AssetInterfacesDescription +{ + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface")] + public class CD_GenericInterface + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasxPredefinedCardinality.One)] + string Title; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#created", Card = AasxPredefinedCardinality.ZeroToOne)] + DateTime? Created; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#modified", Card = AasxPredefinedCardinality.ZeroToOne)] + DateTime? Modified; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#support", Card = AasxPredefinedCardinality.ZeroToOne)] + string Support; + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/EndpointMetadata", Card = AasxPredefinedCardinality.One)] + CD_EndpointMetadata EndpointMetadata = new CD_EndpointMetadata(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/InterfaceMetadata", Card = AasxPredefinedCardinality.One)] + CD_InterfaceMetadata InterfaceMetadata = new CD_InterfaceMetadata(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/ExternalDescriptor", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_ExternalDescriptor ExternalDescriptor = null; + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/EndpointMetadata")] + public class CD_EndpointMetadata + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#base", Card = AasxPredefinedCardinality.One)] + string Base; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/hypermedia#forContentType", Card = AasxPredefinedCardinality.One)] + string ContentType; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasSecurityConfiguration", Card = AasxPredefinedCardinality.One)] + CD_Security Security = new CD_Security(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + CD_SecurityDefinitions SecurityDefinitions = new CD_SecurityDefinitions(); + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasSecurityConfiguration")] + public class CD_Security + { + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme")] + public class CD_SecurityDefinitions + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#NoSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Nosec_sc Nosec_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#AutoSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Auto_sc Auto_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#BasicSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Basic_sc Basic_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#ComboSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Combo_sc Combo_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#APIKeySecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Apikey_sc Apikey_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#PSKSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Psk_sc Psk_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#DigestSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Digest_sc Digest_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#BearerSecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Bearer_sc Bearer_sc = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#OAuth2SecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Oauth2_sc Oauth2_sc = null; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#NoSecurityScheme")] + public class CD_Nosec_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#AutoSecurityScheme")] + public class CD_Auto_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#BasicSecurityScheme")] + public class CD_Basic_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#name", Card = AasxPredefinedCardinality.ZeroToOne)] + string Name; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#in", Card = AasxPredefinedCardinality.ZeroToOne)] + string In; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#ComboSecurityScheme")] + public class CD_Combo_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#oneOf", Card = AasxPredefinedCardinality.One)] + CD_OneOf OneOf = new CD_OneOf(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#allOf", Card = AasxPredefinedCardinality.One)] + CD_AllOf AllOf = new CD_AllOf(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#oneOf")] + public class CD_OneOf + { + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#allOf")] + public class CD_AllOf + { + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#APIKeySecurityScheme")] + public class CD_Apikey_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#name", Card = AasxPredefinedCardinality.ZeroToOne)] + string Name; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#in", Card = AasxPredefinedCardinality.ZeroToOne)] + string In; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#PSKSecurityScheme")] + public class CD_Psk_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#identity", Card = AasxPredefinedCardinality.ZeroToOne)] + string Identity; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#DigestSecurityScheme")] + public class CD_Digest_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#name", Card = AasxPredefinedCardinality.ZeroToOne)] + string Name; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#in", Card = AasxPredefinedCardinality.ZeroToOne)] + string In; + + string Qop; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#BearerSecurityScheme")] + public class CD_Bearer_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#name", Card = AasxPredefinedCardinality.ZeroToOne)] + string Name; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#in", Card = AasxPredefinedCardinality.ZeroToOne)] + string In; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#authorization", Card = AasxPredefinedCardinality.ZeroToOne)] + string Authorization; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#alg", Card = AasxPredefinedCardinality.ZeroToOne)] + string Alg; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#format", Card = AasxPredefinedCardinality.ZeroToOne)] + string Format; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#OAuth2SecurityScheme")] + public class CD_Oauth2_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.One)] + string Scheme; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#token", Card = AasxPredefinedCardinality.ZeroToOne)] + string Token; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#refresh", Card = AasxPredefinedCardinality.ZeroToOne)] + string Refresh; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#authorization", Card = AasxPredefinedCardinality.ZeroToOne)] + string Authorization; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#scopes", Card = AasxPredefinedCardinality.ZeroToOne)] + string Scopes; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#flow", Card = AasxPredefinedCardinality.ZeroToOne)] + string Flow; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + string Proxy; + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/InterfaceMetadata")] + public class CD_InterfaceMetadata + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#PropertyAffordance", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_PropertiesAffordance Properties = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#ActionAffordance", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Actions Actions = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#EventAffordance", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Events Events = null; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#PropertyAffordance")] + public class CD_PropertiesAffordance + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfaceDescription/1/0/PropertyDefinition", Card = AasxPredefinedCardinality.ZeroToMany)] + List PropertyName = new List(); + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfaceDescription/1/0/PropertyDefinition")] + public class CD_PropertyName + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/key", Card = AasxPredefinedCardinality.ZeroToOne)] + string Key; + + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasxPredefinedCardinality.ZeroToOne)] + string Type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasxPredefinedCardinality.ZeroToOne)] + string Title; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasxPredefinedCardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasxPredefinedCardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasxPredefinedCardinality.ZeroToOne)] + string Default; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasxPredefinedCardinality.ZeroToOne)] + string Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Items Items = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#properties", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Properties Properties = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasForm", Card = AasxPredefinedCardinality.One)] + CD_Forms Forms = new CD_Forms(); + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items")] + public class CD_Items + { + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasxPredefinedCardinality.ZeroToOne)] + string Type; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasxPredefinedCardinality.ZeroToOne)] + string Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasxPredefinedCardinality.ZeroToOne)] + string Default; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasxPredefinedCardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasxPredefinedCardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasxPredefinedCardinality.ZeroToOne)] + string Title; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#properties")] + public class CD_Properties + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#propertyName", Card = AasxPredefinedCardinality.ZeroToMany)] + List _propertyName_ = new List(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#propertyName", Card = AasxPredefinedCardinality.ZeroToMany)] + List PropertyName = new List(); + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#propertyName")] + public class CD__propertyName_ + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/key", Card = AasxPredefinedCardinality.ZeroToOne)] + string Key; + + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasxPredefinedCardinality.ZeroToOne)] + string Type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasxPredefinedCardinality.ZeroToOne)] + string Title; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasxPredefinedCardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasxPredefinedCardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasxPredefinedCardinality.ZeroToOne)] + string Default; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasxPredefinedCardinality.ZeroToOne)] + string Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Items Items = null; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasForm")] + public class CD_Forms + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/hypermedia#hasTarget", Card = AasxPredefinedCardinality.One)] + string Href; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/hypermedia#forContentType", Card = AasxPredefinedCardinality.ZeroToOne)] + string ContentType; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasSecurityConfiguration", Card = AasxPredefinedCardinality.One)] + CD_Security Security = new CD_Security(); + + [AasConcept(Cd = "https://www.w3.org/2011/http#methodName", Card = AasxPredefinedCardinality.ZeroToOne)] + string Htv_methodName; + + [AasConcept(Cd = "https://www.w3.org/2011/http#headers", Card = AasxPredefinedCardinality.ZeroToOne)] + CD_Htv_headers Htv_headers = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#Function", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_function; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#Entity", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_entity; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#hasZeroBasedAddressingFlag", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_zeroBasedAddressing; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#pollingTime", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_pollingTime; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_timeout; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#type", Card = AasxPredefinedCardinality.ZeroToOne)] + string Modbus_type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasRetainFlag", Card = AasxPredefinedCardinality.ZeroToOne)] + string Mqv_retain; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#ControlPacket", Card = AasxPredefinedCardinality.ZeroToOne)] + string Mqv_controlPacket; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasxPredefinedCardinality.ZeroToOne)] + string Mqv_qos; + } + + [AasConcept(Cd = "https://www.w3.org/2011/http#headers")] + public class CD_Htv_headers + { + [AasConcept(Cd = "https://www.w3.org/2011/http#headers", Card = AasxPredefinedCardinality.OneToMany)] + List Htv_headers = new List(); + + [AasConcept(Cd = "https://www.w3.org/2011/http#fieldName", Card = AasxPredefinedCardinality.One)] + string Htv_fieldName; + + [AasConcept(Cd = "https://www.w3.org/2011/http#fieldValue", Card = AasxPredefinedCardinality.One)] + string Htv_fieldValue; + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#ActionAffordance")] + public class CD_Actions + { + } + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#EventAffordance")] + public class CD_Events + { + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/ExternalDescriptor")] + public class CD_ExternalDescriptor + { + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel")] + public class CD_AssetInterfacesDescription + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany)] + List InterfaceHTTP = new List(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany)] + List InterfaceMODBUS = new List(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany)] + List InterfaceMQTT = new List(); + } +} + diff --git a/src/AasxPredefinedConcepts/ExportPredefinedConcepts.cs b/src/AasxPredefinedConcepts/ExportPredefinedConcepts.cs index 2a33793b6..194a64721 100644 --- a/src/AasxPredefinedConcepts/ExportPredefinedConcepts.cs +++ b/src/AasxPredefinedConcepts/ExportPredefinedConcepts.cs @@ -7,19 +7,24 @@ This source code is licensed under the Apache License 2.0 (see LICENSE.txt). This source code may use other Open Source software components (see LICENSE.txt). */ -using AasCore.Aas3_0; +using AasxIntegrationBase; using AdminShellNS; using Extensions; using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Linq; using Aas = AasCore.Aas3_0; namespace AasxPredefinedConcepts { + /// + /// Export a text file with a lot of usefuls snippets, which can be used to create + /// source code files for predefined concepts based on a SMT. + /// public static class ExportPredefinedConcepts { - public static void Export(Aas.Environment env, Aas.ISubmodel sm, string fn) + public static void Export(Aas.Environment env, Aas.ISubmodel sm, string fn) { // access if (fn == null || env == null || sm == null || sm.IdShort == null || sm.SubmodelElements == null) @@ -93,7 +98,7 @@ public static void Export(Aas.Environment env, Aas.ISubmodel sm, string fn) // challenge: SM without SMEs var smClone = sm.Copy(); smClone.SubmodelElements = null; - var jsonStr = Jsonization.Serialize.ToJsonObject(smClone) + var jsonStr = Aas.Jsonization.Serialize.ToJsonObject(smClone) .ToJsonString(new System.Text.Json.JsonSerializerOptions() { WriteIndented = true @@ -121,7 +126,7 @@ public static void Export(Aas.Environment env, Aas.ISubmodel sm, string fn) settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); var jsonStr = JsonConvert.SerializeObject(usedCds[k], Formatting.Indented, settings); #else - var jsonStr = Jsonization.Serialize.ToJsonObject(usedCds[k]) + var jsonStr = Aas.Jsonization.Serialize.ToJsonObject(usedCds[k]) .ToJsonString(new System.Text.Json.JsonSerializerOptions() { WriteIndented = true @@ -155,7 +160,16 @@ public static void Export(Aas.Environment env, Aas.ISubmodel sm, string fn) snippets.WriteLine($"this.{k} = bs.RetrieveReferable(\"{k}\");"); snippets.WriteLine(); - } + + // Phase (5) generate look ups + message = "Phase (6) generates attributed C# structures:"; + snippets.WriteLine(message); + snippets.WriteLine(new String('=', message.Length)); + + PredefinedConceptsClassMapper.ExportCSharpClassDefs(env, sm, snippets); + + snippets.WriteLine(); + } } } } diff --git a/src/AasxPredefinedConcepts/PredefinedConceptsClassMapper.cs b/src/AasxPredefinedConcepts/PredefinedConceptsClassMapper.cs new file mode 100644 index 000000000..a737fc861 --- /dev/null +++ b/src/AasxPredefinedConcepts/PredefinedConceptsClassMapper.cs @@ -0,0 +1,449 @@ +/* +Copyright (c) 2018-2023 Festo SE & Co. KG +Author: Michael Hoffmeister + +This source code is licensed under the Apache License 2.0 (see LICENSE.txt). + +This source code may use other Open Source software components (see LICENSE.txt). +*/ + +using AasxIntegrationBase; +using AasxIntegrationBase.AasForms; +using AdminShellNS; +using Extensions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Aas = AasCore.Aas3_0; + +namespace AasxPredefinedConcepts +{ + /// + /// AAS cardinality for predefined concepts + /// + public enum AasxPredefinedCardinality { ZeroToOne = 0, One, ZeroToMany, OneToMany }; + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class)] + public class AasConceptAttribute : Attribute + { + public string Cd { get; set; } + public AasxPredefinedCardinality Card { get; set; } + + public AasConceptAttribute() + { + } + } + + /// + /// This class provides methods to derive a set of C# class definitions from a SMZT definition and + /// to create runtime instances from it based on a concrete SM. + /// + public class PredefinedConceptsClassMapper + { + // + // Export C# classes + // + + private static void ExportCSharpMapperSingleItems( + string indent, Aas.Environment env, Aas.IReferable rf, System.IO.StreamWriter snippets, + bool noEmptyLineFirst = false) + { + // access + if (snippets == null || env == null || rf == null) + return; + + // + // require CD + // + + Aas.IConceptDescription cd = null; + if (rf is Aas.IHasSemantics ihs) + cd = env.FindConceptDescriptionByReference(ihs.SemanticId); + + var cdff = AdminShellUtil.FilterFriendlyName(cd?.IdShort, pascalCase: true); + + var cdRef = cd?.GetCdReference()?.ToStringExtended(format: 2); + + // + // pretty idShort + // + + var idsff = AdminShellUtil.FilterFriendlyName(rf.IdShort, pascalCase: true); + if (idsff.HasContent() != true) + return; + + // + // check Qualifiers/ Extensions + // + + FormMultiplicity card = FormMultiplicity.One; + if (rf is Aas.IQualifiable iqf) + { + var tst = AasFormUtils.GetCardinality(iqf.Qualifiers); + if (tst.HasValue) + card = tst.Value; + } + + var cardSt = card.ToString(); + + // + // lambda for attribute declaration + // + + Action declareLambda = (dt, isScalar, instance) => + { + // empty line ahead + if (!noEmptyLineFirst) + snippets.WriteLine(); + + // write attribute's attribute + if (cdRef?.HasContent() == true) + snippets.WriteLine($"{indent}[AasConcept(Cd = \"{cdRef}\", " + + $"Card = AasxPredefinedCardinality.{cardSt})]"); + + // write attribute itself + if (isScalar) + { + var nullOp = (dt == "string") ? "" : "?"; + + if (card == FormMultiplicity.ZeroToOne) + snippets.WriteLine($"{indent}{dt}{nullOp} {instance};"); + else + if (card == FormMultiplicity.One) + snippets.WriteLine($"{indent}{dt} {instance};"); + else + snippets.WriteLine($"{indent}List<{dt}> {instance} = new List<{dt}>();"); + } + else + { + if (card == FormMultiplicity.ZeroToOne) + snippets.WriteLine($"{indent}{dt} {instance} = null;"); + else + if (card == FormMultiplicity.One) + snippets.WriteLine($"{indent}{dt} {instance} = new {dt}();"); + else + snippets.WriteLine($"{indent}List<{dt}> {instance} = new List<{dt}>();"); + } + }; + + // + // Property + // + + if (rf is Aas.Property prop) + { + var dt = "string"; + switch (prop.ValueType) + { + case Aas.DataTypeDefXsd.Boolean: + dt = "bool"; + break; + + case Aas.DataTypeDefXsd.Byte: + dt = "byte"; + break; + + case Aas.DataTypeDefXsd.Date: + case Aas.DataTypeDefXsd.DateTime: + case Aas.DataTypeDefXsd.Time: + dt = "DateTime"; + break; + + case Aas.DataTypeDefXsd.Float: + dt = "float"; + break; + + case Aas.DataTypeDefXsd.Double: + dt = "double"; + break; + + case Aas.DataTypeDefXsd.Int: + case Aas.DataTypeDefXsd.Integer: + dt = "int"; + break; + + case Aas.DataTypeDefXsd.Long: + dt = "long"; + break; + + case Aas.DataTypeDefXsd.NegativeInteger: + case Aas.DataTypeDefXsd.NonPositiveInteger: + dt = "int"; + break; + + case Aas.DataTypeDefXsd.NonNegativeInteger: + case Aas.DataTypeDefXsd.PositiveInteger: + dt = "unsigned int"; + break; + + case Aas.DataTypeDefXsd.Short: + dt = "short"; + break; + + case Aas.DataTypeDefXsd.UnsignedByte: + dt = "unsigned byte"; + break; + + case Aas.DataTypeDefXsd.UnsignedInt: + dt = "unsigned int"; + break; + + case Aas.DataTypeDefXsd.UnsignedLong: + dt = "usingned long"; + break; + + case Aas.DataTypeDefXsd.UnsignedShort: + dt = "unsigned short"; + break; + } + + declareLambda(dt, true, idsff); + } + + if (( rf is Aas.Submodel + || rf is Aas.SubmodelElementCollection + || rf is Aas.SubmodelElementList) + && cdRef?.HasContent() == true) + { + // in sequence: class first +#if do_not_do + snippets.WriteLine($"{indent}public class {cdff} {{"); + + foreach (var x in rf.DescendOnce()) + if (x is Aas.ISubmodelElement sme) + ExportCSharpMapper("" + indent + " ", env, sme, snippets); + + snippets.WriteLine($"{indent}}}"); +#endif + + declareLambda($"CD_{cdff}", false, idsff); + } + } + + /// + /// The contents of this class are based on one or multiple SMCs (SML..), however + /// the class itself is associated with the associated CD of the SMC (SML..), therefore + /// it is intended to aggregate member definitions. + /// Duplicate members are avoided. Members are found to be duplicate, if IdShort and + /// SemanticId are the same. + /// + private class ExportCSharpClassDef + { + /// + /// The respective SM, SMC, SML .. + /// + public Aas.IReferable Rf = null; + + /// + /// The associated CD. + /// + public Aas.IConceptDescription Cd = null; + + /// + /// Superset of representative memebers. + /// + public List Members = new List(); + + public ExportCSharpClassDef(Aas.Environment env, Aas.IReferable rf) + { + Rf = rf; + if (rf is Aas.IHasSemantics ihs) + Cd = env?.FindConceptDescriptionByReference(ihs.SemanticId); + + if (rf == null) + return; + + foreach (var x in rf.DescendOnce()) + if (x is Aas.ISubmodelElement sme) + Members.Add(sme); + } + + public void EnrichMembersFrom(ExportCSharpClassDef cld) + { + if (cld?.Members == null) + return; + + foreach (var x in cld.Members) + if (x is Aas.ISubmodelElement sme) + { + // check if member with same name and CD is already present + var found = false; + foreach (var em in Members) + if (em?.IdShort?.HasContent() == true + && em.IdShort == sme?.IdShort + && (em.SemanticId?.IsValid() != true + || em.SemanticId?.Matches(sme?.SemanticId, MatchMode.Relaxed) == true)) + found = true; + if (!found) + Members.Add(sme); + } + } + } + + private static void ExportCSharpMapperOnlyClasses( + string indent, Aas.Environment env, Aas.ISubmodel sm, System.IO.StreamWriter snippets) + { + // which is a structual element? + Func isStructRf = (rf) => + (rf is Aas.SubmodelElementCollection + || rf is Aas.SubmodelElementList); + + // list of class definitions (not merged, yet) + var elems = new List(); + foreach (var sme in sm.SubmodelElements?.FindDeep((sme) => isStructRf(sme))) + elems.Add(new ExportCSharpClassDef(env, sme)); + + // list of merged class defs + var distElems = new List(); + foreach (var x in elems.GroupBy((cld) => cld.Cd)) + { + var l = x.ToList(); + for (int i = 1; i < l.Count; i++) + l[0].EnrichMembersFrom(l[i]); + distElems.Add(l[0]); + } + + // add Submodel at last, to be sure it is distinct + distElems.Add(new ExportCSharpClassDef(env, sm)); + // distElems.Reverse(); + + // try to output classed, do not recurse by itself + foreach (var cld in distElems) + { + // gather infos + var cdff = AdminShellUtil.FilterFriendlyName(cld.Cd?.IdShort, pascalCase: true); + var cdRef = cld?.Cd?.GetCdReference()?.ToStringExtended(format: 2); + + // no empty class + if (cdff?.HasContent() != true) + continue; + + // write out class + snippets.WriteLine(); + + if (cdRef?.HasContent() == true) + snippets.WriteLine($"{indent}[AasConcept(Cd = \"{cdRef}\")]"); + + snippets.WriteLine($"{indent}public class CD_{cdff}"); + snippets.WriteLine($"{indent}{{"); + + if (cdff == "Htv_headers") + { + ; + } + + if (cld.Members != null) + { + var noEmptyLineFirst = true; + foreach (var x in cld.Members) + if (x is Aas.ISubmodelElement sme) + { + ExportCSharpMapperSingleItems("" + indent + " ", env, sme, snippets, + noEmptyLineFirst: noEmptyLineFirst); + noEmptyLineFirst = false; + } + } + + + snippets.WriteLine($"{indent}}}"); + } + } + + public static void ExportCSharpClassDefs(Aas.Environment env, Aas.ISubmodel sm, System.IO.StreamWriter snippets) + { + // access + if (snippets == null || env == null || sm == null) + return; + + var head = AdminShellUtil.CleanHereStringWithNewlines( + @" + /* + Copyright (c) 2018-2023 Festo SE & Co. KG + + Author: Michael Hoffmeister + + This source code is licensed under the Apache License 2.0 (see LICENSE.txt). + + This source code may use other Open Source software components (see LICENSE.txt). + + This source code was auto-generated by the AASX Package Explorer. + */ + + using AasxIntegrationBase; + using AdminShellNS; + using Extensions; + using System; + using System.Collections.Generic; + using Aas = AasCore.Aas3_0;"); + snippets.WriteLine(head); + snippets.WriteLine(""); + + snippets.WriteLine($"namespace AasxPredefinedConcepts.{AdminShellUtil.FilterFriendlyName(sm?.IdShort)} {{"); + + ExportCSharpMapperOnlyClasses(" ", env, sm, snippets); + + // ExportCSharpMapperSingleItems(" ", env, sm, snippets); + + snippets.WriteLine($"}}"); + } + + // + // Parse AASX structures + // + + private class ElemAttrInfo + { + public FieldInfo Fi; + public AasConceptAttribute Attr; + } + + private void ParseAasElemFillData(ElemAttrInfo eai, Aas.ISubmodelElement sme) + { + // access + if (eai?.Fi == null || sme == null) + return; + + // straight? + + } + + /// + /// Parse information from the AAS elements (within) root to the + /// attributed class referenced by obj. Reflection dictates the + /// recursion into sub-classes. + /// + public static void ParseAasElemsToObject(Aas.IReferable root, object obj) + { + // access + if (root == null || obj == null) + return; + + // collect information driven by reflection + var eais = new List(); + + // find fields for this object + var t = obj.GetType(); + var l = t.GetFields(BindingFlags.Instance | BindingFlags.Public); + foreach (var f in l) + { + var a = f.GetCustomAttribute(); + if (a != null) + { + eais.Add(new ElemAttrInfo() { Fi = f, Attr = a }); + } + } + + // now try to fill information + foreach (var eai in eais) + { + // try find sme in Rf + foreach (var x in root.DescendOnce()) + if (x is Aas.ISubmodelElement sme) + if (sme?.SemanticId?.MatchesExactlyOneKey(new Aas.Key(Aas.KeyTypes.GlobalReference, eai?.Attr?.Cd)) == true) + ; + } + } + } +} \ No newline at end of file diff --git a/src/AasxWpfControlLibrary/AnyUiWpf.cs b/src/AasxWpfControlLibrary/AnyUiWpf.cs index f18fecc87..cbbc9f8f3 100644 --- a/src/AasxWpfControlLibrary/AnyUiWpf.cs +++ b/src/AasxWpfControlLibrary/AnyUiWpf.cs @@ -1586,8 +1586,8 @@ private UserControl DispatchFlyout(AnyUiDialogueDataBase dialogueData) if (dialogueData is AnyUiDialogueDataChangeElementAttributes ddcea) { - var uc = new ChangeElementAttributesFlyout(); - uc.DiaData = ddcea; + var uc = new ModalPanelFlyout(this); + uc.DiaData = ChangeElementAttributesFlyoutAnyUiFlyout.CreateModelDialogue(ddcea); res = uc; } @@ -1758,7 +1758,16 @@ public override bool StartFlyoverModal(AnyUiDialogueDataBase dialogueData) // start WITHOUT modal FlyoutProvider?.StartFlyover(uc); else + { + // perform modal FlyoutProvider?.StartFlyoverModal(uc); + + // special fix + if (uc is ModalPanelFlyout mpf && mpf.DiaData != dialogueData) + { + dialogueData.Result = mpf.DiaData.Result; + } + } } // now, in case diff --git a/src/AnyUi/AnyUiDialogueDataBase.cs b/src/AnyUi/AnyUiDialogueDataBase.cs index 136836a34..76b0bb96f 100644 --- a/src/AnyUi/AnyUiDialogueDataBase.cs +++ b/src/AnyUi/AnyUiDialogueDataBase.cs @@ -15,6 +15,7 @@ This source code may use other Open Source software components (see LICENSE.txt) using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; using Aas = AasCore.Aas3_0; namespace AnyUi @@ -400,7 +401,18 @@ public enum AttributeEnum { IdShort = 0, Description, ValueText } public string Pattern = "*"; - public AnyUiDialogueDataChangeElementAttributes( + public static string[] HelpLines = new[] + { + "* = all remaining characters of (original) attribute value (OV)", + "? = next single character of OV", + "^,§ = next single character of OV in upper case / lower case", + "^>,§> = all remaining characters of OV in upper case / lower case", + "~ = skip single character of OV", + "< = reverse sequence of remaining characters of OV", + " = use in new attribute value" + }; + + public AnyUiDialogueDataChangeElementAttributes( string caption = "", double? maxWidth = null) : base(caption, maxWidth) diff --git a/src/BlazorExplorer/Pages/Index.razor b/src/BlazorExplorer/Pages/Index.razor index c8e7a76d8..399cb5549 100644 --- a/src/BlazorExplorer/Pages/Index.razor +++ b/src/BlazorExplorer/Pages/Index.razor @@ -80,6 +80,15 @@ DialogueData="evs.DialogueData" /> } + @if (evs.DialogueData is AnyUiDialogueDataChangeElementAttributes ddcea) + { + var outerDd = ChangeElementAttributesFlyoutAnyUiFlyout.CreateModelDialogue(ddcea); + + + } + @if (evs.DialogueData is AnyUiDialogueDataSelectFromList) { PropertyName = new List(); + } + + [AasConcept("https://admin-shell.io/idta/AssetInterfaceDescription/1/0/PropertyDefinition")] + public class CD_PropertyName + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/key", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Key; + + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Title; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasDefinition.Cardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasDefinition.Cardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Default; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items", Card = AasDefinition.Cardinality.ZeroToOne)] + CD_Items Items = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#properties", Card = AasDefinition.Cardinality.ZeroToOne)] + CD_Properties Properties = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasForm", Card = AasDefinition.Cardinality.One)] + CD_Forms Forms = new CD_Forms(); + } + + [AasConcept("https://www.w3.org/2019/wot/json-schema#items")] + public class CD_Items + { + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Type; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Default; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasDefinition.Cardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasDefinition.Cardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Title; + } + + [AasConcept("https://www.w3.org/2019/wot/json-schema#properties")] + public class CD_Properties + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#propertyName", Card = AasDefinition.Cardinality.ZeroToMany)] + List _propertyName_ = new List(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#propertyName", Card = AasDefinition.Cardinality.ZeroToMany)] + List PropertyName = new List(); + } + + [AasConcept("https://www.w3.org/2019/wot/json-schema#propertyName")] + public class CD__propertyName_ + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/key", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Key; + + [AasConcept(Cd = "https://www.w3.org/1999/02/22-rdf-syntax-ns#type", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#title", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Title; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#isObservable", Card = AasDefinition.Cardinality.ZeroToOne)] + bool? Observable; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasDefinition.Cardinality.ZeroToOne)] + int? Const; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Default; + + [AasConcept(Cd = "https://schema.org/unitCode", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Unit; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items", Card = AasDefinition.Cardinality.ZeroToOne)] + CD_Items Items = null; + } + + [AasConcept("https://www.w3.org/2019/wot/td#hasForm")] + public class CD_Forms + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/hypermedia#hasTarget", Card = AasDefinition.Cardinality.One)] + string Href; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/hypermedia#forContentType", Card = AasDefinition.Cardinality.ZeroToOne)] + string? ContentType; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasSecurityConfiguration", Card = AasDefinition.Cardinality.One)] + CD_Security Security = new CD_Security(); + + [AasConcept(Cd = "https://www.w3.org/2011/http#methodName", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Htv_methodName; + + [AasConcept(Cd = "https://www.w3.org/2011/http#headers", Card = AasDefinition.Cardinality.ZeroToOne)] + CD_Htv_headers Htv_headers = null; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#Function", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_function; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#Entity", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_entity; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#hasZeroBasedAddressingFlag", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_zeroBasedAddressing; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#pollingTime", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_pollingTime; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_timeout; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/modbus#type", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Modbus_type; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasRetainFlag", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Mqv_retain; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#ControlPacket", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Mqv_controlPacket; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasDefinition.Cardinality.ZeroToOne)] + string? Mqv_qos; + } + + [AasConcept("https://www.w3.org/2011/http#headers")] + public class CD_Htv_headers + { + [AasConcept(Cd = "https://www.w3.org/2011/http#headers", Card = AasDefinition.Cardinality.OneToMany)] + List Htv_headers = new List(); + + [AasConcept(Cd = "https://www.w3.org/2011/http#fieldName", Card = AasDefinition.Cardinality.One)] + string Htv_fieldName; + + [AasConcept(Cd = "https://www.w3.org/2011/http#fieldValue", Card = AasDefinition.Cardinality.One)] + string Htv_fieldValue; + } + + [AasConcept("https://www.w3.org/2019/wot/td#ActionAffordance")] + public class CD_Actions + { + } + + [AasConcept("https://www.w3.org/2019/wot/td#EventAffordance")] + public class CD_Events + { + } + + [AasConcept("https://admin-shell.io/idta/AssetInterfacesDescription/1/0/ExternalDescriptor")] + public class CD_ExternalDescriptor + { + } + + [AasConcept("https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel")] + public class CD_AssetInterfacesDescription + { + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasDefinition.Cardinality.ZeroToMany)] + List InterfaceHTTP = new List(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasDefinition.Cardinality.ZeroToMany)] + List InterfaceMODBUS = new List(); + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasDefinition.Cardinality.ZeroToMany)] + List InterfaceMQTT = new List(); + } +} +