blob: 5499917fa6f0c34478bfc65eb0c24d408318e877 [file] [log] [blame]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
using AdminShellNS;
/* Copyright (c) 2018-2019 Festo AG & Co. KG <https://www.festo.com/net/de_de/Forms/web/contact_international>, author: Michael Hoffmeister
This software is licensed under the Eclipse Public License - v 2.0 (EPL-2.0) (see https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt).
The browser functionality is under the cefSharp license (see https://raw.githubusercontent.com/cefsharp/CefSharp/master/LICENSE).
The JSON serialization is under the MIT license (see https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md). */
namespace AasxPackageExplorer
{
/// <summary>
/// Interaktionslogik für SelectAasEntityDialogue.xaml
/// </summary>
public partial class SelectEclassEntity : Window
{
private string eclassFullPath = null;
public string ResultIRDI = null;
public AdminShell.ConceptDescription ResultCD = null;
public class SelectItem
{
public string Entity { get; set; }
public string IRDI { get; set; }
public string Info { get; set; }
public XmlNode ContentNode { get; set; }
public SelectItem()
{
Entity = "";
IRDI = "";
Info = "";
ContentNode = null;
}
public SelectItem(string entity, string irdi, string info, XmlNode content)
{
Entity = entity;
IRDI = irdi;
Info = info;
ContentNode = content;
}
}
public SelectEclassEntity(string eclassFullPath = null)
{
InitializeComponent();
this.eclassFullPath = eclassFullPath;
}
private readonly BackgroundWorker worker = new BackgroundWorker();
private class BackgroundArguments
{
public int maxItems = 1000;
public List<string> eclassFiles = new List<string>();
public string searchText = "";
public bool searchInClasses = true;
public bool searchInDatatypes = true;
public bool searchInProperties = true;
public bool searchInUnits = true;
public int numClass = 0;
public int numDatatype = 0;
public int numProperty = 0;
public bool tooMany = false;
public List<SelectItem> items = new List<SelectItem>();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void ButtonSearchStart_Click(object sender, RoutedEventArgs e)
{
if (!worker.IsBusy && eclassFullPath != null)
{
SearchProgress.Value = 0;
EntityList.Items.Clear();
EntityContent.Text = "";
var args = new BackgroundArguments();
args.searchInClasses = this.SearchInClasses.IsChecked == true;
args.searchInDatatypes = this.SearchInDatatypes.IsChecked == true;
args.searchInProperties = this.SearchInProperties.IsChecked == true;
args.searchInUnits = this.SearchInUnits.IsChecked == true;
args.eclassFiles.Clear();
args.eclassFiles.AddRange(System.IO.Directory.GetFiles(eclassFullPath, "*.xml"));
args.searchText = SearchFor.Text.Trim().ToLower();
if (args.searchText.Length < 2)
MessageBox.Show(this, "The search string needs to comprise at least 2 characters in order to limit the amount of search results!", "Info", MessageBoxButton.OK, MessageBoxImage.Exclamation);
else
{
worker.RunWorkerAsync(args);
}
}
}
private void SearchFor_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
e.Handled = true;
// fake mouse click
ButtonSearchStart_Click(null, null);
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
var a = (e.Argument as BackgroundArguments);
if (a == null)
return;
if (a.eclassFiles == null || a.eclassFiles.Count < 1)
return;
double progressPerFile = 1.0 / a.eclassFiles.Count;
for (int fileNdx = 0; fileNdx < a.eclassFiles.Count; fileNdx++)
{
long totalSize = 1 + new System.IO.FileInfo(a.eclassFiles[fileNdx]).Length;
try
{
using (FileStream fileSteam = File.OpenRead(a.eclassFiles[fileNdx]))
{
XmlReaderSettings settings;
settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Document;
int numElems = 0;
using (XmlReader reader = XmlReader.Create(fileSteam, settings))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
string searchForType = null;
if (reader.Name == "ontoml:class" && a.searchInClasses)
{
searchForType = "cls";
a.numClass++;
}
if (reader.Name == "ontoml:datatype" && a.searchInDatatypes)
{
searchForType = "dt";
a.numDatatype++;
}
if (reader.Name == "ontoml:property" && a.searchInProperties)
{
searchForType = "prop";
a.numProperty++;
}
if (reader.Name == "unitsml:Unit" && a.searchInUnits)
{
searchForType = "unit";
a.numProperty++;
}
if (searchForType != null)
{
// always get the XmlDocument (can either read outer xml or the same as a node)
var doc = new XmlDocument();
var node = doc.ReadNode(reader);
// contains the text
if (node.OuterXml.Trim().ToLower().Contains(a.searchText))
{
// get the IRDI
if (node.Attributes != null && node.Attributes["id"] != null)
{
var irdi = node.Attributes["id"].InnerText;
var info = "";
if (searchForType == "prop" && node.HasChildNodes)
{
var n2 = node.SelectSingleNode("preferred_name");
if (n2 != null && n2.HasChildNodes)
foreach (var c2 in n2.ChildNodes)
if (c2 is XmlNode && (c2 as XmlNode).Name == "label")
info = (c2 as XmlNode).InnerText;
}
a.items.Add(new SelectItem(searchForType, irdi, info, node));
// now more than max
if (a.items.Count > a.maxItems)
{
a.tooMany = true;
break;
}
}
}
// count anyway
}
numElems++;
if (numElems % 500 == 0)
{
long currPos = fileSteam.Position;
double frac = Math.Min( 100.0d * progressPerFile * (fileNdx) + (100.0d * currPos) * progressPerFile / totalSize, 100.0);
SearchProgress.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() => this.SearchProgress.Value = frac));
}
}
}
}
}
}
catch { }
}
// set result
e.Result = a;
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
//update ui once worker complete his work
SearchProgress.Value = 100;
// access
var a = (e.Result as BackgroundArguments);
if (a == null)
return;
// may be inform upon too many elements
if (a.tooMany)
MessageBox.Show(this, "Too many search result. Search aborted!", "Search entities", MessageBoxButton.OK, MessageBoxImage.Exclamation);
// sort
a.items.Sort(delegate (SelectItem si1, SelectItem si2)
{
if (si1.Entity != si2.Entity)
return si1.Entity.CompareTo(si2.Entity);
else
return si1.IRDI.CompareTo(si2.IRDI);
});
// re-fill into the UI list
EntityList.Items.Clear();
foreach (var it in a.items)
EntityList.Items.Add(it);
}
private void ButtonSelect_Click(object sender, RoutedEventArgs e)
{
if (FinalizeSelection())
this.DialogResult = true;
}
private void Tree_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (FinalizeSelection())
this.DialogResult = true;
}
private void EntityList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// access
if (EntityContent == null || EntityList == null || EntityList.SelectedItem == null || !(EntityList.SelectedItem is SelectItem))
return;
// set
var si = EntityList.SelectedItem as SelectItem;
if (si.ContentNode != null)
EntityContent.Text = si.ContentNode.OuterXml;
else
EntityContent.Text = "";
}
private bool FinalizeSelection()
{
// get the IRDI
var si = EntityList.SelectedItem as SelectItem;
if (si == null)
return false;
// simply put the IRDI
this.ResultIRDI = si.IRDI;
// special case: property selected
if (si.Entity == "prop")
{
var input = new List<SelectItem>();
input.Add(si);
foreach (SelectItem di in EntityList.Items)
if (di != null && di.Entity == si.Entity && di.IRDI == si.IRDI && si != di)
input.Add(di);
// own function
this.ResultCD = GenerateConceptDescription(input);
}
// ok
return true;
}
private string GetChildInnerText (XmlNode node, string childElemName, string otherwise)
{
if (node == null)
return otherwise;
var n = node.SelectSingleNode(childElemName);
if (n != null)
return n.InnerText;
return otherwise;
}
private void FildChildLangStrings (XmlNode node, string childName, string childChildName, string langCodeAttrib, Action<AdminShell.LangStr> action)
{
if (node == null || action == null)
return;
var n1 = node.SelectSingleNode(childName);
if (n1 != null)
{
var nl = n1.SelectNodes(childChildName);
foreach (XmlNode ni in nl)
if (ni.Attributes != null && ni.Attributes[langCodeAttrib] != null)
{
var ls = new AdminShell.LangStr();
ls.lang = ni.Attributes["language_code"].InnerText;
ls.str = ni.InnerText;
action(ls);
}
}
}
private AdminShell.ConceptDescription GenerateConceptDescription (List<SelectItem> input)
{
// access
if (input == null || input.Count < 1)
return null;
// new cd
var res = new AdminShell.ConceptDescription();
var ds = new AdminShell.DataSpecificationIEC61360();
res.embeddedDataSpecification.dataSpecificationContent.dataSpecificationIEC61360 = ds;
// over all, first is significant
for (int i=0; i<input.Count; i++)
{
var node = input[i].ContentNode;
if (node == null)
continue;
XmlNode n1;
// first is significant
if (i == 0)
{
res.identification.idType = "IRDI";
res.identification.id = input[i].IRDI;
res.AddIsCaseOf(AdminShell.Reference.CreateIrdiReference(input[i].IRDI));
res.administration = new AdminShell.Administration();
n1 = node.SelectSingleNode("revision");
if (n1 != null)
res.administration.revision = "" + n1.InnerText;
FildChildLangStrings(node, "short_name", "label", "language_code", (ls) =>
{
ds.shortName = ls.str;
res.idShort = ls.str;
});
}
// all have language texts
FildChildLangStrings(node, "preferred_name", "label", "language_code", (ls) =>
{
if (ds.preferredName == null)
ds.preferredName = new AdminShell.LangStringIEC61360();
ds.preferredName.langString.Add(ls);
});
FildChildLangStrings(node, "definition", "text", "language_code", (ls) =>
{
if (ds.definition == null)
ds.definition = new AdminShell.LangStringIEC61360();
ds.definition.langString.Add(ls);
});
}
// ok
return res;
}
}
}