From: Tuukka Lehtonen Date: Fri, 16 Jun 2017 07:43:04 +0000 (+0300) Subject: Merge "Revert "Default property editing restores assertions"" X-Git-Tag: v1.31.0~310 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=6573b29e111ea03c3fa88bf1565d47d0fc4faabd;hp=1aa531775d5221775a583fb13f35332dfff8aae8 Merge "Revert "Default property editing restores assertions"" --- diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java index b1e5b8ec4..0bfc3b1b1 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java @@ -221,5 +221,72 @@ public final class URIUtil { public static String decodeIdentifier(String str) { return decode(str.getBytes(), (byte) '$', true); } - + + /** + * Escape any of the following characters: <>:"/\|?* with %nn. + * + * @param str a file name, not a full file path + * @return original string or escaped file name if encoding is needed + */ + public static String encodeFilename2(String str) { + return encodeFilename2(str, '%'); + } + + private static String encodeFilename2(String str, char escapeChar) { + // First calculate the length + int originalLength = str.length(); + int length = originalLength; + for (int i = 0; i < originalLength; ++i) { + char c = str.charAt(i); + if (c < 128 && fileNameEncodeTable[(int) c] == -1) + length += 2; + } + + if (length == originalLength) + return str; + + char[] result = new char[length]; + int pos = 0; + for (int i = 0; i < originalLength; ++i) { + char c = str.charAt(i); + int ic = c; + if (c >= 128) { + // Never escape any non-ASCII characters. Those should work. + result[pos++] = c; + } else { + int ec = fileNameEncodeTable[ic]; + if (ec >= 0) { + result[pos++] = (char) ec; + } else { + result[pos++] = escapeChar; + result[pos++] = Character.forDigit(ic >> 4, 16); + result[pos++] = Character.forDigit(ic & 15, 16); + } + } + } + return new String(result); + } + + static final int[] fileNameEncodeTable = new int[128]; // for UTF-16 non-bijection filenames + + static { + for (int i = 0; i < fileNameEncodeTable.length; ++i) { + if (i < 32) { + // Control characters are all in need of escapes + fileNameEncodeTable[i] = -1; + } else { + switch ((char) i) { + // Denied characters in windows file names + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + case '<': case '>': case ':': case '"': case '/': case '\\': case '|': case '?': case '*': + fileNameEncodeTable[i] = -1; + break; + default: + fileNameEncodeTable[i] = i; + break; + } + } + } + } + } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java index 08dd63ce0..198ee41b7 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java @@ -1379,11 +1379,12 @@ public class Layer0Utils { } - public static String prettyPrintResource(ReadGraph graph, Resource resource) throws Exception { + public static String prettyPrintResource(ReadGraph graph, Resource resource, boolean ignoreIdentifiers) throws Exception { TransferableGraphSource source = makeTGSource(graph, resource); TransferableGraph1 tg = TransferableGraphs.create(graph, source); GraphRefactoringUtils.fixOntologyExport(tg); - return PrettyPrintTG.print(tg); + System.out.println("Printing resoure " + graph.getURI(resource)); + return PrettyPrintTG.print(tg, ignoreIdentifiers); } } diff --git a/bundles/org.simantics.graph.db/src/org/simantics/graph/db/StreamingTransferableGraphImportProcess.java b/bundles/org.simantics.graph.db/src/org/simantics/graph/db/StreamingTransferableGraphImportProcess.java index 78c369f96..9a8196354 100644 --- a/bundles/org.simantics.graph.db/src/org/simantics/graph/db/StreamingTransferableGraphImportProcess.java +++ b/bundles/org.simantics.graph.db/src/org/simantics/graph/db/StreamingTransferableGraphImportProcess.java @@ -163,8 +163,8 @@ public class StreamingTransferableGraphImportProcess implements TransferableGrap void addMissing(int handleIndex, String external) { allMissingExternals.put(external, handleIndex); Set removals = new HashSet<>(); - for(String ext : missingExternals) if(ext.startsWith(external)) return; - for(String ext : missingExternals) if(external.startsWith(ext)) removals.add(ext); + for(String ext : missingExternals) if(ext.startsWith(external + "/")) return; + for(String ext : missingExternals) if(external.startsWith(ext + "/")) removals.add(ext); missingExternals.removeAll(removals); missingExternals.add(external); } @@ -210,18 +210,18 @@ public class StreamingTransferableGraphImportProcess implements TransferableGrap TransientCacheAsyncListener.instance()); Resource child = childMap.get(def.name); if(child == null) { - addMissing(identity.resource, graph.getURI(parent) + "/" + def.name); + addMissing(identity.resource, graph.getURI(parent) + "/" + URIStringUtils.escape(def.name)); } else { handles[identity.resource] = builder.handle(child); } } else { - addMissing(identity.resource, TransferableGraphUtils.getURI(resourceCount, identityMap, def.parent) + "/" + def.name); + addMissing(identity.resource, TransferableGraphUtils.getURI(resourceCount, identityMap, def.parent) + "/" + URIStringUtils.escape(def.name)); } } } } else if(definition instanceof Internal) { - String uri = TransferableGraphUtils.getTrueURI(resourceCount, identityMap, identity.resource); + String uri = TransferableGraphUtils.getURI(resourceCount, identityMap, identity.resource); Resource existing = graph.getPossibleResource(uri); if(existing != null) { existingInternalMap.put(identity.resource, existing); @@ -339,6 +339,10 @@ public class StreamingTransferableGraphImportProcess implements TransferableGrap Collections.sort(missing); for(String uri : missing) { String[] parts = URIStringUtils.splitURI(uri); + // URIStringUtils.splitURI returns root URI in non-standard format, so fix it manually as a workaround + if (parts[0].equals("http://")) { + parts[0] = "http:/"; + } Resource parent = resolvedParents.get(parts[0]); // TODO: proper exception message @@ -351,7 +355,7 @@ public class StreamingTransferableGraphImportProcess implements TransferableGrap Resource nameResource = graph.newResource(); graph.claim(nameResource, InstanceOf, null, String); - graph.claimValue(nameResource, parts[1], WriteBindings.STRING); + graph.claimValue(nameResource, URIStringUtils.unescape(parts[1]), WriteBindings.STRING); graph.claim(childResource, HasName, NameOf, nameResource); graph.claim(parent, ConsistsOf, PartOf, childResource); diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java b/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java index ea449417d..1c567b1e2 100644 --- a/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java +++ b/bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java @@ -48,7 +48,7 @@ public class FixExportedOntology { Path input = Paths.get(args[0]); Path output1 = input.getParent().resolve("graph.tg"); TransferableGraph1 tg = convertExportedSharedOntologyIntoBundleOntology(input, output1); - String listing = PrettyPrintTG.print(tg); + String listing = PrettyPrintTG.print(tg, false); Path output2 = Paths.get(args[0].substring(0, args[0].length() - ".sharedLibrary".length()) + ".pgraph"); Files.write(output2, listing.getBytes(),StandardOpenOption.CREATE); } else { diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/representation/PrettyPrintTG.java b/bundles/org.simantics.graph/src/org/simantics/graph/representation/PrettyPrintTG.java index bb776d5df..0a0a86f0b 100644 --- a/bundles/org.simantics.graph/src/org/simantics/graph/representation/PrettyPrintTG.java +++ b/bundles/org.simantics.graph/src/org/simantics/graph/representation/PrettyPrintTG.java @@ -10,14 +10,19 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.simantics.databoard.Bindings; import org.simantics.databoard.binding.Binding; @@ -30,6 +35,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.trove.list.array.TIntArrayList; +import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.procedure.TIntIntProcedure; @@ -42,290 +48,378 @@ import gnu.trove.set.hash.TLongHashSet; public class PrettyPrintTG { private static final Logger LOGGER = LoggerFactory.getLogger(PrettyPrintTG.class); - - int blankCounter = 0; - MessageDigest m; - - private final Pattern versionExtractPattern = Pattern.compile("^.*-(\\d+\\.\\d+)"); - - final StringBuilder output; - final Map ontologies = new HashMap<>(knownOntologies); - final Set referencedOntologies = new TreeSet<>(); - - static class ResourceInfo { - final boolean hasURI; - final String name; - final int resource; - boolean newResource = false; - - int parent; - - boolean inlined = false; - - // -1 = no owner, -2 = multiple owners - - // Set ownedBy - Set ownedBy = new HashSet<>(); - - // A Map containing information about resource that this resource owns and what are the predicates for forming this ownership - TIntIntHashMap ownedResourcesWithPredicates = new TIntIntHashMap(); - -// int owner = -1; -// int ownerPredicate = 0; - String aliasURI = null; - TIntArrayList owned = new TIntArrayList(); - //TIntObjectHashMap statements = new TIntObjectHashMap(); - public ResourceInfo(boolean hasURI, String name, int resource, int parent) { - this.hasURI = hasURI; - this.name = name; - this.resource = resource; - this.parent = parent; - } - - @Override - public String toString() { - return name + (aliasURI != null ? " = <" + aliasURI + ">" : ""); - } - } - - public PrettyPrintTG(StringBuilder b) throws NoSuchAlgorithmException { - output = b; - m = MessageDigest.getInstance("SHA-256"); - } - - public PrettyPrintTG() throws NoSuchAlgorithmException { - this(new StringBuilder()); - } - - TIntObjectHashMap infos = new TIntObjectHashMap<>(); - - String tgNodeName(String name) { - if(name.contains(" ")) return "\"" + name + "\""; - else return name; - } - - ResourceInfo recurseURI(TransferableGraph1 graph, Identity parent, String parentName, int parentId) { - String name = parentName + "." + tgNodeName(TransferableGraphUtils.getName(parent)); - ResourceInfo info = new ResourceInfo(true, name, parent.resource, parentId); - infos.put(parent.resource, info); - for(Identity child : TransferableGraphUtils.getChildren(graph, parent)) { - recurseURI(graph, child, name, info.resource); - } - return info; - } - - void discoverBlank(TransferableGraph1 graph, int resource, TIntArrayList todo) throws Exception { - TIntArrayList statements = TransferableGraphUtils.getStatements(graph, resource); - for(int i=0;i blankRewrites = new HashMap<>(); + MessageDigest m; + + private final Pattern versionExtractPattern = Pattern.compile("^.*-(\\d+\\.\\d+)"); + + final StringBuilder output; + final Map ontologies = new HashMap<>(knownOntologies); + final Set referencedOntologies = new TreeSet<>(); + + private boolean ignoreIdentifiers; + + static class ResourceInfo { + final boolean hasURI; + String name; + final int resource; + boolean newResource = false; + + int parent; + + boolean inlined = false; + + // -1 = no owner, -2 = multiple owners + + // Set ownedBy + Set ownedBy = new HashSet<>(); + + // A Map containing information about resource that + // this resource owns and what are the predicates for forming this + // ownership + TIntIntHashMap ownedResourcesWithPredicates = new TIntIntHashMap(); + + // int owner = -1; + // int ownerPredicate = 0; + String aliasURI = null; + TIntArrayList owned = new TIntArrayList(); + + // TIntObjectHashMap statements = new + // TIntObjectHashMap(); + public ResourceInfo(boolean hasURI, String name, int resource, int parent) { + this.hasURI = hasURI; + this.name = name; + this.resource = resource; + this.parent = parent; + } + + @Override + public String toString() { + return name + (aliasURI != null ? " = <" + aliasURI + ">" : ""); + } + } + + public PrettyPrintTG(StringBuilder b, boolean ignoreIdentifiers) throws NoSuchAlgorithmException { + output = b; + m = MessageDigest.getInstance("SHA-256"); + this.ignoreIdentifiers = ignoreIdentifiers; + } + + public PrettyPrintTG() throws NoSuchAlgorithmException { + this(new StringBuilder(), false); + } + + TreeMap orderedInfos = new TreeMap<>(); + TIntObjectHashMap infos = new TIntObjectHashMap<>(); + + String tgNodeName(String name) { + if (name.contains(" ")) + return "\"" + name + "\""; + else + return name; + } + + ResourceInfo recurseURI(TransferableGraph1 graph, Identity parent, String parentName, int parentId) { + String name = parentName + "." + tgNodeName(TransferableGraphUtils.getName(parent)); + ResourceInfo info = new ResourceInfo(true, name, parent.resource, parentId); + orderedInfos.put(name, info); + // infos.put(parent.resource, info); + for (Identity child : TransferableGraphUtils.getChildren(graph, parent)) { + recurseURI(graph, child, name, info.resource); + } + return info; + } + + private TreeMap> sortByPredicateUniqueStatements(TransferableGraph1 graph, int resource) { + TreeMap> results = new TreeMap<>(); + TIntArrayList statements = TransferableGraphUtils.getStatements(graph, resource); + for (int i = 0; i < statements.size(); i += 2) { + int predicate = statements.get(i); + String predicateURI = TransferableGraphUtils.getURI(graph, predicate); + TreeSet objects = results.get(predicateURI); + if (objects == null) { + objects = new TreeSet<>(); + } + objects.add(statements.get(i + 1)); + results.put(predicateURI, objects); + } + return results; + } + + void discoverBlank(TransferableGraph1 graph, int resource, TIntArrayList todo) throws Exception { + // TIntArrayList statements = + // TransferableGraphUtils.getStatements(graph, resource); + // for(int i=0;i objects : sortByPredicateUniqueStatements(graph, resource).values()) { + for (int object : objects) { + // int object = statements.get(i+1); + Identity objectId = TransferableGraphUtils.getIdentity(graph, object); + if (objectId != null) { + if (objectId.definition instanceof External) + continue; + } + Value value = TransferableGraphUtils.findValue(graph, object); + if (value != null) { + infos.put(object, new ResourceInfo(false, printValue(value), object, resource)); + continue; + } + ResourceInfo existing = infos.get(object); + if (existing == null) { + + existing = new ResourceInfo(false, "blank" + blankCounter++, object, resource); + + // System.out.println("created blank" + blankCounter + " + // with object " + object + " resource " + resource); + infos.put(object, existing); + todo.add(object); + } + } + } + } + + private String makeHash(byte[] data) { + m.reset(); + m.update(data, 0, data.length); + return new BigInteger(1, m.digest()).toString(16); + } + + void discoverOwners(TransferableGraph1 graph, ResourceInfo info) { + log("Discovering owners for {}", info); + int resource = info.resource; + TIntArrayList statements = TransferableGraphUtils.getStatements(graph, resource); + for (int i = 0; i < statements.size(); i += 2) { + int predicate = statements.get(i); + int object = statements.get(i + 1); + ResourceInfo existing = infos.get(object); + if (existing != null) { // Add all owners here for now and resolve the best owner later - existing.ownedResourcesWithPredicates.put(resource, predicate); - // Check if predicate is inverse, this just resolves all predicates to be inverse with ending "Inverse".. - String predicateUri = rewritePredicateURI(graph, predicate); - if (!predicateUri.endsWith("Inverse")) { - existing.ownedBy.add(info); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(" " + existing + " owns " + info + " with " + predicateUri); - } - } - } - } - } + + // Check if predicate is inverse, this just resolves all + // predicates to be inverse with ending "Inverse".. + String predicateUri = rewritePredicateURI(graph, predicate); + if (!predicateUri.endsWith("Inverse") && !predicateUri.endsWith("Of")) { + existing.ownedResourcesWithPredicates.put(resource, predicate); + // if (predicateUri.endsWith("Of")) { + // System.out.println("asd"); + // } else { + existing.ownedBy.add(info); + log(" {} owns {} with {}", existing, info, predicateUri); + // } + } else { + // System.out.println("asd"); + } + } + } + } DataValueRepository repo = new DataValueRepository(); DataValuePrinter printer = new DataValuePrinter(null, repo); - + String printValue(Value value) throws Exception { StringBuilder sb = new StringBuilder(); printer.setFormat(PrintFormat.SINGLE_LINE); printer.setOutput(sb); - + Variant variant = value.value; printer.print(variant.getBinding(), variant.getValue()); String formattedOutput = sb.toString(); if (formattedOutput.length() > 100) { - // Ok, value too long, lets calculate a hash for it and store first 100 chars as comment - byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue()); - m.reset(); - m.update(data, 0, data.length); - String hash = "\"" + new BigInteger(1, m.digest()).toString(16) + "\""; - return hash + " // " + formattedOutput.substring(0, 100) + ".."; + // Ok, value too long, lets calculate a hash for it and store first + // 100 chars as comment + byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue()); + m.reset(); + m.update(data, 0, data.length); + String hash = "\"" + new BigInteger(1, m.digest()).toString(16) + "\""; + return hash + " // " + formattedOutput.substring(0, 100) + ".."; } else { return formattedOutput; } -// -// Variant variant = value.value; -// Datatype dt = variant.getBinding().type(); -// if (Datatypes.STRING.equals(dt)) { -// String s = (String) variant.getValue(Bindings.STRING); -// if (s.contains("\n")) { -// return "\"\"\"" + s + "\"\"\""; -// } else { -// return "\"" + s + "\""; -// } -// } else if (Datatypes.BOOLEAN.equals(dt)) { -// Boolean i = (Boolean) variant.getValue(Bindings.BOOLEAN); -// return i ? "true" : "false"; -// } else if (Datatypes.INTEGER.equals(dt)) { -// Integer i = (Integer) variant.getValue(Bindings.INTEGER); -// return i.toString(); -// } else if (Datatypes.LONG.equals(dt)) { -// Long i = (Long) variant.getValue(Bindings.LONG); -// return i.toString(); -// } else if (Datatypes.DOUBLE.equals(dt)) { -// Double d = (Double) variant.getValue(); -// return d.toString(); -// } else if (Datatypes.FLOAT.equals(dt)) { -// Float f = (Float) variant.getValue(); -// return f.toString(); -// } else if (Datatypes.STRING_ARRAY.equals(dt)) { -// return Arrays.toString((String []) variant.getValue()); -// } else if (Datatypes.BOOLEAN_ARRAY.equals(dt)) { -// return Arrays.toString((boolean []) variant.getValue()); -// } else if (Datatypes.INTEGER_ARRAY.equals(dt)) { -// return Arrays.toString((int []) variant.getValue()); -// } else if (Datatypes.LONG_ARRAY.equals(dt)) { -// return Arrays.toString((long []) variant.getValue()); -// } else if (Datatypes.DOUBLE_ARRAY.equals(dt)) { -// return Arrays.toString((double []) variant.getValue()); -// } else if (Datatypes.FLOAT_ARRAY.equals(dt)) { -// return Arrays.toString((float []) variant.getValue()); -// } else if (Datatypes.BYTE_ARRAY.equals(dt)) { -// return Arrays.toString((byte []) variant.getValue()); -//// } else if (dt instanceof ArrayType) { -//// return Arrays.toString((Object []) variant.getValue()); -// } else { -// byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue()); -// m.reset(); -// m.update(data, 0, data.length); -// return "\"" + new BigInteger(1, m.digest()).toString(16) + "\""; -// } + // + // Variant variant = value.value; + // Datatype dt = variant.getBinding().type(); + // if (Datatypes.STRING.equals(dt)) { + // String s = (String) variant.getValue(Bindings.STRING); + // if (s.contains("\n")) { + // return "\"\"\"" + s + "\"\"\""; + // } else { + // return "\"" + s + "\""; + // } + // } else if (Datatypes.BOOLEAN.equals(dt)) { + // Boolean i = (Boolean) variant.getValue(Bindings.BOOLEAN); + // return i ? "true" : "false"; + // } else if (Datatypes.INTEGER.equals(dt)) { + // Integer i = (Integer) variant.getValue(Bindings.INTEGER); + // return i.toString(); + // } else if (Datatypes.LONG.equals(dt)) { + // Long i = (Long) variant.getValue(Bindings.LONG); + // return i.toString(); + // } else if (Datatypes.DOUBLE.equals(dt)) { + // Double d = (Double) variant.getValue(); + // return d.toString(); + // } else if (Datatypes.FLOAT.equals(dt)) { + // Float f = (Float) variant.getValue(); + // return f.toString(); + // } else if (Datatypes.STRING_ARRAY.equals(dt)) { + // return Arrays.toString((String []) variant.getValue()); + // } else if (Datatypes.BOOLEAN_ARRAY.equals(dt)) { + // return Arrays.toString((boolean []) variant.getValue()); + // } else if (Datatypes.INTEGER_ARRAY.equals(dt)) { + // return Arrays.toString((int []) variant.getValue()); + // } else if (Datatypes.LONG_ARRAY.equals(dt)) { + // return Arrays.toString((long []) variant.getValue()); + // } else if (Datatypes.DOUBLE_ARRAY.equals(dt)) { + // return Arrays.toString((double []) variant.getValue()); + // } else if (Datatypes.FLOAT_ARRAY.equals(dt)) { + // return Arrays.toString((float []) variant.getValue()); + // } else if (Datatypes.BYTE_ARRAY.equals(dt)) { + // return Arrays.toString((byte []) variant.getValue()); + //// } else if (dt instanceof ArrayType) { + //// return Arrays.toString((Object []) variant.getValue()); + // } else { + // byte[] data = + // Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue()); + // m.reset(); + // m.update(data, 0, data.length); + // return "\"" + new BigInteger(1, m.digest()).toString(16) + "\""; + // } + + } + + // void fixInstanceOf(TransferableGraph1 graph, ResourceInfo info) { + // Identity id = getIdentity(graph, info.resource); + // if(id == null) return; + // if(id.definition instanceof Internal) { + // Identity instanceOf = findExternal(graph, + // "http://www.simantics.org/Layer0-1.1/InstanceOf"); + // Identity library = findExternal(graph, + // "http://www.simantics.org/Layer0-1.1/Library"); + // info.statements.add(instanceOf.resource); + // info.statements.add(library.resource); + // } + // } + + public static String getExternalURI(TransferableGraph1 tg, External ext) { + String name = ext.name; + if (name.contains(" ")) + name = name.replace(" ", "_").replaceAll("@", "_");// name = "\"" + + // name + "\""; + int parentId = ext.parent; + // if(parentId == 0) return ext.name; + // else { + Identity id = TransferableGraphUtils.getIdentity(tg, parentId); + if (id.definition instanceof External) { + return getExternalURI(tg, (External) id.definition) + "/" + name; + } else if (id.definition instanceof Root) { + Root root = (Root) id.definition; + return "http:/" + root.name + "/" + name; + } else { + return null; + } + // } + } + + public static String getExternalURI(TransferableGraph1 tg, int resource) { + Identity id = TransferableGraphUtils.getIdentity(tg, resource); + if (id == null) + return null; + if (id.definition instanceof External) { + External ext = (External) id.definition; + return getExternalURI(tg, ext); + } + return null; + } + + String rewritePredicateURI(TransferableGraph1 graph, int predicate) { + + String uri = getExternalURI(graph, predicate); + if (uri == null) { + ResourceInfo info = infos.get(predicate); + if (info != null) + return info.name; + return "_"; + } + + for (String ontology : ontologies.keySet()) { + if (uri.contains(ontology)) { + String key = ontologies.get(ontology); + uri = uri.replace(ontology, key); + referencedOntologies.add(ontology); + } + } + + uri = uri.replace("/", "."); + + return uri; + + } + + static void indent(StringBuilder output, int indent) { + for (int i = 0; i < indent; i++) + output.append(" "); + } + + String printBlank(TransferableGraph1 graph, String predicateURI2, ResourceInfo info, int indent) { + + if (info.hasURI) + return null; + + StringBuilder output = new StringBuilder(); + + String infoName = info.name; + if (infoName.startsWith("blank")) { + infoName = getBlankRewrite(infoName); + } + if (ignoreIdentifiers) { + if (predicateURI2.contains("L0.identifier")) { + // Do nothing + } else { + indent(output, indent); + output.append(predicateURI2 + " " + infoName + "\n"); + } + } else { + indent(output, indent); + output.append(predicateURI2 + " " + infoName + "\n"); + } + + if (info.ownedResourcesWithPredicates.isEmpty()) { + if (DEBUG) + System.out.print("printBlank"); + String uri = printURI(graph, info, false, indent, false); + if (uri != null) + output.append(uri); + } + // if(info.owner < 0) { + // printURI(graph, info, false, indent); + // } + return output.toString(); } - // void fixInstanceOf(TransferableGraph1 graph, ResourceInfo info) { - // Identity id = getIdentity(graph, info.resource); - // if(id == null) return; - // if(id.definition instanceof Internal) { - // Identity instanceOf = findExternal(graph, "http://www.simantics.org/Layer0-1.1/InstanceOf"); - // Identity library = findExternal(graph, "http://www.simantics.org/Layer0-1.1/Library"); - // info.statements.add(instanceOf.resource); - // info.statements.add(library.resource); - // } - // } - - public static String getExternalURI(TransferableGraph1 tg, External ext) { - String name = ext.name; - if(name.contains(" ")) name = name.replace(" ", "_").replaceAll("@", "_");//name = "\"" + name + "\""; - int parentId = ext.parent; - //if(parentId == 0) return ext.name; - // else { - Identity id = TransferableGraphUtils.getIdentity(tg, parentId); - if(id.definition instanceof External) { - return getExternalURI(tg, (External)id.definition) + "/" + name; - } else if(id.definition instanceof Root) { - Root root = (Root)id.definition; - return "http:/" + root.name + "/" + name; - } else { - return null; - } - // } - } - - public static String getExternalURI(TransferableGraph1 tg, int resource) { - Identity id = TransferableGraphUtils.getIdentity(tg, resource); - if(id == null) return null; - if(id.definition instanceof External) { - External ext = (External)id.definition; - return getExternalURI(tg, ext); - } - return null; - } - - String rewritePredicateURI(TransferableGraph1 graph, int predicate) { - - String uri = getExternalURI(graph, predicate); - if(uri == null) { - ResourceInfo info = infos.get(predicate); - if(info != null) return info.name; - return "_"; - } - - for(String ontology : ontologies.keySet()) { - if(uri.contains(ontology)) { - String key = ontologies.get(ontology); - uri = uri.replace(ontology, key); - referencedOntologies.add(ontology); - } - } - - uri = uri.replace("/", "."); - - return uri; - - } - - static void indent(StringBuilder output, int indent) { - for(int i=0;i> statements, String predicate, ResourceInfo objectInfo, int indent) { + private String getBlankRewrite(String infoName) { + String rewrite = blankRewrites.get(infoName); + if (rewrite == null) { + rewrite = "rblank" + newBlankCounter++; + if (DEBUG) + System.out.println("rewrote " + infoName + " to " + rewrite); + blankRewrites.put(infoName, rewrite); + } + return rewrite; + // return infoName; + } + + static long longStm(int predicate, int object) { + return ((predicate & 0xffffffffL) << 32) | (object & 0xffffffffL); + } + + private void addInlineStatement(TransferableGraph1 graph, Map> statements, String predicate, + ResourceInfo objectInfo, int indent) { Set objects = statements.get(predicate); - if(objects == null) { + if (objects == null) { objects = new TreeSet<>(); statements.put(predicate, objects); } @@ -338,260 +432,331 @@ public class PrettyPrintTG { objectInfo.inlined = true; } - - void addStatement(Map> statements, String predicate, String object) { - // TODO: fix this - if (predicate.endsWith("Inverse")) - return; - Set objects = statements.get(predicate); - if(objects == null) { - objects = new TreeSet<>(); - statements.put(predicate, objects); - } - objects.add(object); - } - - String printURI(TransferableGraph1 graph, ResourceInfo info, boolean requireURI, int indent, boolean inline) { - - if(requireURI && !info.hasURI) - return null; - - // Check if this ResourceInfo is already inlined with some other ResourceInfo - if (info.inlined) - return null; - - Map> statements = new TreeMap<>(); - Identity consistsOf = TransferableGraphUtils.findExternal(graph, "http://www.simantics.org/Layer0-1.1/ConsistsOf"); - TLongHashSet processed = new TLongHashSet(); - for(int i=0;i debug = new HashSet<>(); - info.ownedResourcesWithPredicates.forEachEntry(new TIntIntProcedure() { - - @Override - public boolean execute(int owner, int predicate) { - ResourceInfo ownerInfo = infos.get(owner); - debug.add(ownerInfo); -// ResourceInfo predicateInfo = infos.get(predicate); -// debug.add(predicateInfo); - return true; + void addStatement(Map> statements, String predicate, String object) { + // TODO: fix this + if (predicate.endsWith("Inverse")) + return; + Set objects = statements.get(predicate); + if (objects == null) { + objects = new TreeSet<>(); + statements.put(predicate, objects); + } + objects.add(object); + } + + String printURI(TransferableGraph1 graph, ResourceInfo info, boolean requireURI, int indent, boolean inline) { + + if (requireURI && !info.hasURI) + return null; + + // Check if this ResourceInfo is already inlined with some other + // ResourceInfo + if (info.inlined) + return null; + + Map> statements = new TreeMap<>(); + Identity consistsOf = TransferableGraphUtils.findExternal(graph, + "http://www.simantics.org/Layer0-1.1/ConsistsOf"); + // Identity partOf = TransferableGraphUtils.findExternal(graph, + // "http://www.simantics.org/Layer0-1.1/PartOf"); + TLongHashSet processed = new TLongHashSet(); + if (DEBUG) + System.out.println("info.owned.size " + info.owned.size() + info.owned); + for (int i = 0; i < info.owned.size(); i += 2) { + int predicate = info.owned.get(i); + int object = info.owned.get(i + 1); + long stmId = longStm(predicate, object); + if (DEBUG) + System.out.println( + " " + stmId + " is already processed as it is owned (" + predicate + " " + object + ")"); + processed.add(stmId); + } + + TreeMap predicateURIs = new TreeMap<>(); + + TIntArrayList rawStatements = TransferableGraphUtils.getStatements(graph, info.resource); + if (DEBUG) + System.out.println( + "rawStatements size for " + info.name + " : " + rawStatements.size() + " " + rawStatements); + for (int i = 0; i < rawStatements.size(); i += 2) { + int predicate = rawStatements.get(i); + int object = rawStatements.get(i + 1); + long stmId = longStm(predicate, object); + if (!processed.add(stmId)) { + if (DEBUG) + System.out.println(" " + stmId + " is already processed (" + (predicate & 0xffffffffL) + " " + + (object & 0xffffffffL) + ")"); + continue; } - }); - - StringBuilder output = new StringBuilder(); - - if(indent == 0 || inline) { - if("ROOT".equals(info.name)) { - output.append("ROOT="); - } else if (info.aliasURI != null) { - output.append(info.name + " = <" + info.aliasURI + ">"); - } else { - if (inline) - System.out.println("asdasd"); - output.append(inline ? "_" : info.name); - } - Set instanceOfs = statements.get("L0.InstanceOf"); - if(instanceOfs != null) { - for(String instanceOf : instanceOfs) { - output.append(" : " + instanceOf); - } - } - Set subrelationOfs = statements.get("L0.SubrelationOf"); - if(subrelationOfs != null) { - for(String subrelationOf : subrelationOfs) { - output.append(" inherits = statements.get("L0.Inherits"); - if(inherits != null) { - for(String inherit : inherits) { - output.append(" > entry : statements.entrySet()) { - String predicate = entry.getKey(); - if("L0.InstanceOf".equals(predicate)) continue; - if("L0.SubrelationOf".equals(predicate)) continue; - if("L0.Inherits".equals(predicate)) continue; - if("L0.PartOf".equals(predicate)) continue; - Set objects = entry.getValue(); - indent(output, indent+1); - if(objects.size() == 1) { - output.append(predicate + " " + objects.iterator().next() + "\n"); - } else{ - output.append(predicate + "\n"); - for(String object : objects) { - indent(output, indent+1); - output.append(" " + object + "\n"); - } - } - } - - for(int i=0;i entry : predicateURIs.entrySet()) { + String predicateURI = entry.getKey(); + int object = entry.getValue(); + + ResourceInfo objectInfo = infos.get(object); + if (objectInfo == null) { + String objectURI = rewritePredicateURI(graph, object); + if (DEBUG) + System.out.println(" adding statement " + predicateURI + " " + objectURI); + addStatement(statements, predicateURI, objectURI); + } else if (objectInfo.ownedBy.size() == 1 && objectInfo.ownedBy.contains(info)) { + // inline printing with _ + if (DEBUG) + System.out.println(" adding inline statement " + predicateURI + " " + objectInfo.name); + addInlineStatement(graph, statements, predicateURI, objectInfo, indent); + } else { + String objectName = objectInfo.name; + if (objectName.startsWith("blank")) { + objectName = getBlankRewrite(objectName); + } + if (DEBUG) + System.out.println(" adding statement " + predicateURI + " " + objectName); + addStatement(statements, predicateURI, objectName); + } + } + + if (DEBUG) + System.out.println( + "statements size for " + info.name + " : " + statements.size() + " " + statements.keySet()); + + StringBuilder output = new StringBuilder(); + + if (indent == 0 || inline) { + if ("ROOT".equals(info.name)) { + output.append("ROOT="); + } else if (info.aliasURI != null) { + output.append(info.name + " = <" + info.aliasURI + ">"); + } else { + String infoName = info.name; + if (infoName.startsWith("blank")) { + infoName = getBlankRewrite(infoName); + } + output.append(inline ? "_" : infoName); + } + Set instanceOfs = statements.get("L0.InstanceOf"); + if (instanceOfs != null) { + for (String instanceOf : instanceOfs) { + output.append(" : " + instanceOf); + } + } + Set subrelationOfs = statements.get("L0.SubrelationOf"); + if (subrelationOfs != null) { + for (String subrelationOf : subrelationOfs) { + output.append(" inherits = statements.get("L0.Inherits"); + if (inherits != null) { + for (String inherit : inherits) { + output.append(" > entry : statements.entrySet()) { + String predicate = entry.getKey(); + if (ignoreIdentifiers) { + if (predicate.equals("L0.identifier")) { + continue; + } + } + if ("L0.InstanceOf".equals(predicate)) + continue; + if ("L0.SubrelationOf".equals(predicate)) + continue; + if ("L0.Inherits".equals(predicate)) + continue; + if ("L0.PartOf".equals(predicate)) + continue; + + // predicates can be blank + if (predicate.startsWith("blan")) { + predicate = getBlankRewrite(predicate); + } + + Set objects = entry.getValue(); + indent(output, indent + 1); + if (objects.size() == 1) { + output.append(predicate + " " + objects.iterator().next() + "\n"); + } else { + output.append(predicate + "\n"); + for (String object : objects) { + indent(output, indent + 1); + output.append(" " + object + "\n"); + } + } + } + + TreeMap ownedOrdered = new TreeMap<>(); + + for (int i = 0; i < info.owned.size(); i += 2) { + String predicateURI = rewritePredicateURI(graph, info.owned.get(i)); + ownedOrdered.put(predicateURI, info.owned.get(i + 1)); + } + + if (DEBUG) + System.out.println(info.name + " : " + ownedOrdered.keySet()); + + for (Entry entry : ownedOrdered.entrySet()) { + String predicateURI = entry.getKey(); + int owned = entry.getValue(); + ResourceInfo ownedInfo = infos.get(owned); + + String blank = printBlank(graph, predicateURI, ownedInfo, indent + 1); + if (blank != null) { + output.append(blank); + } + } + + return output.toString(); + } void prettyPrint(Path input, Path output) throws Exception { - System.out.format("Converting exported shared ontology%n\t" + input.toString() + "%nto bundle-compatible ontology%n\t" + output.toString()); - try (InputStream is = new BufferedInputStream(Files.newInputStream(input), 128*1024)) { - DataInput dis = new DataInputStream(is); - org.simantics.databoard.container.DataContainer container = - DataContainers.readFile(dis); - Binding binding = TransferableGraph1.BINDING; - TransferableGraph1 graph = (TransferableGraph1)container.content.getValue(binding); - prettyPrint(graph); - Files.write(output, this.output.toString().getBytes()); - - } - - } - - static Map knownOntologies = new HashMap<>(); - - static { - knownOntologies.put("http://www.simantics.org/Layer0-1.1", "L0"); - knownOntologies.put("http://www.simantics.org/Layer0X-1.1", "L0X"); - knownOntologies.put("http://www.simantics.org/Modeling-1.2", "MOD"); - knownOntologies.put("http://www.simantics.org/Diagram-2.2", "DIA"); - knownOntologies.put("http://www.simantics.org/Structural-1.2", "STR"); - knownOntologies.put("http://www.simantics.org/Document-1.2", "DOC"); - knownOntologies.put("http://www.simantics.org/Documentation-1.2", "DOCU"); - knownOntologies.put("http://www.simantics.org/G2D-1.1", "G2D"); - knownOntologies.put("http://www.simantics.org/SelectionView-1.2", "SEL"); - knownOntologies.put("http://www.simantics.org/Viewpoint-1.2", "VP"); - knownOntologies.put("http://www.simantics.org/Image2-1.2", "IMAGE2"); - knownOntologies.put("http://www.simantics.org/GraphFile-0.1", "GRAPHFILE"); - knownOntologies.put("http://www.simantics.org/Project-1.2", "PROJECT"); - knownOntologies.put("http://www.semantum.fi/Simupedia-1.0", "SIMUPEDIA"); - knownOntologies.put("http://www.semantum.fi/SimupediaWorkbench-1.0", "SIMUPEDIA_WORKBENCH"); - } - - - void prettyPrint(TransferableGraph1 graph) throws Exception { - - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Starting prettyPrint for TransferableGraph with " + graph.resourceCount + " resources, " + graph.identities + " identities, " + graph.statements.length + " statements and " + graph.values.length + " values"); - - for(Identity id : graph.identities) { - if(id.definition instanceof Internal) { - Internal internal = (Internal)id.definition; - Identity parent = TransferableGraphUtils.getIdentity(graph, internal.parent); - if(parent.definition instanceof External) { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Resolving internal identity " + id); - String name = "BASE"; - ResourceInfo info = new ResourceInfo(true, name, id.resource, -1); - info.aliasURI = TransferableGraphUtils.getURI(graph, id.resource); - info.newResource = true; - infos.put(id.resource, info); - if (LOGGER.isDebugEnabled()) - LOGGER.debug(" which parent is external " + parent + " and has an aliasURI " + info.aliasURI) ; - for(Identity child : TransferableGraphUtils.getChildren(graph, id)) { - recurseURI(graph, child, name, info.resource); - } - if (LOGGER.isDebugEnabled()) - LOGGER.debug(" and has " + (infos.size() - 1) + " children"); - } - } else if (id.definition instanceof External) { - External ext = (External)id.definition; - // Try to detect shared libraries - if(ext.name.contains("@")) { - - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Detected an external shared library " + ext); - - int index = ext.name.indexOf('@'); - String prefix = ext.name.substring(0, index); - int index2 = ext.name.indexOf('/', index); - String ontology = index2 == -1 ? ext.name : ext.name.substring(0, index2); - String uri = TransferableGraphUtils.getURI(graph, id.resource); - - if (LOGGER.isDebugEnabled()) - LOGGER.debug(" which was resolved as URI=" + uri + " and prefix " + prefix); - - ontologies.put(uri, prefix); - - } else if (ext.name.contains("-")) { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Resolving possible ontology " + ext); - String uri = TransferableGraphUtils.getURI(graph, id.resource); - Matcher m = versionExtractPattern.matcher(uri); - if (m.matches()) { - if(!ontologies.containsKey(uri)) { - int index = ext.name.indexOf('-'); + System.out.format("Converting exported shared ontology%n\t" + input.toString() + + "%nto bundle-compatible ontology%n\t" + output.toString()); + try (InputStream is = new BufferedInputStream(Files.newInputStream(input), 128 * 1024)) { + DataInput dis = new DataInputStream(is); + org.simantics.databoard.container.DataContainer container = DataContainers.readFile(dis); + Binding binding = TransferableGraph1.BINDING; + TransferableGraph1 graph = (TransferableGraph1) container.content.getValue(binding); + prettyPrint(graph); + Files.write(output, this.output.toString().getBytes()); + + } + + } + + static Map knownOntologies = new HashMap<>(); + + static { + knownOntologies.put("http://www.simantics.org/Layer0-1.1", "L0"); + knownOntologies.put("http://www.simantics.org/Layer0X-1.1", "L0X"); + knownOntologies.put("http://www.simantics.org/Modeling-1.2", "MOD"); + knownOntologies.put("http://www.simantics.org/Diagram-2.2", "DIA"); + knownOntologies.put("http://www.simantics.org/Structural-1.2", "STR"); + knownOntologies.put("http://www.simantics.org/Document-1.2", "DOC"); + knownOntologies.put("http://www.simantics.org/Documentation-1.2", "DOCU"); + knownOntologies.put("http://www.simantics.org/G2D-1.1", "G2D"); + knownOntologies.put("http://www.simantics.org/SelectionView-1.2", "SEL"); + knownOntologies.put("http://www.simantics.org/Viewpoint-1.2", "VP"); + knownOntologies.put("http://www.simantics.org/Image2-1.2", "IMAGE2"); + knownOntologies.put("http://www.simantics.org/GraphFile-0.1", "GRAPHFILE"); + knownOntologies.put("http://www.simantics.org/Project-1.2", "PROJECT"); + knownOntologies.put("http://www.semantum.fi/Simupedia-1.0", "SIMUPEDIA"); + knownOntologies.put("http://www.semantum.fi/SimupediaWorkbench-1.0", "SIMUPEDIA_WORKBENCH"); + } + + void prettyPrint(TransferableGraph1 graph) throws Exception { + log("Starting prettyPrint for TransferableGraph with {} resources, {} identities, {} statements and {} values", + graph.resourceCount, graph.identities, graph.statements.length, graph.values.length); + + for (Identity id : graph.identities) { + if (id.definition instanceof Internal) { + Internal internal = (Internal) id.definition; + Identity parent = TransferableGraphUtils.getIdentity(graph, internal.parent); + if (parent.definition instanceof External) { + log("Resolving internal identity {}", id); + String name = "BASE"; + ResourceInfo info = new ResourceInfo(true, name, id.resource, -1); + info.aliasURI = TransferableGraphUtils.getURI(graph, id.resource); + info.newResource = true; + orderedInfos.put(name, info); + // infos.put(id.resource, info); + log(" which parent is external {} and has an aliasURI {}", parent, info.aliasURI); + for (Identity child : TransferableGraphUtils.getChildren(graph, id)) { + recurseURI(graph, child, name, info.resource); + } + log(" and has {} children", infos.size()); + } + } else if (id.definition instanceof External) { + External ext = (External) id.definition; + // Try to detect shared libraries + if (ext.name.contains("@")) { + + log("Detected an external shared library {}", ext); + + int index = ext.name.indexOf('@'); + String prefix = ext.name.substring(0, index); + int index2 = ext.name.indexOf('/', index); + String ontology = index2 == -1 ? ext.name : ext.name.substring(0, index2); + String uri = TransferableGraphUtils.getURI(graph, id.resource); + + log(" which was resolved as URI={} and prefix={}", uri, prefix); + + ontologies.put(uri, prefix); + + } else if (ext.name.contains("-")) { + log("Resolving possible ontology {}", ext); + String uri = TransferableGraphUtils.getURI(graph, id.resource); + Matcher m = versionExtractPattern.matcher(uri); + if (m.matches()) { + if (!ontologies.containsKey(uri)) { + int index = ext.name.indexOf('-'); String prefix = ext.name.substring(0, index); - if (LOGGER.isDebugEnabled()) - LOGGER.debug(" and it was resolved as URI=" + uri + " and prefix " + prefix); + log(" and it was resolved as URI={} and prefix {}", uri, prefix); ontologies.put(uri, prefix); - } - } - } - } - } - // Discover other resources - if (LOGGER.isDebugEnabled()) - LOGGER.debug("Discovering other resources.."); - - TIntArrayList todo = new TIntArrayList(); - for(ResourceInfo info : infos.valueCollection()) - todo.add(info.resource); - - while(!todo.isEmpty()) { - int resource = todo.removeAt(todo.size()-1); - discoverBlank(graph, resource, todo); - } - for(ResourceInfo info : infos.valueCollection()) - discoverOwners(graph, info); - // for(ResourceInfo info : infos.valueCollection()) - // fixInstanceOf(graph, info); - + } + } + } + } + } + + // Discover other resources + log("Discovering other resources.."); + + TIntArrayList todo = new TIntArrayList(); + for (ResourceInfo info : orderedInfos.values()) { + todo.add(info.resource); + + // put orderedInfos to infos + infos.put(info.resource, info); + } + + while (!todo.isEmpty()) { + int resource = todo.removeAt(todo.size() - 1); + discoverBlank(graph, resource, todo); + } + for (ResourceInfo info : infos.valueCollection()) + discoverOwners(graph, info); + // for(ResourceInfo info : infos.valueCollection()) + // fixInstanceOf(graph, info); + for (ResourceInfo info : infos.valueCollection()) { -// Old implementation -// if (info.owner >= 0) { -// ResourceInfo ownerInfo = infos.get(info.owner); -// System.out.println("originalOwner : " + info.owner + " originalPredicate: " + info.ownerPredicate); -// ownerInfo.owned.add(info.ownerPredicate); -// ownerInfo.owned.add(info.resource); -// } - + // Old implementation + // if (info.owner >= 0) { + // ResourceInfo ownerInfo = infos.get(info.owner); + // System.out.println("originalOwner : " + info.owner + " + // originalPredicate: " + info.ownerPredicate); + // ownerInfo.owned.add(info.ownerPredicate); + // ownerInfo.owned.add(info.resource); + // } + if (!info.ownedResourcesWithPredicates.isEmpty() && info.ownedResourcesWithPredicates.size() == 1) { info.ownedResourcesWithPredicates.forEachEntry(new TIntIntProcedure() { - + @Override public boolean execute(int owner, int predicate) { ResourceInfo ownerInfo = infos.get(owner); @@ -605,63 +770,263 @@ public class PrettyPrintTG { // Resolve inverses from ownedBy list for (ResourceInfo info : infos.valueCollection()) { - for (int i = 0; i < info.owned.size(); i+=2) { - int object = info.owned.get(i+1); + for (int i = 0; i < info.owned.size(); i += 2) { + int object = info.owned.get(i + 1); ResourceInfo inf = infos.get(object); if (inf != null) { info.ownedBy.remove(inf); } } } - - TreeMap order = new TreeMap<>(); - for(ResourceInfo info : infos.valueCollection()) - order.put(info.name, info); - - for(ResourceInfo info : order.values()) { - String uri = printURI(graph, info, true, 0, false); - if (uri != null) - output.append(uri); - } - - for (ResourceInfo info : order.values()) { - if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) { - String uri = printURI(graph, info, false, 0, false); - if (uri != null) - output.append(uri); - } - } -// for(ResourceInfo info : order.values()) -// if(!info.hasURI && info.owner < 0) -// printURI(graph, info, false, 0); - - StringBuilder refs = new StringBuilder(); - for(String ontology : referencedOntologies) { - String key = ontologies.get(ontology); - refs.append(key + " = <" + ontology + ">\n"); - } - if (!referencedOntologies.isEmpty()) - refs.append("\n"); - output.insert(0, refs.toString()); - - } - - public static String print(TransferableGraph1 tg) throws Exception { - StringBuilder b = new StringBuilder(); - new PrettyPrintTG(b).prettyPrint(tg); - return b.toString(); - } - - public static void main(String[] args) throws Exception { - if (args.length < 1) { - System.out.println("Required arguments: []"); - } else if (args.length < 2) { - Path input = Paths.get(args[0]); - Path output = input.getParent().resolve(input.getName(input.getNameCount()-1) + ".fixed"); - new PrettyPrintTG().prettyPrint(input, output); - } else { - new PrettyPrintTG().prettyPrint(Paths.get(args[0]), Paths.get(args[1])); - } - } + + Identity routeGraphConn = TransferableGraphUtils.findExternal(graph, + "http://www.simantics.org/Diagram-2.2/RouteGraphConnection"); + Identity instanceOf = TransferableGraphUtils.findExternal(graph, + "http://www.simantics.org/Layer0-1.1/InstanceOf"); + Identity diagramConnetionToConnection = TransferableGraphUtils.findExternal(graph, + "http://www.simantics.org/Modeling-1.2/DiagramConnectionToConnection"); + + for (ResourceInfo infoo : infos.valueCollection()) { + Identity elemTo = TransferableGraphUtils.findExternal(graph, + "http://www.simantics.org/Modeling-1.2/ElementToComponent"); + if (elemTo != null) { + int elemToComponent = TransferableGraphUtils.getPossibleObject2(graph, infoo.resource, elemTo); + if (elemToComponent != TransferableGraphUtils.NOT_FOUND) { + + Identity component = TransferableGraphUtils.getIdentity(graph, elemToComponent); + Identity internal = TransferableGraphUtils.getIdentity(graph, infoo.resource); + if (internal.definition instanceof Internal && component.definition instanceof Internal) { + Internal iCOmponent = (Internal) component.definition; + infoo.name = infoo.name.substring(0, infoo.name.lastIndexOf(".") + 1) + iCOmponent.name; + } + } + } + + if (instanceOf != null) { + int instOf = TransferableGraphUtils.getPossibleObject2(graph, infoo.resource, instanceOf); + if (instOf != TransferableGraphUtils.NOT_FOUND && routeGraphConn != null) { + if (instOf == routeGraphConn.resource) { + // Found routegraphconnection, change name + // Lets go to configuration + + int connection = TransferableGraphUtils.getPossibleObject2(graph, infoo.resource, + diagramConnetionToConnection); + if (connection != TransferableGraphUtils.NOT_FOUND) { + // Gather all inverse statements to construct unique + // name + List nameParts = new ArrayList<>(); + TIntArrayList statements = TransferableGraphUtils.getStatements(graph, connection); + for (int i = 0; i < statements.size(); i += 2) { + int predicate = statements.get(i); + Identity possibleInverse = TransferableGraphUtils.getIdentity(graph, predicate); + if (possibleInverse != null) { + int inverseRelation = TransferableGraphUtils.NOT_FOUND; + int parentId = TransferableGraphUtils.NOT_FOUND; + if (possibleInverse.definition instanceof Internal) { + Internal iPossibleInverse = (Internal) possibleInverse.definition; + if (iPossibleInverse.name.equals("Inverse")) { + inverseRelation = TransferableGraphUtils.getPossibleObject2(graph, + connection, possibleInverse); + parentId = iPossibleInverse.parent; + } else { + LOGGER.error("THIS UNSUPPORTED for " + infoo + " " + iPossibleInverse); + } + } else if (possibleInverse.definition instanceof External) { + External ePossibleInverse = (External) possibleInverse.definition; + if (ePossibleInverse.name.equals("Inverse")) { + inverseRelation = TransferableGraphUtils.getPossibleObject2(graph, + connection, possibleInverse); + parentId = ePossibleInverse.parent; + } else { + // This is not an inverse + // LOGGER.error("THIS UNSUPPORTED + // TOO"); + } + } else { + LOGGER.error("UNSUPPORTED for " + infoo + " "); + } + if (inverseRelation != TransferableGraphUtils.NOT_FOUND) { + // Ok found something + Identity object = TransferableGraphUtils.getIdentity(graph, inverseRelation); + Identity parent = TransferableGraphUtils.getIdentity(graph, parentId); + String objectName, parentName; + if (object.definition instanceof Internal) { + objectName = ((Internal) object.definition).name; + } else if (object.definition instanceof External) { + objectName = ((External) object.definition).name; + } else { + LOGGER.error("UNSUPPORTED " + infoo); + throw new Error("UNSUPPORTED " + infoo); + } + if (parent.definition instanceof Internal) { + parentName = ((Internal) parent.definition).name; + } else if (parent.definition instanceof External) { + parentName = ((External) parent.definition).name; + } else { + LOGGER.error("UNSUPPORTED " + infoo); + throw new Error("UNSUPPORTED " + infoo); + } + String fullName = parentName + "_" + objectName; + nameParts.add(fullName); + } else { + LOGGER.error("THIS IS ALSO UNSupported"); + } + } else { + LOGGER.error("HERE"); + } + } + nameParts.sort((o1, o2) -> o1.compareTo(o2)); + String name = ""; + for (String namep : nameParts) { + name += namep; + } + infoo.name = infoo.name.substring(0, infoo.name.lastIndexOf(".") + 1) + name; + } else { + LOGGER.error("Could not find connection for " + infoo + ". Statements of graph below"); + LOGGER.error(Arrays.toString(graph.statements)); + LOGGER.error("Subject -> Predicate : " + infoo.resource + " -> " + + diagramConnetionToConnection.resource); + } + } + } + } + } + for (ResourceInfo info : infos.valueCollection()) { + if (info.name.startsWith("blank")) { + info.name = "blank" + findHash(graph, info); + } + } + + TreeMap order = new TreeMap<>(); + for (ResourceInfo info : infos.valueCollection()) + order.put(info.name, info); + + for (ResourceInfo info : order.values()) { + if (DEBUG) + System.out.print("info "); + String uri = printURI(graph, info, true, 0, false); + if (uri != null) + output.append(uri); + } + + TreeMap rblanks = new TreeMap<>(); + + for (ResourceInfo info : order.values()) { + if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) { + if (DEBUG) + System.out.print("ownedResources "); + if (info.name.startsWith("blank")) { + // These will be printed later + rblanks.put(getBlankRewrite(info.name), info); + } else { + String uri = printURI(graph, info, false, 0, false); + if (uri != null) + output.append(uri); + } + } + } + // Now print blanks in order + for (ResourceInfo info : rblanks.values()) { + if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) { + if (DEBUG) + System.out.print("ownedResources "); + String uri = printURI(graph, info, false, 0, false); + if (uri != null) + output.append(uri); + } + } + + // for(ResourceInfo info : order.values()) + // if(!info.hasURI && info.owner < 0) + // printURI(graph, info, false, 0); + + StringBuilder refs = new StringBuilder(); + for (String ontology : referencedOntologies) { + String key = ontologies.get(ontology); + refs.append(key + " = <" + ontology + ">\n"); + } + if (!referencedOntologies.isEmpty()) + refs.append("\n"); + output.insert(0, refs.toString()); + + } + + private String calculateHash(TransferableGraph1 graph, ResourceInfo info) { + StringBuilder statementHash = new StringBuilder(); + TreeSet parts = new TreeSet<>(); + for (int i = 0; i < info.owned.size(); i += 2) { + int predicate = info.owned.get(i); + int object = info.owned.get(i + 1); + // Lets resolve a unique name for this based on the statements this + // one has + + String predicatee = rewritePredicateURI(graph, predicate); + ResourceInfo objInfo = infos.get(object); + parts.add(predicatee + "->" + objInfo.name + ";;;"); + } + // Remove this from the list + List filtered = info.ownedBy.stream().filter(ri -> !ri.name.startsWith("blank")) + .collect(Collectors.toList()); + for (ResourceInfo ownedBy : filtered) { + parts.add(ownedBy.name); + } + // check parent + ResourceInfo parentInfo = infos.get(info.parent); + if (parentInfo != null && !parentInfo.name.startsWith("blank")) { + parts.add("parent" + parentInfo.name); + } else { + // LOGGER.error("This should not happen"); + } + for (String s : parts) { + statementHash.append(s); + } + String hash = makeHash(statementHash.toString().getBytes()); + if (DEBUG) + System.out.println(statementHash + " -> " + hash); + return hash; + } + + private String findHash(TransferableGraph1 graph, ResourceInfo info) { + if (info.name.startsWith("blank")) { + String hash = hashes.get(info.name); + if (hash == null) { + String oldName = info.name; + if (DEBUG) + System.out.print("calculating hash for " + oldName + " "); + hash = calculateHash(graph, info); + if (hashes.put(oldName, hash) != null) { + System.err.println("!!!!A clash occured for " + info + " with hash " + hash); + } + } + return hash; + } else { + return info.name; + } + } + + private THashMap hashes = new THashMap<>(); + + public static String print(TransferableGraph1 tg, boolean ignoreIdentifiers) throws Exception { + StringBuilder b = new StringBuilder(); + new PrettyPrintTG(b, ignoreIdentifiers).prettyPrint(tg); + return b.toString(); + } + + public static void main(String[] args) throws Exception { + if (args.length < 1) { + System.out.println("Required arguments: []"); + } else if (args.length < 2) { + Path input = Paths.get(args[0]); + Path output = input.getParent().resolve(input.getName(input.getNameCount() - 1) + ".fixed"); + new PrettyPrintTG().prettyPrint(input, output); + } else { + new PrettyPrintTG().prettyPrint(Paths.get(args[0]), Paths.get(args[1])); + } + } + + private static void log(String string, Object... args) { + if (LOGGER.isDebugEnabled() && DEBUG) + LOGGER.debug(string, args); + } } diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphUtils.java b/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphUtils.java index a7b92c8d0..b210d8dd7 100644 --- a/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphUtils.java +++ b/bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphUtils.java @@ -146,22 +146,53 @@ public class TransferableGraphUtils { return result; } + /** + * This implementation is no longer advised to use because it returns 0 as + * NOT_FOUND which is in fact a valid ID for resource in graph + */ + @Deprecated public static int getPossibleObject(TransferableGraph1 tg, int subject, Identity predicate) { int result = 0; for(int i=0;i getNames(TransferableGraph1 tg, Collection ids) { Map result = new HashMap(); @@ -256,36 +287,14 @@ public class TransferableGraphUtils { if(definition instanceof External) { External def = (External)definition; if(def.parent == -1) return "http:/"; - else return getURI(resourceCount, identities, def.parent) + "/" + def.name; - } else if(definition instanceof Root) { - Root def = (Root)definition; - if(def.name.isEmpty()) return "http:/"; - return def.name; - } else if (definition instanceof Internal) { - Internal def = (Internal)definition; - return getURI(resourceCount, identities, def.parent) + "/" + def.name; - } else { - return ""; - } - } - return ":"; - } - - public static String getTrueURI(int resourceCount, TIntObjectMap identities, int id) { - Identity identity = identities.get(id); - if(identity != null) { - IdentityDefinition definition = identity.definition; - if(definition instanceof External) { - External def = (External)definition; - if(def.parent == -1) return "http:/"; - else return getTrueURI(resourceCount, identities, def.parent) + "/" + URIStringUtils.escape(def.name); + else return getURI(resourceCount, identities, def.parent) + "/" + URIStringUtils.escape(def.name); } else if(definition instanceof Root) { Root def = (Root)definition; if(def.name.isEmpty()) return "http:/"; return def.name; } else if (definition instanceof Internal) { Internal def = (Internal)definition; - return getTrueURI(resourceCount, identities, def.parent) + "/" + URIStringUtils.escape(def.name); + return getURI(resourceCount, identities, def.parent) + "/" + URIStringUtils.escape(def.name); } else { return ""; } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/PGraphEditorDocumentProvider.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/PGraphEditorDocumentProvider.java index eeaab985c..39152636b 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/PGraphEditorDocumentProvider.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/PGraphEditorDocumentProvider.java @@ -64,7 +64,7 @@ public class PGraphEditorDocumentProvider extends AbstractDocumentProvider { if(indexRoot != null && graph.isInstanceOf(indexRoot, L0.Ontology)) { TransferableGraph1 tg = ModelingUtils.exportSharedOntology(graph, indexRoot, null, Constants.SHARED_LIBRARY_FORMAT, Constants.SHARED_LIBRARY_CURRENT_VERSION); GraphRefactoringUtils.fixOntologyExport(tg); - currentText = PrettyPrintTG.print(tg); + currentText = PrettyPrintTG.print(tg, false); errorHappened = false; } return new Document(currentText != null ? currentText : ""); diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/NodeTree.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/NodeTree.java new file mode 100644 index 000000000..a17aafb4a --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/NodeTree.java @@ -0,0 +1,501 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - #7297 + *******************************************************************************/ +package org.simantics.modeling.ui.pdf; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ICheckStateProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.TreeItem; +import org.simantics.browsing.ui.common.views.DefaultFilterStrategy; +import org.simantics.browsing.ui.common.views.IFilterStrategy; +import org.simantics.modeling.requests.CollectionResult; +import org.simantics.modeling.requests.Node; +import org.simantics.utils.strings.AlphanumComparator; +import org.simantics.utils.ui.ISelectionUtils; + +/** + * A tree of nodes intended for usable listing and selecting diagrams. + * + * @author Tuukka Lehtonen + * @since 1.30.0 + */ +public class NodeTree extends Composite { + + /** + * This exists to make {@link NodeCheckStateProvider} faster + */ + private static class CheckStateCache { + Map isChecked = new HashMap<>(); + Map isGrayed = new HashMap<>(); + + public void invalidate(Node n) { + for (; n != null; n = n.getParent()) { + isChecked.remove(n); + isGrayed.remove(n); + } + } + public void invalidate() { + isChecked.clear(); + isGrayed.clear(); + } + } + + protected Display display; + + protected LocalResourceManager resourceManager; + + protected Color noDiagramColor; + + protected IFilterStrategy filterStrategy = new DefaultFilterStrategy(); + + protected Text filter; + + protected Matcher matcher = null; + + protected CheckboxTreeViewer tree; + + /** + * The tree paths that were expanded last time no filter was defined. Will + * be nullified after the expanded paths have been returned when + * {@link #matcher} turns null. + */ + protected TreePath[] noFilterExpandedPaths; + + protected Set selectedNodes; + + protected CheckStateCache checkStateCache = new CheckStateCache(); + + protected Runnable selectionChangeListener; + + protected CollectionResult nodes; + + public NodeTree(Composite parent, Set selectedNodes) { + super(parent, 0); + + this.display = getDisplay(); + this.selectedNodes = selectedNodes; + + resourceManager = new LocalResourceManager(JFaceResources.getResources(), this); + noDiagramColor = getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); + + GridLayoutFactory.fillDefaults().spacing(20, 10).numColumns(3).applyTo(this); + + createFilter(this); + createTree(this); + createButtons(this); + } + + public void setSelectionChangeListener(Runnable r) { + this.selectionChangeListener = r; + } + + public void setInput(CollectionResult nodes) { + this.nodes = nodes; + tree.setInput(nodes); + resetFilterString(filter.getText()); + } + + private Runnable resetFilter = () -> resetFilterString(filter.getText()); + + private void createFilter(Composite parent) { + Label filterLabel = new Label(parent, SWT.NONE); + filterLabel.setText("Fi<er:"); + GridDataFactory.fillDefaults().span(1, 1).applyTo(filterLabel); + filter = new Text(parent, SWT.BORDER); + GridDataFactory.fillDefaults().span(2, 1).applyTo(filter); + filter.addModifyListener(e -> display.timerExec(500, resetFilter)); + } + + private void createTree(Composite parent) { + tree = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); + tree.setUseHashlookup(true); + GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(tree.getControl()); + tree.getControl().setToolTipText("Selects the diagrams to include in the exported document."); + tree.setAutoExpandLevel(2); + tree.addCheckStateListener(new CheckStateListener()); + tree.setContentProvider(new NodeTreeContentProvider()); + tree.setLabelProvider(new NodeLabelProvider()); + tree.setCheckStateProvider(new NodeCheckStateProvider()); + tree.setComparator(new ViewerComparator(AlphanumComparator.CASE_INSENSITIVE_COMPARATOR)); + tree.setFilters(new ViewerFilter[] { new NodeFilter() }); + } + + private void createButtons(Composite parent) { + Composite bar = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(bar); + bar.setLayout(new RowLayout()); + Button selectAll = new Button(bar, SWT.PUSH); + selectAll.setText("Select &All"); + selectAll.setToolTipText("Select All Visible Diagrams"); + selectAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + selectedNodes.addAll(filter.getText().isEmpty() ? nodes.breadthFirstFlatten(CollectionResult.DIAGRAM_RESOURCE_FILTER) : getVisibleNodes()); + refreshTree(true); + fireChangeListener(); + scheduleFocusTree(); + } + }); + Button clearSelection = new Button(bar, SWT.PUSH); + clearSelection.setText("&Deselect All"); + clearSelection.setToolTipText("Deselect All Visible Diagrams"); + clearSelection.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (filter.getText().isEmpty()) + selectedNodes.clear(); + else + selectedNodes.removeAll(getVisibleNodes()); + refreshTree(true); + fireChangeListener(); + scheduleFocusTree(); + } + }); + Button expand = new Button(bar, SWT.PUSH); + expand.setText("&Expand"); + expand.setToolTipText("Fully Expand Selected Nodes or All Nodes"); + expand.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + IStructuredSelection ss = tree.getStructuredSelection(); + if (ss.isEmpty()) + tree.expandAll(); + else + for (Object n : ss.toList()) + tree.expandToLevel(n, TreeViewer.ALL_LEVELS); + scheduleFocusTree(); + } + }); + Button collapse = new Button(bar, SWT.PUSH); + collapse.setText("&Collapse"); + collapse.setToolTipText("Collapse Selected Nodes or All Nodes"); + collapse.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + IStructuredSelection ss = tree.getStructuredSelection(); + if (ss.isEmpty()) + tree.collapseAll(); + else + for (Object n : ss.toList()) + tree.collapseToLevel(n, TreeViewer.ALL_LEVELS); + scheduleFocusTree(); + } + }); + } + + protected void fireChangeListener() { + if (selectionChangeListener != null) + selectionChangeListener.run(); + } + + protected void scheduleFocusTree() { + display.asyncExec(() -> { + if (!tree.getTree().isDisposed() && !tree.getTree().isFocusControl()) + tree.getTree().setFocus(); + }); + } + + private Collection getVisibleNodes() { + Collection result = new ArrayList<>(); + + Deque todo = new ArrayDeque<>(); + for (TreeItem ti : tree.getTree().getItems()) { + todo.add(ti); + } + + while (!todo.isEmpty()) { + TreeItem item = todo.removeLast(); + Node node = (Node) item.getData(); + if (node != null) + result.add(node); + + for (TreeItem child : item.getItems()) { + todo.add(child); + } + } + + return result; + } + + private void resetFilterString(String filterString) { + TreePath[] restoreExpansions = null; + String patternString = filterStrategy.toPatternString(filterString); + if (patternString == null) { + if (matcher != null) { + // Filter has been removed + restoreExpansions = noFilterExpandedPaths; + noFilterExpandedPaths = null; + } + matcher = null; + } else { + if (matcher == null) { + // Filter has been defined after not being previously defined + noFilterExpandedPaths = tree.getExpandedTreePaths(); + } + matcher = Pattern.compile(patternString).matcher(""); + } + refreshTree(false); + if (restoreExpansions != null) + tree.setExpandedTreePaths(restoreExpansions); + else + tree.expandAll(); + } + + protected static boolean hasDiagram(Node n) { + return n.getDiagramResource() != null; + } + + protected static boolean hasDiagramDeep(Node n) { + if (hasDiagram(n)) + return true; + for (Node c : n.getChildren()) + if (hasDiagramDeep(c)) + return true; + return false; + } + + protected boolean isSomethingSelected(Node node) { + if (selectedNodes.contains(node)) + return true; + + Collection children = node.getChildren(); + if (!children.isEmpty()) { + for (Node child : children) { + if (!hasDiagramDeep(child)) + continue; + if (isSomethingSelected(child)) + return true; + } + } + return false; + } + + protected boolean isFullySelected(Node node) { + if (selectedNodes.contains(node)) + return true; + + int selectedCount = 0; + boolean allSelected = true; + Collection children = node.getChildren(); + if (!children.isEmpty()) { + for (Node child : children) { + if (!hasDiagramDeep(child)) + continue; + boolean selected = isFullySelected(child); + allSelected &= selected; + selectedCount += selected ? 1 : 0; + //System.out.println("\tisFullySelected: test child: " + child + " : " + selected + " => " + allSelected); + if (!selected) + break; + } + } + //System.out.println("isFullySelected(" + node + "): " + allSelected + ", " + selectedCount); + return allSelected && selectedCount > 0; + } + + protected boolean isPartiallySelected(Node node) { + return !selectedNodes.contains(node) && isSomethingSelected(node) && !isFullySelected(node); + } + + protected void refreshTree(boolean invalidateCheckStateCache) { + if (invalidateCheckStateCache) + checkStateCache.invalidate(); + tree.refresh(); + } + + public void refreshTree() { + refreshTree(true); + } + + public boolean addOrRemoveSelection(Node node, boolean add) { + boolean changed = false; + if (hasDiagram(node)) { + if (add) + changed = selectedNodes.add(node); + else + changed = selectedNodes.remove(node); + if (changed) + checkStateCache.invalidate(node); + } + return changed; + } + + public boolean addOrRemoveSelectionRec(Node node, boolean add) { + boolean changed = false; + changed |= addOrRemoveSelection(node, add); + for (Node child : node.getChildren()) + changed |= addOrRemoveSelectionRec(child, add); + return changed; + } + + private static class NodeTreeContentProvider implements ITreeContentProvider { + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + @Override + public void dispose() { + } + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof CollectionResult) + return ((CollectionResult) inputElement).roots.toArray(); + return new Object[0]; + } + @Override + public boolean hasChildren(Object element) { + Node n = (Node) element; + Collection children = n.getChildren(); + if (children.isEmpty()) + return false; + for (Node c : children) + if (hasDiagramDeep(c)) + return true; + return false; + + } + @Override + public Object getParent(Object element) { + return ((Node) element).getParent(); + } + @Override + public Object[] getChildren(Object parentElement) { + Node n = (Node) parentElement; + List result = new ArrayList<>( n.getChildren().size() ); + for (Node c : n.getChildren()) + if (hasDiagramDeep(c)) + result.add(c); + return result.toArray(); + } + } + + private class NodeLabelProvider extends CellLabelProvider { + @Override + public void update(ViewerCell cell) { + Object e = cell.getElement(); + if (e instanceof Node) { + Node n = (Node) e; + String name = DiagramPrinter.formDiagramName(n, false); + cell.setText(name); + + if (n.getDiagramResource() == null) + cell.setForeground(noDiagramColor); + else + cell.setForeground(null); + } else { + cell.setText("invalid input: " + e.getClass().getSimpleName()); + } + } + } + + private class CheckStateListener implements ICheckStateListener { + @Override + public void checkStateChanged(CheckStateChangedEvent event) { + final boolean checked = event.getChecked(); + Node checkedNode = (Node) event.getElement(); + + Set nodes = new HashSet<>(); + Set selection = ISelectionUtils.filterSetSelection(tree.getSelection(), Node.class); + if (selection.contains(checkedNode)) + nodes.addAll(selection); + else + tree.setSelection(StructuredSelection.EMPTY); + nodes.add(checkedNode); + + for (Node node : nodes) + addOrRemoveSelectionRec(node, checked); + + tree.refresh(); + fireChangeListener(); + } + } + + private class NodeCheckStateProvider implements ICheckStateProvider { + @Override + public boolean isChecked(Object element) { + Node n = (Node) element; + Boolean cache = checkStateCache.isChecked.get(n); + if (cache != null) + return cache; + boolean checked = isSomethingSelected(n); + checkStateCache.isChecked.put(n, checked); + return checked; + } + @Override + public boolean isGrayed(Object element) { + Node n = (Node) element; + Boolean cache = checkStateCache.isGrayed.get(n); + if (cache != null) + return cache; + boolean grayed = n.getDiagramResource() == null && isPartiallySelected(n); + checkStateCache.isGrayed.put(n, grayed); + return grayed; + } + } + + private class NodeFilter extends ViewerFilter { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (matcher == null) + return true; + + Node node = (Node) element; + boolean matches = matcher.reset(node.getName().toLowerCase()).matches(); + if (matches) + return true; + + // If any children are in sight, show this element. + for (Node child : node.getChildren()) + if (select(viewer, element, child)) + return true; + + return false; + } + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java index f0c9cddb3..461e98c10 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - initial selection handling improvements *******************************************************************************/ package org.simantics.modeling.ui.pdf; @@ -17,16 +18,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPersistentPreferenceStore; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.IFilter; @@ -36,15 +36,16 @@ import org.eclipse.ui.IExportWizard; import org.eclipse.ui.IMemento; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.simantics.NameLabelMode; +import org.simantics.NameLabelUtil; import org.simantics.Simantics; -import org.simantics.browsing.ui.graph.impl.request.GetName; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.NamedResource; import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.request.ActiveModels; import org.simantics.db.management.ISessionContext; import org.simantics.layer0.Layer0; import org.simantics.modeling.requests.Node; @@ -56,12 +57,17 @@ import org.simantics.simulation.ontology.SimulationResource; import org.simantics.ui.SimanticsUI; import org.simantics.ui.utils.ResourceAdaptionUtils; import org.simantics.utils.FileUtils; +import org.simantics.utils.strings.AlphanumComparator; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ExceptionUtils; import org.simantics.utils.ui.workbench.StringMemento; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PDFDiagramExportWizard extends Wizard implements IExportWizard { + private static final Logger LOGGER = LoggerFactory.getLogger(PDFDiagramExportWizard.class); + private static final int MAX_RECENT_EXPORT_PATHS = 10; private static final String TAG_PATH = "path"; @@ -70,9 +76,9 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { Deque recentExportPaths; boolean zoomToFit; - boolean attachTG, attachWiki; + boolean attachTG, attachWiki, addPageNumbers; - PDFExportPlan exportPlan; + PDFExportPlan exportPlan; private boolean readPreferences() { IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.PLUGIN_ID); @@ -82,6 +88,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { zoomToFit = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT); attachTG = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_TG); attachWiki = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_WIKI); + addPageNumbers = store.getBoolean(Preferences.DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS); return true; } @@ -93,13 +100,14 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT, String.valueOf(zoomToFit)); store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_TG, String.valueOf(attachTG)); store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ATTACH_WIKI, String.valueOf(attachWiki)); + store.putValue(Preferences.DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS, String.valueOf(addPageNumbers)); if (store.needsSaving()) store.save(); } private Deque decodePaths(String recentPathsPref) { - Deque result = new LinkedList(); + Deque result = new LinkedList<>(); try { StringMemento sm = new StringMemento(recentPathsPref); for (IMemento m : sm.getChildren(TAG_PATH)) { @@ -137,7 +145,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { } private NamedResource toNamedResource(ReadGraph graph, Resource r) throws DatabaseException { - String name = graph.syncRequest(new GetName(r)); + String name = NameLabelUtil.modalName(graph, r, NameLabelMode.NAME_AND_LABEL); return new NamedResource(name, r); } @@ -154,54 +162,45 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { exportPlan = new PDFExportPlan(ctx, recentExportPaths); exportPlan.project = project; - final Object selectedObject = selection.getFirstElement(); + exportPlan.initialSelection = selection; exportPlan.fitContentToPageMargins = zoomToFit; exportPlan.attachTG = attachTG; exportPlan.attachWiki = attachWiki; + exportPlan.addPageNumbers = addPageNumbers; // Get all model names try { exportPlan.sessionContext.getSession().syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { - Resource selection = ResourceAdaptionUtils.toSingleResource(selectedObject); - if (selection != null) { - //exportModel.selection = new NamedResource(name + " (input selection)", selection); - exportPlan.selection = toNamedResource(graph, selection); - exportPlan.selectableModels.add(exportPlan.selection); - } else { - for (Resource activeModel : graph.syncRequest(new ActiveModels(exportPlan.project.get()))) { - selection = activeModel; - exportPlan.selection = toNamedResource(graph, activeModel); - exportPlan.selectableModels.add( exportPlan.selection ); - break; - } - } + Set processed = new HashSet<>(); + List models = new ArrayList<>(); - List models = new ArrayList(); - Collection ontologies = Simantics.applySCL("Simantics/SharedOntologies", "traverseSharedOntologies", graph, graph.getRootLibrary()); - for (Resource model : ontologies) { - if (model.equals(selection)) - continue; - models.add( toNamedResource(graph, model) ); + for (Resource root : ontologies) { + if (processed.add(root)) + models.add( toNamedResource(graph, root) ); } - + for (Resource model : graph.syncRequest(new ObjectsWithType(exportPlan.project.get(), Layer0.getInstance(graph).ConsistsOf, SimulationResource.getInstance(graph).Model))) { - if (model.equals(selection)) - continue; - models.add( toNamedResource(graph, model) ); + if (processed.add(model)) + models.add( toNamedResource(graph, model) ); } - Collections.sort(models); + Collections.sort(models, AlphanumComparator.CASE_INSENSITIVE_COMPARATOR); exportPlan.selectableModels.addAll(models); - if (selection == null && !exportPlan.selectableModels.isEmpty()) { + + Resource selected = ResourceAdaptionUtils.toSingleResource(selection.getFirstElement()); + Resource indexRoot = selected != null ? graph.sync(new PossibleIndexRoot(selected)) : null; + if (indexRoot != null) + exportPlan.initialModelSelection = exportPlan.selection = toNamedResource(graph, indexRoot); + + if (exportPlan.selection == null && !exportPlan.selectableModels.isEmpty()) exportPlan.selection = exportPlan.selectableModels.get(0); - } } }); } catch (DatabaseException e) { - e.printStackTrace(); + LOGGER.error("Failed to initialize diagram PDF export wizard input data.", e); } } @@ -224,7 +223,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { recentExportPaths.addFirst(exportPlan.exportLocation.getAbsolutePath()); // Remove duplicates - Set dups = new TreeSet(String.CASE_INSENSITIVE_ORDER); + Set dups = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); for (Iterator it = recentExportPaths.iterator(); it.hasNext();) { String path = it.next(); if (!dups.add(path)) { @@ -238,6 +237,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { zoomToFit = exportPlan.fitContentToPageMargins; attachTG = exportPlan.attachTG; attachWiki = exportPlan.attachWiki; + addPageNumbers = exportPlan.addPageNumbers; writePreferences(); } catch (IOException e) { @@ -256,16 +256,13 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { long start = System.currentTimeMillis(); try { - getContainer().run(true, true, new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes); - } catch (PdfException e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } + getContainer().run(true, true, monitor -> { + try { + DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes); + } catch (PdfException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); } }); } catch (InvocationTargetException e) { @@ -276,7 +273,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard { return false; } long end = System.currentTimeMillis(); - System.out.println("PDF export took " + ((end - start) * 1e-3) + " seconds."); + LOGGER.info("PDF export took " + ((end - start) * 1e-3) + " seconds."); return true; } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java index 7ef2efb94..fb2f8b0c6 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,145 +8,71 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - #7297 *******************************************************************************/ package org.simantics.modeling.ui.pdf; import java.io.File; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Deque; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.resource.LocalResourceManager; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.CheckStateChangedEvent; -import org.eclipse.jface.viewers.CheckboxTreeViewer; -import org.eclipse.jface.viewers.ICheckStateListener; -import org.eclipse.jface.viewers.ICheckStateProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.jface.viewers.ViewerComparator; -import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.TreeItem; -import org.simantics.browsing.ui.common.views.DefaultFilterStrategy; -import org.simantics.browsing.ui.common.views.IFilterStrategy; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.NamedResource; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.exception.DatabaseException; +import org.simantics.modeling.requests.CollectionResult; import org.simantics.modeling.requests.Node; +import org.simantics.modeling.requests.Nodes; +import org.simantics.ui.utils.ResourceAdaptionUtils; import org.simantics.utils.FileUtils; -import org.simantics.utils.strings.AlphanumComparator; -import org.simantics.utils.ui.ISelectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PDFExportPage extends WizardPage { - protected Display display; + private static final Logger LOGGER = LoggerFactory.getLogger(PDFExportPage.class); - protected PDFExportPlan exportModel; + protected Display display; - protected IFilterStrategy filterStrategy = new DefaultFilterStrategy(); + protected PDFExportPlan exportModel; protected Combo modelSelector; protected SelectionListener modelSelectorListener; - protected Text filter; - - protected Matcher matcher = null; - - protected CheckboxTreeViewer tree; + protected NodeTree nodeTree; protected CCombo exportLocation; protected ModifyListener exportLocationListener; protected Set selectedNodes; - - protected LocalResourceManager resourceManager; - protected Color noDiagramColor; - protected Label toFileLabel; + protected Label toFileLabel; protected boolean exportLocationTouchedByUser = false; - ICheckStateProvider checkStateProvider = new ICheckStateProvider() { - @Override - public boolean isChecked(Object element) { - Node node = (Node) element; - - // Primarily checked if any children are selected. - Collection children = node.getChildren(); - if (!children.isEmpty()) { - for (Node child : node.getChildren()) - if (isChecked(child)) - return true; - - // No children are checked, not checked. - return false; - } - - // Otherwise checked only if selected. - return selectedNodes.contains(node); - } - @Override - public boolean isGrayed(Object element) { - Node node = (Node) element; - - // Grayed if there are children but not all of them are selected. - Collection children = node.getChildren(); - if (!children.isEmpty()) { - for (Node child : children) - if (!selectedNodes.contains(child)) - return true; - } - - // Grayed if the node itself contains no diagram. - if (node.getDiagramResource() == null) - return true; - - // Otherwise never grayed. - return false; - } - }; - protected PDFExportPage(PDFExportPlan model) { super("Export Diagrams to PDF", "Define Exported Items", null); this.exportModel = model; @@ -165,14 +91,6 @@ public class PDFExportPage extends WizardPage { layout.numColumns = 3; container.setLayout(layout); } - resourceManager = new LocalResourceManager(JFaceResources.getResources()); - container.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - resourceManager.dispose(); - } - }); - noDiagramColor = container.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); Label modelSelectorLabel = new Label(container, SWT.NONE); modelSelectorLabel.setText("Model Selector:"); @@ -196,198 +114,9 @@ public class PDFExportPage extends WizardPage { modelSelector.addSelectionListener(modelSelectorListener); -// Label label = new Label(container, SWT.NONE); -// label.setText("Diagrams to Export:"); -// GridDataFactory.fillDefaults().span(3, 1).applyTo(label); - - Label filterLabel = new Label(container, SWT.NONE); - filterLabel.setText("Fi<er:"); - GridDataFactory.fillDefaults().span(1, 1).applyTo(filterLabel); - filter = new Text(container, SWT.BORDER); - GridDataFactory.fillDefaults().span(2, 1).applyTo(filter); - filter.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - resetFilterString(filter.getText()); - } - }); - - tree = new CheckboxTreeViewer(container, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); - { - tree.setUseHashlookup(true); - GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(tree.getControl()); - tree.getControl().setToolTipText("Selects the diagram to include in the exported document."); - tree.setAutoExpandLevel(TreeViewer.ALL_LEVELS); - tree.addCheckStateListener(new ICheckStateListener(){ - void addOrRemoveSelection(Node node, boolean add) { - if (add) - selectedNodes.add(node); - else - selectedNodes.remove(node); - } - void addOrRemoveSelectionRec(Node node, boolean add) { - addOrRemoveSelection(node, add); - for (Node child : node.getChildren()) - addOrRemoveSelectionRec(child, add); - } - @Override - public void checkStateChanged(CheckStateChangedEvent event) { - final boolean checked = event.getChecked(); - Node checkedNode = (Node) event.getElement(); - - Set nodes = new HashSet(); - Set selection = ISelectionUtils.filterSetSelection(tree.getSelection(), Node.class); - if (selection.contains(checkedNode)) - nodes.addAll(selection); - else - tree.setSelection(StructuredSelection.EMPTY); - nodes.add(checkedNode); - - for (Node node : nodes) { - addOrRemoveSelectionRec(node, checked); - -// tree.setSubtreeChecked(node, checked); -// The checked node is always either checked or not checked, never grayed. -// tree.setGrayed(node, checkStateProvider.isGrayed(node)); - -// Node parent = node.getParent(); -// if (parent != null) { -// tree.setChecked(parent, checkStateProvider.isChecked(parent)); -// tree.setGrayed(parent, checkStateProvider.isGrayed(parent)); -// } - } - - refreshAndExpandTree(); - validatePage(); - } - }); - - tree.setContentProvider(new ITreeContentProvider(){ - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - @Override - public void dispose() { - } - @Override - public Object[] getElements(Object inputElement) { - return exportModel.nodes.roots.toArray(); - } - @Override - public boolean hasChildren(Object element) { - Node n = (Node) element; - if (n.getChildren().isEmpty()) return false; - for (Node c : n.getChildren()) if (hasDiagram(c)) return true; - return false; - - } - @Override - public Object getParent(Object element) { - Node n = (Node) element; - return n.getParent(); - } - @Override - public Object[] getChildren(Object parentElement) { - Node n = (Node) parentElement; - List result = new ArrayList( n.getChildren().size() ); - for (Node c : n.getChildren()) - if (hasDiagram(c)) - result.add(c); - return result.toArray(); - } - - boolean hasDiagram(Node n) - { - if (n.getDiagramResource()!=null) return true; - for (Node c : n.getChildren()) if (hasDiagram(c)) return true; - return false; - } - }); - tree.setLabelProvider(new CellLabelProvider() { - @Override - public void update(ViewerCell cell) { - Object e = cell.getElement(); - if (e instanceof Node) { - Node n = (Node) e; - String name = DiagramPrinter.formDiagramName(n, false); - cell.setText(name); - - if (n.getDiagramResource() == null) - cell.setForeground(noDiagramColor); - else - cell.setForeground(null); - } else { - cell.setText("invalid input: " + e.getClass().getSimpleName()); - } - } - }); - tree.setComparator(new ViewerComparator(AlphanumComparator.CASE_INSENSITIVE_COMPARATOR)); - tree.setFilters(new ViewerFilter[] { - new ViewerFilter() { - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - if (matcher == null) - return true; - - Node node = (Node) element; - // If any children are in sight, show this element. - for (Node child : node.getChildren()) { - if (select(viewer, element, child)) - return true; - } - - return matcher.reset(node.getName().toLowerCase()).matches(); - } - } - }); - tree.setCheckStateProvider(checkStateProvider); - } - - Composite bar = new Composite(container, SWT.NONE); - GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(bar); - bar.setLayout(new RowLayout()); - Button selectAll = new Button(bar, SWT.PUSH); - selectAll.setText("Select &All"); - selectAll.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten()); - for (Node root : exportModel.nodes.roots) - tree.setSubtreeChecked(root, true); - validatePage(); - } - }); - Button clearSelection = new Button(bar, SWT.PUSH); - clearSelection.setText("&Clear Selection"); - clearSelection.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - selectedNodes.clear(); - for (Node root : exportModel.nodes.roots) - tree.setSubtreeChecked(root, false); - validatePage(); - } - }); - Button selectVisible = new Button(bar, SWT.PUSH); - selectVisible.setText("&Select Visible"); - selectVisible.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - selectedNodes.addAll(getVisibleNodes()); - refreshAndExpandTree(); - validatePage(); - } - }); - Button deselectVisible = new Button(bar, SWT.PUSH); - deselectVisible.setText("&Deselect Visible"); - deselectVisible.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - selectedNodes.removeAll(getVisibleNodes()); - refreshAndExpandTree(); - validatePage(); - } - }); + nodeTree = new NodeTree(container, selectedNodes); + GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(nodeTree); + nodeTree.setSelectionChangeListener(this::validatePage); toFileLabel = new Label(container, SWT.NONE); toFileLabel.setText("&To file:"); @@ -474,7 +203,7 @@ public class PDFExportPage extends WizardPage { } }); */ - + final Button attachWikiButton = new Button(container, SWT.CHECK); GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( attachWikiButton ); attachWikiButton.setText("Attach &Wiki page"); @@ -485,7 +214,18 @@ public class PDFExportPage extends WizardPage { exportModel.attachWiki = attachWikiButton.getSelection(); } }); - + + final Button addPageNumbers = new Button(container, SWT.CHECK); + GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo( addPageNumbers ); + addPageNumbers.setText("Add page &numbers"); + addPageNumbers.setSelection(exportModel.addPageNumbers); + addPageNumbers.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + exportModel.addPageNumbers = addPageNumbers.getSelection(); + } + }); + setControl(container); validatePage(); @@ -493,21 +233,14 @@ public class PDFExportPage extends WizardPage { } private void scheduleInitializeData(final NamedResource modelSelection) { - display.asyncExec(new Runnable() { - @Override - public void run() { - if (filter.isDisposed()) - return; - - try { + display.asyncExec(() -> { + try { + if (!nodeTree.isDisposed()) initializeData(modelSelection); - } catch (DatabaseException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.getTargetException().printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + } catch (DatabaseException | InterruptedException e) { + LOGGER.error("Input data initialization failed.", e); + } catch (InvocationTargetException e) { + LOGGER.error("Input data initialization failed.", e.getTargetException()); } }); } @@ -527,43 +260,9 @@ public class PDFExportPage extends WizardPage { exportLocation.addModifyListener(exportLocationListener); } - private Collection getVisibleNodes() { - Collection result = new ArrayList(); - - Deque todo = new ArrayDeque(); - for (TreeItem ti : tree.getTree().getItems()) { - todo.add(ti); - } - - while (!todo.isEmpty()) { - TreeItem item = todo.removeLast(); - Node node = (Node) item.getData(); - result.add(node); - - for (TreeItem child : item.getItems()) { - todo.add(child); - } - } - - return result; - } - - private void resetFilterString(String filterString) { - String patternString = filterStrategy.toPatternString(filterString); - if (patternString == null) { - matcher = null; - } else { - matcher = Pattern.compile(patternString).matcher(""); - } - refreshAndExpandTree(); - } - - private void refreshAndExpandTree() { - tree.refresh(); - tree.expandAll(); - } - private void initializeData(final NamedResource modelSelection) throws DatabaseException, InvocationTargetException, InterruptedException { + Set toBeSelected = new HashSet<>(); + if (modelSelection != null) { // Process input selection to find the model/state selected by default. @@ -573,29 +272,54 @@ public class PDFExportPage extends WizardPage { // !PROFILE long time = System.nanoTime(); - getWizard().getContainer().run(true, true, new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - final SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100); - exportModel.sessionContext.getSession().syncRequest(new ReadRequest() { - @Override - public void run(ReadGraph graph) throws DatabaseException { - exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() }); + getWizard().getContainer().run(true, true, monitor -> { + try { + SubMonitor mon = SubMonitor.convert(monitor, "Searching for exportable diagrams...", 100); + exportModel.sessionContext.getSession().syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + CollectionResult coll = exportModel.nodes = DiagramPrinter.browse(mon.newChild(100), graph, new Resource[] { modelSelection.getResource() }); + + // Decide initial selection based on exportModel.initialSelection + if (modelSelection.equals(exportModel.initialModelSelection)) { + Set selectedResources = new HashSet<>(); + for (Object o : exportModel.initialSelection.toList()) { + Resource r = ResourceAdaptionUtils.toSingleResource(o); + if (r != null) + selectedResources.add(r); + } + coll.walkTree(node -> { + if (node.getDiagramResource() != null) { + if (Nodes.parentIsInSet(toBeSelected, node)) + toBeSelected.add(node); + else + for (Resource r : node.getDefiningResources()) + if (selectedResources.contains(r)) + toBeSelected.add(node); + } + return true; + }); } - }); - } catch (DatabaseException e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } + + // Filter out any excess nodes from the tree. + exportModel.nodes = coll = coll.withRoots(Nodes.depthFirstFilter(Nodes.DIAGRAM_RESOURCE_PREDICATE, coll.roots)); + + // Select all if initial selection doesn't dictate anything. + if (toBeSelected.isEmpty()) + toBeSelected.addAll(coll.breadthFirstFlatten(CollectionResult.DIAGRAM_RESOURCE_FILTER)); + } + }); + } catch (DatabaseException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); } }); // !PROFILE long endTime = System.nanoTime(); if (exportModel.nodes != null) - System.out.println("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds."); + LOGGER.info("Found " + exportModel.nodes.diagrams.size() + " diagrams in " + ((endTime - time)*1e-9) + " seconds."); } // Browsing was canceled by user. @@ -604,15 +328,10 @@ public class PDFExportPage extends WizardPage { // Setup selected states, select everything by default. selectedNodes.clear(); - selectedNodes.addAll(exportModel.nodes.breadthFirstFlatten()); - - tree.setInput(this); + selectedNodes.addAll(toBeSelected); - for (Node root : exportModel.nodes.roots) { - tree.setSubtreeChecked(root, true); - } - - resetFilterString(filter.getText()); + // Fully refresh node tree + nodeTree.setInput(exportModel.nodes); modelSelector.removeSelectionListener(modelSelectorListener); int selectedIndex = -1; @@ -632,8 +351,16 @@ public class PDFExportPage extends WizardPage { } void validatePage() { + int diagramCount = 0; + Node singleDiagram = null; + for (Node n : selectedNodes) + if (n.getDiagramResource() != null) { + ++diagramCount; + singleDiagram = n; + } + //System.out.println("VALIDATE PAGE: " + exportLocationTouchedByUser); - if (selectedNodes.size() == 0) { + if (diagramCount == 0) { setMessage("Select the diagrams to export."); setErrorMessage(null); setPageComplete(false); @@ -645,8 +372,8 @@ public class PDFExportPage extends WizardPage { // Generate file name automatically if user hasn't touched the name manually. NamedResource nr = getSelectedModel(); if (nr != null) { - if (selectedNodes.size() == 1) { - generatedName = nr.getName() + "-" + selectedNodes.iterator().next().getName(); + if (diagramCount == 1 && singleDiagram != null) { + generatedName = nr.getName() + "-" + singleDiagram.getName(); } else { generatedName = nr.getName(); } @@ -701,11 +428,6 @@ public class PDFExportPage extends WizardPage { } exportModel.exportLocation = file; - int diagramCount = 0; - for (Node n : selectedNodes) - if (n.getDiagramResource() != null) - ++diagramCount; - String msg = diagramCount + " diagrams selected for export."; setMessage(msg); diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java index a41715f3b..73e5b09d2 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java @@ -19,6 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.eclipse.jface.viewers.IStructuredSelection; import org.simantics.db.common.NamedResource; import org.simantics.db.management.ISessionContext; import org.simantics.export.core.pdf.PageNumbering; @@ -31,6 +32,8 @@ public class PDFExportPlan { // Input public ISessionContext sessionContext; public IProject project; + public IStructuredSelection initialSelection; + public NamedResource initialModelSelection; public List selectableModels = new ArrayList(); public NamedResource selection; public Collection recentLocations; diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/Preferences.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/Preferences.java index f248ca2fa..97265df58 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/Preferences.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/Preferences.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - page numbering additions *******************************************************************************/ package org.simantics.modeling.ui.pdf; @@ -21,6 +22,6 @@ public interface Preferences { String DIAGRAM_EXPORT_PDF_ZOOM_TO_FIT = "diagram.export.pdf.zoomToFit"; String DIAGRAM_EXPORT_PDF_ATTACH_TG = "diagram.export.pdf.attachTG"; String DIAGRAM_EXPORT_PDF_ATTACH_WIKI = "diagram.export.pdf.attachWiki"; - + String DIAGRAM_EXPORT_PDF_ADD_PAGE_NUMBERS = "diagram.export.pdf.addPageNumbers"; } diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/ModelImportWizard.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/ModelImportWizard.java index 235c304e6..9f9dc489e 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/ModelImportWizard.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/ModelImportWizard.java @@ -34,11 +34,10 @@ import org.eclipse.ui.IWorkbench; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.simantics.Simantics; import org.simantics.databoard.binding.Binding; -import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.container.DataContainer; import org.simantics.databoard.container.DataContainers; import org.simantics.databoard.container.FormatHandler; -import org.simantics.databoard.util.binary.BinaryFile; +import org.simantics.databoard.util.URIStringUtils; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.layer0.migration.MigratedImportResult; @@ -46,7 +45,6 @@ import org.simantics.db.layer0.migration.MigrationState; import org.simantics.db.layer0.migration.MigrationStateKeys; import org.simantics.db.layer0.migration.MigrationUtils; import org.simantics.db.layer0.migration.ModelImportAdvisor; -import org.simantics.db.layer0.util.DraftStatusBean; import org.simantics.db.management.ISessionContext; import org.simantics.graph.db.ImportResult; import org.simantics.graph.db.MissingDependencyException; @@ -153,7 +151,7 @@ public class ModelImportWizard extends Wizard implements IImportWizard { if (result[0].hasMissingExternals()) { InfoDialog.open(getShell(), "Missing Externals Created", "The system was unable to find some of the external entities referenced by the imported material. Place-holders have been created for the missing entities.\nThe missing entities are:\n" - + EString.implode(result[0].tgResult.missingExternals), + + URIStringUtils.unescape(EString.implode(result[0].tgResult.missingExternals)), SWT.SHEET); } } catch (InvocationTargetException e) { diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/SharedOntologyImportWizard.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/SharedOntologyImportWizard.java index df6564634..8345c229e 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/SharedOntologyImportWizard.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/SharedOntologyImportWizard.java @@ -36,6 +36,7 @@ import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.container.DataContainer; import org.simantics.databoard.container.DataContainers; import org.simantics.databoard.container.FormatHandler; +import org.simantics.databoard.util.URIStringUtils; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.layer0.migration.MigratedImportResult; @@ -146,7 +147,7 @@ public class SharedOntologyImportWizard extends Wizard implements IImportWizard if (result[0].hasMissingExternals()) { InfoDialog.open(getShell(), "Missing Externals Created", "The system was unable to find some of the external entities referenced by the imported material. Place-holders have been created for the missing entities.\nThe missing entities are:\n" - + EString.implode(result[0].tgResult.missingExternals), + + URIStringUtils.unescape(EString.implode(result[0].tgResult.missingExternals)), SWT.SHEET); } } catch (InvocationTargetException e) { diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionRequest.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionRequest.java index 70aa8c88b..183717325 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionRequest.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionRequest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,6 @@ import org.simantics.db.Resource; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.utils.NameUtils; -import org.simantics.db.exception.AdaptionException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.request.Read; import org.simantics.diagram.query.DiagramRequests; @@ -69,22 +68,6 @@ public class CollectionRequest implements Read { return g.syncRequest(new GetName(r)); } -// Collection getPartOfGroups(Resource diagram) throws DatabaseException { -// Resource r = diagram; -// Deque result = new ArrayDeque(); -// loop: -// while (true) { -// for (Resource partOf : g.getObjects(r, b.PartOf)) { -// if (g.isInstanceOf(partOf, dr.DiagramLibrary)) { -// result.addFirst(safeGetName(partOf)); -// r = partOf; -// continue loop; -// } -// } -// return result; -// } -// } - @Override public CollectionResult perform(ReadGraph g) throws DatabaseException { this.g = g; @@ -96,53 +79,22 @@ public class CollectionRequest implements Read { SIMU = SimulationResource.getInstance(g); final CollectionResult result = new CollectionResult(); - final Deque roots = new ArrayDeque(); + final Deque roots = new ArrayDeque<>(); // 1. Based on input, look for the proper nodes to start browsing for diagrams. for (Resource r : input) { - /*if (g.isInstanceOf(r, SIMU.Model)) { - // Complete models - Resource composite = g.getPossibleObject(r, SIMU.HasConfiguration); - Resource diagram = composite != null ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null; - - if (DEBUG) - System.out.println("Model root"); - - if (composite != null) { - Node node = new Node(null, safeGetName(r), diagram, composite, r); - roots.add(node); - result.roots.add(roots.peekLast()); - } - } else*/ if (g.isInstanceOf(r, l0.IndexRoot)) { -// for(Resource type : ModelingUtils.searchByTypeShallow(g, r, sr.ComponentType)) { -// Resource composite = g.getPossibleObject(type, sr.IsDefinedBy); -// Resource diagram = composite != null ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null; -// if(composite != null) { -// Node node = new Node(null, safeGetName(r), diagram, composite, r); -// roots.add(node); -// result.roots.add(roots.peekLast()); -// } -// } - - Node node = new Node(null, safeGetName(r), null, r); - roots.add(node); - result.roots.add(roots.peekLast()); - + if (g.isInstanceOf(r, l0.IndexRoot)) { + Node node = new Node(null, safeGetName(r), null, r); + roots.add(node); + result.roots.add(roots.peekLast()); } else if (g.isInstanceOf(r, sr.Composite)) { // The contents of components String name = null; Resource model = g.getPossibleObject(r, SIMU.IsConfigurationOf); - //Resource componentType = g.getPossibleObject(r, sr.Defines); if (model != null) { name = safeGetName(model); - if (DEBUG) System.out.println("Configuration root: " + name); - -// } else if (componentType != null) { -// Resource singleInstance = componentType != null ? g.getPossibleObject(componentType, b.HasSingleInstance) : null; -// name = singleInstance != null ? safeGetName(singleInstance) : safeGetName(componentType); -// System.out.println("Composite of component type root: " + name); } else { name = safeGetName(r); if (DEBUG) @@ -153,19 +105,10 @@ public class CollectionRequest implements Read { diagram = (diagram != null && g.isInstanceOf(diagram, dr.Composite)) ? diagram : null; { - Node node = new Node(null, name, diagram, r); - roots.add(node); - result.roots.add(roots.peekLast()); + Node node = new Node(null, name, diagram, r); + roots.add(node); + result.roots.add(roots.peekLast()); } -// } else if (g.isInstanceOf(r, sr.Component)) { -// // Complete components themselves -// Resource componentType = g.getSingleType(r, sr.Component); -// Resource composite = g.getPossibleObject(componentType, sr.IsDefinedBy); -// Resource diagram = (composite != null && g.isInstanceOf(composite, sr.Composite)) ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null; -// String name = safeGetName(r); -// System.out.println("Component root: " + name); -// roots.add(new Node(null, name, diagram, composite, r)); -// result.roots.add(roots.peekLast()); } else if (g.isInheritedFrom(r, dr.DefinedElement)) { // Symbols Resource composite = g.getPossibleObject(r, sr.IsDefinedBy); @@ -176,21 +119,13 @@ public class CollectionRequest implements Read { name += " Symbol"; if (DEBUG) System.out.println("Symbol root: " + name); - - { - Node node = new Node(null, name, composite, r); - roots.add(node); - result.roots.add(roots.peekLast()); + + { + Node node = new Node(null, name, composite, r); + roots.add(node); + result.roots.add(roots.peekLast()); } } -// } else if (g.isInheritedFrom(r, sr.Component)) { -// // Reusable component types -// Resource composite = g.getPossibleObject(r, sr.IsDefinedBy); -// Resource diagram = (composite != null && g.isInstanceOf(composite, sr.Composite)) ? g.getPossibleObject(composite, mr.CompositeToDiagram) : null; -// String name = safeGetName(r); -// System.out.println("Component type root: " + name); -// roots.add(new Node(null, name, diagram, r, composite)); -// result.roots.add(roots.peekLast()); } } @@ -206,35 +141,41 @@ public class CollectionRequest implements Read { private void loadComposites(ReadGraph graph, final Node node) throws DatabaseException { Resource diagram = node.getDiagramResource(); - //System.out.println("loadComposites(" + diagram + ", " + node + ")"); - if (diagram != null) { + if (DEBUG) + System.out.println("loadComposites(" + diagram + ", " + node + ")"); + if (diagram != null) result.addDiagram(diagram, node); -// node.setPartOfGroups(getPartOfGroups(diagram)); - } mon.setWorkRemaining(1000); for(Resource r : graph.getObjects(node.getDefiningResources().resources[0], l0.ConsistsOf)) { - if(graph.isInstanceOf(r, sr.Composite)) { - String compositeName = graph.syncRequest(new GetName(r)); - Resource definingDiagram = graph.getPossibleObject(r, mr.CompositeToDiagram); - Node n = new Node(node, compositeName, definingDiagram, r); + if(graph.isInstanceOf(r, sr.Composite)) { + String compositeName = graph.syncRequest(new GetName(r)); + Resource definingDiagram = graph.getPossibleObject(r, mr.CompositeToDiagram); + Node n = new Node(node, compositeName, definingDiagram, r); + if (DEBUG) + System.out.println("Found composite: " + n); loadComposites(graph, n); mon.worked(1); - } else if (graph.isInstanceOf(r, l0.Library)) { - String compositeName = graph.syncRequest(new GetName(r)); - Node n = new Node(node, compositeName, null, r); + } else if (graph.isInstanceOf(r, l0.Library)) { + String compositeName = graph.syncRequest(new GetName(r)); + Node n = new Node(node, compositeName, null, r); + if (DEBUG) + System.out.println("Found library: " + n); loadComposites(graph, n); mon.worked(1); - } else if (graph.isInheritedFrom(r, sr.Component)) { - String name = safeGetName(r); - Node n = new Node(node, name, null, r); - loadComposites(graph, n); - mon.worked(1); - } + } else if (graph.isInheritedFrom(r, sr.Component)) { + Resource definedBy = graph.getPossibleObject(r, sr.IsDefinedBy); + if (definedBy == null) + continue; + String name = safeGetName(r); + Node n = new Node(node, name, null, r); + if (DEBUG) + System.out.println("Found component: " + n); + loadComposites(graph, n); + mon.worked(1); + } } - } - }); ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID)); @@ -263,9 +204,8 @@ public class CollectionRequest implements Read { return result; } - - static class GetName extends ResourceRead { + static class GetName extends ResourceRead { public GetName(Resource resource) { super(resource); } @@ -274,11 +214,10 @@ public class CollectionRequest implements Read { public String perform(ReadGraph graph) throws DatabaseException { try { return NameLabelUtil.modalName(graph, resource); - } catch (AdaptionException e) { + } catch (DatabaseException e) { return NameUtils.getSafeName(graph, resource); } } - } } \ No newline at end of file diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionResult.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionResult.java index ff06e43d0..c182c59c8 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionResult.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionResult.java @@ -29,6 +29,9 @@ import org.simantics.scl.runtime.function.Function1; */ public class CollectionResult { + public static final IFilter DIAGRAM_RESOURCE_FILTER = o -> Nodes.DIAGRAM_RESOURCE_PREDICATE.test((Node) o); + public static final IFilter DIAGRAM_RESOURCE_AND_RVI_FILTER = o -> Nodes.DIAGRAM_RESOURCE_AND_RVI_PREDICATE.test((Node) o); + public class DiagramFilter implements IFilter { private final IFilter proxy; @@ -44,10 +47,28 @@ public class CollectionResult { } - final public Set roots = new ConcurrentSkipListSet(); - final private Set diagramSet = new ConcurrentSkipListSet(); - final public List diagramList = new Vector(); - final public Map diagrams = new ConcurrentHashMap(); + public final Set roots; + private final Set diagramSet; + public final List diagramList; + public final Map diagrams; + + public CollectionResult() { + this.roots = new ConcurrentSkipListSet(); + this.diagramSet = new ConcurrentSkipListSet(); + this.diagramList = new Vector(); + this.diagrams = new ConcurrentHashMap(); + } + + private CollectionResult(Set roots, Set diagramSet, List diagramList, Map diagrams) { + this.roots = roots; + this.diagramSet = diagramSet; + this.diagramList = diagramList; + this.diagrams = diagrams; + } + + public CollectionResult withRoots(Set roots) { + return new CollectionResult(roots, diagramSet, diagramList, diagrams); + } public void addDiagram(Resource r, Node n) { diagramList.add(n); diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Node.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Node.java index 3d52b2604..4a43e0840 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Node.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Node.java @@ -27,15 +27,12 @@ import org.simantics.utils.strings.AlphanumComparator; */ public class Node implements Comparable { - public static final Comparator CASE_INSENSITIVE_COMPARATOR = new Comparator() { - @Override - public int compare(Node o1, Node o2) { - return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName()); - } - }; + public static final Comparator CASE_INSENSITIVE_COMPARATOR = + (o1, o2) -> AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName()); private final Node parent; private final List children = new ArrayList(); + private final List unmodifiableChildren = Collections.unmodifiableList(children); /** * May be null if there is no diagram for this node. @@ -44,10 +41,8 @@ public class Node implements Comparable { private final ResourceArray definingResource; // i.e. Composite private final String name; -// private String[] partOfGroups = {}; - private PageDesc pageDesc; - private String RVI; + private String rvi; /** * @param parent @@ -67,6 +62,13 @@ public class Node implements Comparable { parent.addChild(this); } + public Node cloneWithoutChildren(Node parent) { + Node clone = new Node(parent, name, diagram, definingResource.resources); + clone.setRVI(rvi); + clone.setPageDesc(pageDesc); + return clone; + } + public Node getParent() { return parent; } @@ -100,27 +102,19 @@ public class Node implements Comparable { } public Collection getChildren() { - return Collections.unmodifiableCollection(children); + return unmodifiableChildren; } -// public void setPartOfGroups(Collection groups) { -// this.partOfGroups = groups.toArray(new String[groups.size()]); -// } -// -// public String[] getPartOfGroups() { -// return partOfGroups; -// } - public void setPageDesc(PageDesc pageDesc) { this.pageDesc = pageDesc; } - public void setRVI(String RVI) { - this.RVI = RVI; + public void setRVI(String rvi) { + this.rvi = rvi; } public String getRVI() { - return RVI; + return rvi; } public PageDesc getPageDesc() { diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Nodes.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Nodes.java index 01c89aaf1..5d1da8797 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Nodes.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Nodes.java @@ -7,6 +7,9 @@ import java.util.Collections; import java.util.Comparator; import java.util.Deque; import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.Predicate; import org.eclipse.jface.viewers.IFilter; import org.simantics.scl.runtime.function.Function1; @@ -16,14 +19,17 @@ import org.simantics.scl.runtime.function.Function1; */ public class Nodes { + public static final Predicate DIAGRAM_RESOURCE_PREDICATE = n -> n.getDiagramResource() != null; + public static final Predicate DIAGRAM_RESOURCE_AND_RVI_PREDICATE = n -> n.getDiagramResource() != null && n.getRVI() != null; + public static Collection breadthFirstFlatten(IFilter filter, Collection roots) { - Collection result = new ArrayList(); - List sortedRoots = new ArrayList(roots); + Collection result = new ArrayList<>(); + List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots); - Deque todo = new ArrayDeque(sortedRoots); + Deque todo = new ArrayDeque<>(sortedRoots); while (!todo.isEmpty()) { Node n = todo.removeFirst(); - List sorted = new ArrayList(n.getChildren()); + List sorted = new ArrayList<>(n.getChildren()); Collections.sort(sorted); todo.addAll(sorted); if (filter == null || filter.select(n)) @@ -33,8 +39,8 @@ public class Nodes { } public static Collection depthFirstFlatten(IFilter filter, Collection roots, Comparator comparator) { - Collection result = new ArrayList(); - List sortedRoots = new ArrayList(roots); + Collection result = new ArrayList<>(); + List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots, comparator); for (Node n : sortedRoots) { depthFirstFlattenRec(filter, comparator, n, result); @@ -50,7 +56,7 @@ public class Nodes { if (children.isEmpty()) return result; - List sorted = new ArrayList(children); + List sorted = new ArrayList<>(children); Collections.sort(sorted, comparator); for (Node child : sorted) depthFirstFlattenRec(filter, comparator, child, result); @@ -67,7 +73,7 @@ public class Nodes { * if the walk was cancelled */ public static boolean walkTree(Function1 filter, Collection roots) { - List sortedRoots = new ArrayList(roots); + List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots); for (Node n : sortedRoots) if (!walkTreeRec(filter, n)) @@ -81,7 +87,7 @@ public class Nodes { Collection children = n.getChildren(); if (!children.isEmpty()) { - List sorted = new ArrayList(children); + List sorted = new ArrayList<>(children); Collections.sort(sorted); for (Node child : sorted) if (!walkTreeRec(filter, child)) @@ -90,4 +96,41 @@ public class Nodes { return true; } + public static boolean parentIsInSet(Set set, Node node) { + for (Node n = node.getParent(); n != null; n = n.getParent()) + if (set.contains(n)) + return true; + return false; + } + + public static Set depthFirstFilter(Predicate filter, Collection nodes) { + Set result = new TreeSet<>(Node.CASE_INSENSITIVE_COMPARATOR); + for (Node n : nodes) { + Node newNode = depthFirstFilterRec(filter, n, null); + if (newNode != null) + result.add(newNode); + } + return result; + } + + public static Node depthFirstFilter(Predicate filter, Node n) { + return depthFirstFilterRec(filter, n, null); + } + + private static Node depthFirstFilterRec(Predicate filter, Node n, Node newParent) { + Collection children = n.getChildren(); + if (children.isEmpty()) + return filter.test(n) ? n.cloneWithoutChildren(newParent) : null; + + Node newNode = n.cloneWithoutChildren(newParent); + int childCount = 0; + for (Node child : children) { + Node newChild = depthFirstFilterRec(filter, child, newNode); + if (newChild != null) + ++childCount; + } + + return childCount > 0 ? newNode : null; + } + } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java index a8f3d2045..d7f1aa11e 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java @@ -11,7 +11,6 @@ import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -43,6 +42,7 @@ import org.simantics.scl.compiler.module.ImportDeclaration; import org.simantics.scl.compiler.module.repository.ImportFailure; import org.simantics.scl.compiler.module.repository.ImportFailureException; import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.runtime.RuntimeEnvironment; import org.simantics.scl.compiler.top.ExpressionEvaluator; import org.simantics.scl.compiler.top.LocalStorage; @@ -76,6 +76,7 @@ public class CommandSession { THashMap variableTypes = new THashMap(); PrintStream fileOutput; + private UpdateListener dependenciesListener; /** * Only checks the commands for compilation errors but does not run them. @@ -108,10 +109,13 @@ public class CommandSession { runtimeEnvironment = null; try { + if(dependenciesListener != null) + dependenciesListener.stopListening(); try { runtimeEnvironment = moduleRepository.createRuntimeEnvironment( environmentSpecification, - getClass().getClassLoader()); + getClass().getClassLoader(), + dependenciesListener); } catch(ImportFailureException e) { THashSet failedModules = new THashSet(); for(ImportFailure failure : e.failures) { @@ -129,7 +133,7 @@ public class CommandSession { try { runtimeEnvironment = moduleRepository.createRuntimeEnvironment( environmentSpecification, - getClass().getClassLoader()); + getClass().getClassLoader()); // no listener here, because should listen also failed modules } catch (ImportFailureException e1) { for(ImportFailure failure : e1.failures) defaultHandler.printError(failure.toString()); @@ -665,4 +669,7 @@ public class CommandSession { return validate(new StringReader(command)); } + public void setDependenciesListener(UpdateListener dependenciesListener) { + this.dependenciesListener = dependenciesListener; + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java index 80acf17c5..0ab17f834 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java @@ -12,6 +12,7 @@ public class ModuleHeader { public long classLoaderLocation; public String defaultLocalName; public List export; + // Features public boolean chr; public boolean fields; @@ -32,37 +33,47 @@ public class ModuleHeader { break; case "export": if(assignment.value == null) - errorLog.log(assignment.location, "Property export needs to be given a string list value."); + errorLog.log(assignment.location, "Property export needs to be given a list of exported symbols."); else { export = AnnotationUtils.extractIdentifierList(assignment.value); if(export == null) - errorLog.log(assignment.value.location, "Expected a list of exported items."); + errorLog.log(assignment.value.location, "Expected a list of exported symbols."); + } + break; + case "features": + if(assignment.value == null) + errorLog.log(assignment.location, "Property features needs to be given a list of features (identifiers)."); + else { + List features = AnnotationUtils.extractIdentifierList(assignment.value); + if(features == null) + errorLog.log(assignment.value.location, "Expected a list of features (identifiers)."); + for(EVar feature : features) + handleFeature(errorLog, feature); } break; case "defaultLocalName": - if(assignment.value == null) + if(assignment.value == null) errorLog.log(assignment.location, "Property defaultLocalName needs to be given a string value."); - else { - defaultLocalName = AnnotationUtils.extractString(assignment.value); - if(defaultLocalName == null) - errorLog.log(assignment.value.location, "Expected string here."); - } - break; - case "fields": - if(assignment.value != null) - errorLog.log(assignment.location, "No value expected for property fields."); - this.fields = true; + else { + defaultLocalName = AnnotationUtils.extractString(assignment.value); + if(defaultLocalName == null) + errorLog.log(assignment.value.location, "Expected string here."); + } break; - case "chr": - if(assignment.value != null) - errorLog.log(assignment.location, "No value expected for property chr."); - this.chr = true; - break; default: errorLog.logWarning(assignment.location, "Unknown module header field was skipped."); } } + private void handleFeature(ErrorLog errorLog, EVar feature) { + switch(feature.name) { + case "chr": chr = true; break; + case "fields": fields = true; break; + default: + errorLog.log(feature.location, "Unknown feature " + feature.name + "."); + } + } + public static ModuleHeader process(ErrorLog errorLog, FieldAssignment[] fields) { if(fields == null) return null; diff --git a/bundles/org.simantics.scl.db/scl/Simantics/DB.scl b/bundles/org.simantics.scl.db/scl/Simantics/DB.scl index 19e83d30b..df556086e 100644 --- a/bundles/org.simantics.scl.db/scl/Simantics/DB.scl +++ b/bundles/org.simantics.scl.db/scl/Simantics/DB.scl @@ -343,7 +343,7 @@ importJava "org.simantics.db.layer0.util.Layer0Utils" where listOntologies :: () -> [Resource] emptyTrashBin :: () -> () purgeDatabase :: () -> () - prettyPrintResource :: Resource -> String + prettyPrintResource :: Resource -> Boolean -> String @private @JavaName copyTo diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java index cb2181912..a7eb43323 100644 --- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java +++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java @@ -10,6 +10,8 @@ import java.util.List; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuCreator; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.preference.IPersistentPreferenceStore; @@ -20,11 +22,17 @@ import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.simantics.scl.compiler.commands.CommandSessionImportEntry; import org.simantics.scl.compiler.commands.SCLConsoleListener; +import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.testing.TestRunnable; import org.simantics.scl.osgi.internal.TestUtils; import org.simantics.scl.ui.Activator; @@ -35,13 +43,16 @@ public class SCLConsoleView extends ViewPart { public static final String PLUGIN_ID = "org.simantics.scl.ui"; public static final String IMPORTS = "imports"; + public static final String REFRESH_AUTOMATICALLY = "refresh-automatically"; public static final String SEPARATOR = ";"; public static final String DISABLED_TAG = "[DISABLED]"; + IPersistentPreferenceStore store; SCLConsole console; + boolean refreshAutomatically = false; + MenuItem refreshAutomaticallyItem; private ArrayList readImportPreferences() { - IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID); String importsString = store.getString(IMPORTS); String[] splitted = importsString.split(SEPARATOR); @@ -86,7 +97,7 @@ public class SCLConsoleView extends ViewPart { } IPersistentPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID); - store.putValue(IMPORTS, b.toString()); + store.setValue(IMPORTS, b.toString()); } private ArrayList getCurrentImports() { @@ -127,10 +138,39 @@ public class SCLConsoleView extends ViewPart { } } } + + private UpdateListener dependencyListener = new UpdateListener() { + @Override + public void notifyAboutUpdate() { + if(refreshAutomatically) + console.getSession().updateRuntimeEnvironment(true); + } + }; + private void setRefreshAutomatically(boolean refreshAutomatically, boolean refreshAlso) { + this.refreshAutomatically = refreshAutomatically; + if(refreshAutomaticallyItem != null) + refreshAutomaticallyItem.setSelection(refreshAutomatically); + + store.setValue(REFRESH_AUTOMATICALLY, refreshAutomatically); + + if(refreshAutomatically) { + console.getSession().setDependenciesListener(dependencyListener); + if(refreshAlso) + console.getSession().updateRuntimeEnvironment(true); + } + else { + console.getSession().setDependenciesListener(null); + dependencyListener.stopListening(); + } + } + @Override public void createPartControl(Composite parent) { + store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PLUGIN_ID); this.console = new SCLConsole(parent, SWT.NONE); + + setRefreshAutomatically(store.getBoolean(REFRESH_AUTOMATICALLY), false); setCurrentImports(readImportPreferences()); addScriptDropSupport(console); @@ -179,8 +219,40 @@ public class SCLConsoleView extends ViewPart { }); // Refresh action - toolBarManager.add(new Action("Refresh modules", - Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/arrow_refresh.png")) { + toolBarManager.add(new Action("Refresh modules", IAction.AS_DROP_DOWN_MENU) { + { + setImageDescriptor(Activator.imageDescriptorFromPlugin("org.simantics.scl.ui", "icons/arrow_refresh.png")); + setMenuCreator(new IMenuCreator() { + Menu menu; + @Override + public Menu getMenu(Menu parent) { + throw new UnsupportedOperationException(); + } + + @Override + public Menu getMenu(Control parent) { + if(menu == null) { + menu = new Menu(parent); + refreshAutomaticallyItem = new MenuItem(menu, SWT.CHECK); + refreshAutomaticallyItem.setText("Refresh automatically"); + refreshAutomaticallyItem.setSelection(refreshAutomatically); + refreshAutomaticallyItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setRefreshAutomatically(!refreshAutomatically, true); + } + }); + } + return menu; + } + + @Override + public void dispose() { + if(menu != null) + menu.dispose(); + } + }); + } @Override public void run() { console.getSession().getModuleRepository().getSourceRepository().checkUpdates(); diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/modulebrowser/ModuleNameTreeEntry.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/modulebrowser/ModuleNameTreeEntry.java index 4c3bf1a2c..2461e5231 100644 --- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/modulebrowser/ModuleNameTreeEntry.java +++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/modulebrowser/ModuleNameTreeEntry.java @@ -2,11 +2,13 @@ package org.simantics.scl.ui.modulebrowser; import java.util.Arrays; import java.util.Iterator; -import java.util.Map.Entry; import gnu.trove.map.hash.THashMap; public class ModuleNameTreeEntry implements Comparable { + public static final String STANDARD_LIBRARY = "StandardLibrary"; + public static final String HTTP_PREFIX = "http://"; + public final ModuleNameTreeEntry parent; public final String fullName; public final String name; @@ -21,11 +23,20 @@ public class ModuleNameTreeEntry implements Comparable { public void addModule(String moduleFullName) { int startingPos = fullName.isEmpty() ? 0 : fullName.length()+1; - int p = moduleFullName.indexOf('/', startingPos); + int p; + if(parent == null && moduleFullName.startsWith(HTTP_PREFIX)) + p = moduleFullName.indexOf('/', HTTP_PREFIX.length()); + else + p = moduleFullName.indexOf('/', startingPos); if(p == -1) { - String name = moduleFullName.substring(startingPos); - ModuleNameTreeEntry entry = getOrCreateChildMapEntry(name); - entry.isModule = true; + if(parent == null) { + getOrCreateChildMapEntry(STANDARD_LIBRARY).addModule(name); + } + else { + String name = moduleFullName.substring(startingPos); + ModuleNameTreeEntry entry = getOrCreateChildMapEntry(name); + entry.isModule = true; + } } else { String name = moduleFullName.substring(startingPos, p); @@ -37,7 +48,15 @@ public class ModuleNameTreeEntry implements Comparable { private ModuleNameTreeEntry getOrCreateChildMapEntry(String name) { ModuleNameTreeEntry entry = childMap.get(name); if(entry == null) { - String newFullName = fullName.isEmpty() ? name : fullName + "/" + name; + String newFullName; + if(parent == null) { + if(name.equals(STANDARD_LIBRARY)) + newFullName = ""; + else + newFullName = name; + } + else + newFullName = fullName + "/" + name; entry = new ModuleNameTreeEntry(this, newFullName, name); childMap.put(name, entry); } diff --git a/bundles/org.simantics.tests.modelled/META-INF/MANIFEST.MF b/bundles/org.simantics.tests.modelled/META-INF/MANIFEST.MF index 8f1829479..4cbcec294 100644 --- a/bundles/org.simantics.tests.modelled/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.tests.modelled/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Require-Bundle: org.simantics.tests.modelled.ontology, org.junit, org.simantics.modeling;bundle-version="1.1.1", org.slf4j.api, - org.simantics.db.testing + org.simantics.db.testing, + org.simantics.debug.browser;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Export-Package: org.simantics.tests.modelled, diff --git a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSRunner.java b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSRunner.java index 29628cec0..393174906 100644 --- a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSRunner.java +++ b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSRunner.java @@ -13,21 +13,30 @@ import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; import org.junit.runners.model.InitializationError; import org.simantics.Simantics; +import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.testing.common.AcornTests; import org.simantics.tests.modelled.utils.ModelledSTSSuite; import org.simantics.tests.modelled.utils.STSSuiteTestCollector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ModelledSTSRunner extends ParentRunner { + private static final Logger LOGGER = LoggerFactory.getLogger(ModelledSTSRunner.class); + + public static final String INCLUSION_FILTER = "org.simantics.tests.modelled.singleTestIncludeFilter"; public static final String EXCLUSION_FILTER = "org.simantics.tests.modelled.excludeFilter"; private final List children; public ModelledSTSRunner(Class testClass) throws InitializationError { super(testClass); + try { initialize0(); Collection suites = STSSuiteTestCollector.collectTests(); + + // Filter exclusions String exclusionFilter = System.getProperty(EXCLUSION_FILTER); Collection filtered; if (exclusionFilter != null) { @@ -36,7 +45,18 @@ public class ModelledSTSRunner extends ParentRunner { } else { filtered = suites; } + // Filter inclusions +// String inclusionFilter = System.getProperty(INCLUSION_FILTER); +// Collection included; +// if (inclusionFilter != null) { +// String[] filters = inclusionFilter.split(","); +// included = filtered.stream().filter(s -> startsWithAny(s, filters)).collect(Collectors.toList()); +// } else { +// included = filtered; +// } + // Sort by priority +// List sorted = included.stream().sorted((o1, o2) -> Integer.compare(o1.getPriority(), o2.getPriority())).collect(Collectors.toList()); List sorted = filtered.stream().sorted((o1, o2) -> Integer.compare(o1.getPriority(), o2.getPriority())).collect(Collectors.toList()); @@ -82,7 +102,12 @@ public class ModelledSTSRunner extends ParentRunner { @Override protected void runChild(ModelledSTSSuiteRunner child, RunNotifier notifier) { - child.run(notifier); + try { + child.run(notifier); + } finally { + // Clear query cache + Layer0Utils.queryDebugSupport("QueryControl.flush"); + } // TODO: Add coverage reporting to ModelledSTSRunner // CombinedCoverage cover = child.getCoverage(); // CoverageBuilder b = new CoverageBuilder(); @@ -96,11 +121,13 @@ public class ModelledSTSRunner extends ParentRunner { private void initialize0() throws Exception { AcornTests.newSimanticsWorkspace(null, null); + org.simantics.debug.browser.internal.Activator.getDefault().startDebugServer(); initialize(); } private void deinitialize0() throws Exception { deinitialize(); + org.simantics.debug.browser.internal.Activator.getDefault().stopDebugServer(); Simantics.shutdown(new NullProgressMonitor()); } } diff --git a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSSuiteRunner.java b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSSuiteRunner.java index 11931d824..0bfb1f1ce 100644 --- a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSSuiteRunner.java +++ b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSSuiteRunner.java @@ -25,11 +25,40 @@ public class ModelledSTSSuiteRunner extends ParentRunner super(ModelledSTSSuiteRunner.class); this.suite = suite; this.children = new ArrayList<>(suite.getChildren().size()); + + // Do possible filtering + // Filter exclusions + String exclusionFilter = System.getProperty(ModelledSTSRunner.EXCLUSION_FILTER); + // Filter inclusions + String inclusionFilter = System.getProperty(ModelledSTSRunner.INCLUSION_FILTER); for (ModelledSTSTest test : suite.getSortedChildren()) { - children.add(new ModelledSTSTestRunner(test)); + boolean add = true; + if (exclusionFilter != null) { + String[] filters = exclusionFilter.split(","); + if (startsWithAny(test, filters)) { + add = false; + } + } + if (inclusionFilter != null) { + String[] filters = inclusionFilter.split(","); + if (!startsWithAny(test, filters)) { + add = false; + } + } + if (add) + children.add(new ModelledSTSTestRunner(test)); } } + private static boolean startsWithAny(ModelledSTSTest test, String[] filters) { + for (String filter : filters) { + if (test.getName().contains(filter)) { + return true; + } + } + return false; + } + @Override protected String getName() { return suite.getName(); @@ -61,7 +90,8 @@ public class ModelledSTSSuiteRunner extends ParentRunner } notifier.fireTestStarted(description); List newVars = child.runWithVars(variables); - storedVariables.put(child.getTest().getName(), newVars); +// TODO: FIX THIS BY NOT ADDING ALL VARIABLES TO MEMORY (CAN BE HUGE) +// storedVariables.put(child.getTest().getName(), newVars); notifier.fireTestFinished(description); } catch (Throwable e) { notifier.fireTestFailure(new Failure(description, e)); diff --git a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java index 33e4c25e2..c0ed9b191 100644 --- a/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java +++ b/bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java @@ -94,6 +94,7 @@ public class ModelledSTSTest { public List run(List vars) throws IOException { ModuleRepository repo = new ModuleRepository(SCLOsgi.SOURCE_REPOSITORY); + CommandSession session = null; try { repo.setAdvisor(new ModuleCompilationOptionsAdvisor() { @@ -113,7 +114,7 @@ public class ModelledSTSTest { }); SCLReportingHandler handler = (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); - CommandSession session = new CommandSession(repo, handler); + session = new CommandSession(repo, handler); for (CommandSessionVariable var : vars) session.setVariable(var.getName(), var.getType(), var.getValue()); diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR10.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR10.scl index 758074d32..8f587d508 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR10.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR10.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" data V = V { x :: Double, y :: Double } @@ -17,7 +17,7 @@ main = () 4.0 () -- -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" data V = V { x :: Double, y :: Double } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl index c59c02dbb..6803c113e 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" ruleset IntegerSet where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl index f1e28d08a..76f0408a0 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" ruleset RS where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl index b10257ca8..6e878ebf4 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" ruleset RS where diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl index c3a88f58a..dd915ebb5 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" main = () diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl index 07514821a..427b8df6b 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl @@ -1,4 +1,4 @@ -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" main = () @@ -10,7 +10,7 @@ main = () 1.0 () -- -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" main = () @@ -20,7 +20,7 @@ main = () -- 7:13-7:26: Field y not defined. -- -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" @@ -31,7 +31,7 @@ main = () -- 8:13-8:35: Relation V does not define field names. -- -module { export = [main], chr } +module { export = [main], features = [chr] } import "StandardLibrary" diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record2.scl index de71cf487..352336ff3 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record2.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record2.scl @@ -1,5 +1,5 @@ module { - fields + features = [fields] } import "Prelude"