]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Merge "Default property editing restores assertions"
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 16 Jun 2017 07:09:47 +0000 (10:09 +0300)
committerGerrit Code Review <gerrit2@www.simantics.org>
Fri, 16 Jun 2017 07:09:47 +0000 (10:09 +0300)
34 files changed:
bundles/org.simantics.databoard/src/org/simantics/databoard/util/URIUtil.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/Layer0Utils.java
bundles/org.simantics.graph.db/src/org/simantics/graph/db/StreamingTransferableGraphImportProcess.java
bundles/org.simantics.graph/src/org/simantics/graph/refactoring/FixExportedOntology.java
bundles/org.simantics.graph/src/org/simantics/graph/representation/PrettyPrintTG.java
bundles/org.simantics.graph/src/org/simantics/graph/representation/TransferableGraphUtils.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/PGraphEditorDocumentProvider.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/NodeTree.java [new file with mode: 0644]
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPage.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/Preferences.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/ModelImportWizard.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/sharedontology/wizard/SharedOntologyImportWizard.java
bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionRequest.java
bundles/org.simantics.modeling/src/org/simantics/modeling/requests/CollectionResult.java
bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Node.java
bundles/org.simantics.modeling/src/org/simantics/modeling/requests/Nodes.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/commands/CommandSession.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/header/ModuleHeader.java
bundles/org.simantics.scl.db/scl/Simantics/DB.scl
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/modulebrowser/ModuleNameTreeEntry.java
bundles/org.simantics.tests.modelled/META-INF/MANIFEST.MF
bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSRunner.java
bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/junit/v2/ModelledSTSSuiteRunner.java
bundles/org.simantics.tests.modelled/src/org/simantics/tests/modelled/utils/ModelledSTSTest.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR10.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR5.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR6.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR7.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR8.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/CHR9.scl
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record2.scl

index b1e5b8ec4da5cfdc5d41cc4f5242e01294ae7a43..0bfc3b1b12c52e543001fcbcf74d0d96bc7c4e7e 100644 (file)
@@ -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: <code><>:"/\|?*</code> 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;
+                }
+            }
+        }
+    }
+
 }
index 103c9bb0129259bd5dd0c2000410a95fc147bc53..5ccfcf325f49df3f919f6ee54f34b3d0f2033960 100644 (file)
@@ -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);
     }
 
     public static Resource getPossibleAssertedObject(ReadGraph graph, Resource resource, Resource predicate) throws DatabaseException {
index 78c369f96679f9ba467b76df8bdc9f074d28e503..9a819635463a8703651465c312bc688b3622326f 100644 (file)
@@ -163,8 +163,8 @@ public class StreamingTransferableGraphImportProcess implements TransferableGrap
        void addMissing(int handleIndex, String external) {
                allMissingExternals.put(external, handleIndex);
                Set<String> 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);
index ea449417d305ee7eac034af76e3ceadec07e7b79..1c567b1e21d39294f00652a0e8467e33cf803044 100644 (file)
@@ -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 {
index bb776d5df649eaa08ac455942e453718c9d2a721..0a0a86f0be45be0c0aff59fe6927a989df675120 100644 (file)
@@ -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<String,String> ontologies = new HashMap<>(knownOntologies);
-       final Set<String> 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<ResourceInfo> ownedBy
-               Set<ResourceInfo> ownedBy = new HashSet<>();
-               
-               // A Map<Integer, Integer> 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<TIntHashSet> statements = new TIntObjectHashMap<TIntHashSet>();
-               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<ResourceInfo> 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<statements.size();i+=2) {
-                       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);
-                               infos.put(object, existing);
-                               todo.add(object);
-                       }
-               }
-       }
-
-       void discoverOwners(TransferableGraph1 graph, ResourceInfo info) {
-           if (LOGGER.isDebugEnabled())
-               LOGGER.debug("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) {
+
+    private static final boolean DEBUG = false;
+
+    int blankCounter = 0;
+    int newBlankCounter = 0;
+    Map<String, String> blankRewrites = new HashMap<>();
+    MessageDigest m;
+
+    private final Pattern versionExtractPattern = Pattern.compile("^.*-(\\d+\\.\\d+)");
+
+    final StringBuilder output;
+    final Map<String, String> ontologies = new HashMap<>(knownOntologies);
+    final Set<String> 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<ResourceInfo> ownedBy
+        Set<ResourceInfo> ownedBy = new HashSet<>();
+
+        // A Map<Integer, Integer> 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<TIntHashSet> statements = new
+        // TIntObjectHashMap<TIntHashSet>();
+        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<String, ResourceInfo> orderedInfos = new TreeMap<>();
+    TIntObjectHashMap<ResourceInfo> 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<String, TreeSet<Integer>> sortByPredicateUniqueStatements(TransferableGraph1 graph, int resource) {
+        TreeMap<String, TreeSet<Integer>> 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<Integer> 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<statements.size();i+=2) {
+        for (TreeSet<Integer> 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<indent;i++)
-                   output.append("  ");
-       }
-       
-       String printBlank(TransferableGraph1 graph, String predicateURI2, ResourceInfo info, int indent) {
-
-               if(info.hasURI)
-                   return null;
-               
-               StringBuilder output = new StringBuilder();
-               indent(output, indent);
-               output.append(predicateURI2 + " " + info.name + "\n");
-
-               if (info.ownedResourcesWithPredicates.isEmpty()) {
-                   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();
-       }
-
-       static long longStm(int predicate, int object) {
-               return (predicate<<32) | (object & 0xffffffffL); 
-       }
-
-
-    private void addInlineStatement(TransferableGraph1 graph, Map<String, Set<String>> 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<String, Set<String>> statements, String predicate,
+            ResourceInfo objectInfo, int indent) {
         Set<String> 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<String,Set<String>> statements, String predicate, String object) {
-           // TODO: fix this
-           if (predicate.endsWith("Inverse"))
-               return;
-               Set<String> 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<String,Set<String>> 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<info.owned.size();i+=2) {
-                       long stmId = longStm(info.owned.get(i), info.owned.get(i+1));
-                       processed.add(stmId);
-               }
-               
-               TIntArrayList rawStatements = TransferableGraphUtils.getStatements(graph, info.resource);
-               for(int i=0;i<rawStatements.size();i+=2) {
-                       long stmId = longStm(rawStatements.get(i), rawStatements.get(i+1));
-                       if(!processed.add(stmId)) continue;
-                       if(consistsOf.resource == rawStatements.get(i)) continue;
-                       String predicateURI = rewritePredicateURI(graph, rawStatements.get(i));
-                       ResourceInfo objectInfo = infos.get(rawStatements.get(i+1));
-                       if(objectInfo == null) {
-                               String objectURI = rewritePredicateURI(graph, rawStatements.get(i+1));
-                               addStatement(statements, predicateURI, objectURI);
-                       } else if (objectInfo.ownedBy.size() == 1 && objectInfo.ownedBy.contains(info)) {
-                           // inline printing with _
-                           addInlineStatement(graph, statements, predicateURI, objectInfo, indent);
-                       } else {
-                               addStatement(statements, predicateURI, objectInfo.name);
-                       }
-               }
-
-               HashSet<ResourceInfo> 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<String, Set<String>> statements, String predicate, String object) {
+        // TODO: fix this
+        if (predicate.endsWith("Inverse"))
+            return;
+        Set<String> 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<String, Set<String>> 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<String, Integer> 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=<http:/>");
-                       } else if (info.aliasURI != null) {
-                               output.append(info.name + " = <" + info.aliasURI + ">");
-                       } else {
-                           if (inline)
-                               System.out.println("asdasd");
-                               output.append(inline ? "_" : info.name);
-                       }
-                       Set<String> instanceOfs = statements.get("L0.InstanceOf");
-                       if(instanceOfs != null) {
-                               for(String instanceOf : instanceOfs) {
-                                       output.append(" : " + instanceOf);              
-                               }
-                       }
-                       Set<String> subrelationOfs = statements.get("L0.SubrelationOf");
-                       if(subrelationOfs != null) {
-                               for(String subrelationOf : subrelationOfs) {
-                                       output.append(" <R " + subrelationOf);          
-                               }
-                       }
-                       Set<String> inherits = statements.get("L0.Inherits");
-                       if(inherits != null) {
-                               for(String inherit : inherits) {
-                                       output.append(" <T " + inherit);                
-                               }
-                       }
-                       output.append("\n");
-               }
-
-               if(info.newResource)
-                       output.append("  @L0.new\n");
-
-               for(Map.Entry<String, Set<String>> 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<String> 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<info.owned.size();i+=2) {
-                       String predicateURI = rewritePredicateURI(graph, info.owned.get(i));
-                       ResourceInfo ownedInfo = infos.get(info.owned.get(i+1));
-                       String blank = printBlank(graph, predicateURI, ownedInfo, indent+1);
-                       if (blank != null)
-                           output.append(blank);
-               }
-               
-               return output.toString();
-       }
+            if (DEBUG)
+                System.out.println("   " + stmId + " is currently being processed (" + (predicate & 0xffffffffL) + " "
+                        + (object & 0xffffffffL) + ")");
+            // if (partOf.resource == rawStatements.get(i))
+            // continue;
+            if (consistsOf.resource == predicate) {
+                // if (!info.owned.isEmpty() && !info.name.startsWith("blank"))
+                // {
+                if (DEBUG)
+                    System.out.println("  is consistsof " + predicate + " (" + consistsOf.resource + ")");
+                continue;
+                // } else {
+                // // this will be inlined so lets indent
+                // indent++;
+                // }
+            }
+            String predicateURI = rewritePredicateURI(graph, predicate);
+            predicateURIs.put(predicateURI, object);
+        }
+        for (Entry<String, Integer> 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=<http:/>");
+            } 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<String> instanceOfs = statements.get("L0.InstanceOf");
+            if (instanceOfs != null) {
+                for (String instanceOf : instanceOfs) {
+                    output.append(" : " + instanceOf);
+                }
+            }
+            Set<String> subrelationOfs = statements.get("L0.SubrelationOf");
+            if (subrelationOfs != null) {
+                for (String subrelationOf : subrelationOfs) {
+                    output.append(" <R " + subrelationOf);
+                }
+            }
+            Set<String> inherits = statements.get("L0.Inherits");
+            if (inherits != null) {
+                for (String inherit : inherits) {
+                    output.append(" <T " + inherit);
+                }
+            }
+            output.append("\n");
+        }
+
+        if (info.newResource)
+            output.append("  @L0.new\n");
+
+        for (Map.Entry<String, Set<String>> 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<String> 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<String, Integer> 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<String, Integer> 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<String,String> 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<String, String> 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<String,ResourceInfo> 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: <input .sharedOntology file> [<output .tg file>]");
-               } 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<String> 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<String, ResourceInfo> 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<String, ResourceInfo> 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<String> 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<ResourceInfo> 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<String, String> 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: <input .sharedOntology file> [<output .tg file>]");
+        } 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);
+    }
 
 }
index a7b92c8d015727880d256a9c17494bed54b70ce9..b210d8dd713348cb38fa846f6558509442d05276 100644 (file)
@@ -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<tg.statements.length;i+=4) {
                        if(tg.statements[i] == subject && tg.statements[i+1] == predicate.resource) {
-                               if(result != 0) return 0;
+                               if(result != 0 && tg.statements[i+3] != result) return 0;
                                result = tg.statements[i+3];
                        }
                }
                return result;
        }
+
+       public static final int NOT_FOUND = -2;
+
+       public static int getPossibleObject2(TransferableGraph1 tg, int subject, Identity predicate) {
+           int result = NOT_FOUND;
+        for(int i=0;i<tg.statements.length;i+=4) {
+            if(tg.statements[i] == subject && tg.statements[i+1] == predicate.resource) {
+                if(result != NOT_FOUND && tg.statements[i+3] != result)
+                    return NOT_FOUND;
+                result = tg.statements[i+3];
+            }
+        }
+        return result;
+       }
        
+       /**
+        * @return 0 for presenting not found which is BAD
+        * @see getPossibleObject2
+        */
+       @Deprecated
        public static int getPossibleObject(TransferableGraph1 tg, Identity subject, String predicate) {
                Identity p = findExternal(tg, predicate);
                if(p == null) return 0;
                return getPossibleObject(tg, subject.resource, p);
        }
+       
+    public static int getPossibleObject2(TransferableGraph1 tg, Identity subject, String predicate) {
+        Identity p = findExternal(tg, predicate);
+        if (p == null)
+            return NOT_FOUND;
+        return getPossibleObject2(tg, subject.resource, p);
+    }
 
        public static Map<Identity, String> getNames(TransferableGraph1 tg, Collection<Identity> ids) {
                Map<Identity, String> result = new HashMap<Identity, String>();
@@ -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 "<internal reference " + id + ">:";
-       }
-       
-       public static String getTrueURI(int resourceCount, TIntObjectMap<Identity> 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 "";
                        }
index eeaab985c2d6d5816c725655addfe4b03d2eb257..39152636b0e80aab3d9b18eaa439ce26ca839cf1 100644 (file)
@@ -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 (file)
index 0000000..a17aafb
--- /dev/null
@@ -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<Node, Boolean> isChecked = new HashMap<>();
+               Map<Node, Boolean> 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<Node>            selectedNodes;
+
+       protected CheckStateCache      checkStateCache = new CheckStateCache();
+
+       protected Runnable             selectionChangeListener;
+
+       protected CollectionResult     nodes;
+
+       public NodeTree(Composite parent, Set<Node> 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&lter:");
+               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<Node> getVisibleNodes() {
+               Collection<Node> result = new ArrayList<>();
+
+               Deque<TreeItem> 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<Node> 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<Node> 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<Node> 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<Object> 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<Node> nodes = new HashSet<>();
+                       Set<Node> 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
index f0c9cddb32514610ec850b0bb9b30919e5657516..461e98c10b1d10d4895230ec1b9e9fe7df85e9b7 100644 (file)
@@ -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<String>               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<String> decodePaths(String recentPathsPref) {
-        Deque<String> result = new LinkedList<String>();
+        Deque<String> 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<Resource> processed = new HashSet<>();
+                    List<NamedResource> models = new ArrayList<>();
 
-                    List<NamedResource> models = new ArrayList<NamedResource>();
-                    
                     Collection<Resource> 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<String> dups = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+            Set<String> dups = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
             for (Iterator<String> 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;
     }
index 7ef2efb9406f283b578f6bfdcabc7669d91e997a..fb2f8b0c640adf08c4dcfb845ca46ced5bfb880b 100644 (file)
@@ -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
  *
  * 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<Node>            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<Node> 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<Node> 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&lter:");
-        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<Node> nodes = new HashSet<Node>();
-                    Set<Node> 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<Object> result = new ArrayList<Object>( 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<Node> getVisibleNodes() {
-        Collection<Node> result = new ArrayList<Node>();
-
-        Deque<TreeItem> todo = new ArrayDeque<TreeItem>();
-        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<Node> 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<Resource> 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);
index a41715f3bc81e64d4eabb0c44323c523541b7c6c..73e5b09d2b4700c3d6a11e50153e224d020d7f9f 100644 (file)
@@ -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<NamedResource>       selectableModels = new ArrayList<NamedResource>();
     public NamedResource             selection;
     public Collection<String>        recentLocations;
index f248ca2fa5aad1067cda302c147f26e5b98244f9..97265df58bddd3f074426f70d07b3a3695912255 100644 (file)
@@ -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";
 
 }
index 235c304e6009f56942a8f288f17d703776f7fcad..9f9dc489e42af88a111b2705fa723bfcc70e6578 100644 (file)
@@ -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) {
index df65646346386755b7cecc2388350ac74824a652..8345c229eb8d5d6d4dca452a270e0d152fef43e9 100644 (file)
@@ -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) {
index 70aa8c88b100b7547fccc29ddb8ca2c7d9c6ef01..183717325bf0353a6d2a459d6b8577f914e3625e 100644 (file)
@@ -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<CollectionResult> {
         return g.syncRequest(new GetName(r));
     }
 
-//    Collection<String> getPartOfGroups(Resource diagram) throws DatabaseException {
-//        Resource r = diagram;
-//        Deque<String> result = new ArrayDeque<String>();
-//        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<CollectionResult> {
         SIMU = SimulationResource.getInstance(g);
 
         final CollectionResult result = new CollectionResult();
-        final Deque<Node> roots = new ArrayDeque<Node>();
+        final Deque<Node> 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<CollectionResult> {
                 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<CollectionResult> {
                     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<CollectionResult> {
 
             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<CollectionResult> {
 
         return result;
     }
-    
-    static class GetName extends ResourceRead<String> {
 
+    static class GetName extends ResourceRead<String> {
         public GetName(Resource resource) {
             super(resource);
         }
@@ -274,11 +214,10 @@ public class CollectionRequest implements Read<CollectionResult> {
         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
index ff06e43d0946bc10a6bb15a6155232e17631718c..c182c59c80120b7c5eff2814b7a073a07898fc44 100644 (file)
@@ -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<Node>           roots       = new ConcurrentSkipListSet<Node>();
-    final private Set<Node>          diagramSet  = new ConcurrentSkipListSet<Node>();
-    final public List<Node>          diagramList = new Vector<Node>();
-    final public Map<Resource, Node> diagrams    = new ConcurrentHashMap<Resource, Node>();
+    public final Set<Node>           roots;
+    private final Set<Node>          diagramSet;
+    public final List<Node>          diagramList;
+    public final Map<Resource, Node> diagrams;
+
+    public CollectionResult() {
+        this.roots       = new ConcurrentSkipListSet<Node>();
+        this.diagramSet  = new ConcurrentSkipListSet<Node>();
+        this.diagramList = new Vector<Node>();
+        this.diagrams    = new ConcurrentHashMap<Resource, Node>();
+    }
+
+    private CollectionResult(Set<Node> roots, Set<Node> diagramSet, List<Node> diagramList, Map<Resource, Node> diagrams) {
+        this.roots = roots;
+        this.diagramSet = diagramSet;
+        this.diagramList = diagramList;
+        this.diagrams = diagrams;
+    }
+
+    public CollectionResult withRoots(Set<Node> roots) {
+        return new CollectionResult(roots, diagramSet, diagramList, diagrams);
+    }
 
     public void addDiagram(Resource r, Node n) {
         diagramList.add(n);
index 3d52b2604df683a08b8f610420ec2f17d023e6cf..4a43e0840a907cecc3bfd0bfbc847113775e8161 100644 (file)
@@ -27,15 +27,12 @@ import org.simantics.utils.strings.AlphanumComparator;
  */
 public class Node implements Comparable<Node> {
 
-    public static final Comparator<Node> CASE_INSENSITIVE_COMPARATOR = new Comparator<Node>() {
-        @Override
-        public int compare(Node o1, Node o2) {
-            return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName());
-        }
-    };
+    public static final Comparator<Node> CASE_INSENSITIVE_COMPARATOR =
+            (o1, o2) -> AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1.getName(), o2.getName());
 
     private final Node       parent;
     private final List<Node> children = new ArrayList<Node>();
+    private final List<Node> unmodifiableChildren = Collections.unmodifiableList(children);
 
     /**
      * May be <code>null</code> if there is no diagram for this node.
@@ -44,10 +41,8 @@ public class Node implements Comparable<Node> {
     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<Node> {
             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<Node> {
     }
 
     public Collection<Node> getChildren() {
-        return Collections.unmodifiableCollection(children);
+        return unmodifiableChildren;
     }
 
-//    public void setPartOfGroups(Collection<String> 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() {
index 01c89aaf19cee51f5f0d45c6e5de3e448310a15b..5d1da87970420ab81ca22de772d679025201ea53 100644 (file)
@@ -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<Node> DIAGRAM_RESOURCE_PREDICATE = n -> n.getDiagramResource() != null;
+    public static final Predicate<Node> DIAGRAM_RESOURCE_AND_RVI_PREDICATE = n -> n.getDiagramResource() != null && n.getRVI() != null;
+
     public static Collection<Node> breadthFirstFlatten(IFilter filter, Collection<Node> roots) {
-        Collection<Node> result = new ArrayList<Node>();
-        List<Node> sortedRoots = new ArrayList<Node>(roots);
+        Collection<Node> result = new ArrayList<>();
+        List<Node> sortedRoots = new ArrayList<>(roots);
         Collections.sort(sortedRoots);
-        Deque<Node> todo = new ArrayDeque<Node>(sortedRoots);
+        Deque<Node> todo = new ArrayDeque<>(sortedRoots);
         while (!todo.isEmpty()) {
             Node n = todo.removeFirst();
-            List<Node> sorted = new ArrayList<Node>(n.getChildren());
+            List<Node> 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<Node> depthFirstFlatten(IFilter filter, Collection<Node> roots, Comparator<? super Node> comparator) {
-        Collection<Node> result = new ArrayList<Node>();
-        List<Node> sortedRoots = new ArrayList<Node>(roots);
+        Collection<Node> result = new ArrayList<>();
+        List<Node> 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<Node> sorted = new ArrayList<Node>(children);
+        List<Node> 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<Node, Boolean> filter, Collection<Node> roots) {
-        List<Node> sortedRoots = new ArrayList<Node>(roots);
+        List<Node> sortedRoots = new ArrayList<>(roots);
         Collections.sort(sortedRoots);
         for (Node n : sortedRoots)
             if (!walkTreeRec(filter, n))
@@ -81,7 +87,7 @@ public class Nodes {
 
         Collection<Node> children = n.getChildren();
         if (!children.isEmpty()) {
-            List<Node> sorted = new ArrayList<Node>(children);
+            List<Node> 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<Node> set, Node node) {
+        for (Node n = node.getParent(); n != null; n = n.getParent())
+            if (set.contains(n))
+                return true;
+        return false;
+    }
+
+    public static Set<Node> depthFirstFilter(Predicate<Node> filter, Collection<Node> nodes) {
+        Set<Node> 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<Node> filter, Node n) {
+        return depthFirstFilterRec(filter, n, null);
+    }
+
+    private static Node depthFirstFilterRec(Predicate<Node> filter, Node n, Node newParent) {
+        Collection<Node> 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;
+    }
+
 }
index a8f3d2045efb105928e18c951d1322410bd13a0f..d7f1aa11e568c2d5e1351c973e5022cb9a49eb5d 100644 (file)
@@ -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<String,Type> variableTypes = new THashMap<String,Type>();
     
     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<String> failedModules = new THashSet<String>();
                 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;
+    }
 }
index 80acf17c571cb242e2db401233525006f118908d..0ab17f83478313ee3f5df5209850ce3178b198ef 100644 (file)
@@ -12,6 +12,7 @@ public class ModuleHeader {
     public long classLoaderLocation;
     public String defaultLocalName;
     public List<EVar> 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<EVar> 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;
index 19e83d30b571a7dfd9cf197090b1fecbe72939ea..df556086ed6ab61d0aa1458f5d6da06e24955172 100644 (file)
@@ -343,7 +343,7 @@ importJava "org.simantics.db.layer0.util.Layer0Utils" where
     listOntologies :: () -> <ReadGraph> [Resource]
     emptyTrashBin :: () -> <Proc> ()
     purgeDatabase :: () -> <Proc> ()
-    prettyPrintResource :: Resource -> <ReadGraph> String
+    prettyPrintResource :: Resource -> Boolean -> <ReadGraph> String
 
     @private
     @JavaName copyTo
index cb2181912e1464b5978298c6b7314e81bdff6e48..a7eb4332333cc0cba1a4325c36e69b829c7a7a75 100644 (file)
@@ -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<CommandSessionImportEntry> 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<CommandSessionImportEntry> 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();
index 4c3bf1a2c9df1495da8bc101922c957f6fea9003..2461e5231e5535a504092acb15c0d132cb4b97c3 100644 (file)
@@ -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<ModuleNameTreeEntry> {
+    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<ModuleNameTreeEntry> {
     
     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<ModuleNameTreeEntry> {
     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);
         }
index 8f182947930bb09a6d637bf373bc9e0bdc1d8fc3..4cbcec294d7fcb3e1855994e398decc065ad105a 100644 (file)
@@ -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,
index 29628cec061e8b4ef5117da84d45947524cd3893..393174906afeb46e7530a71cdef4091c818507ec 100644 (file)
@@ -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<ModelledSTSSuiteRunner> {
 
+    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<ModelledSTSSuiteRunner> children;
 
     public ModelledSTSRunner(Class<?> testClass) throws InitializationError {
         super(testClass);
+
         try {
             initialize0();
             Collection<ModelledSTSSuite> suites = STSSuiteTestCollector.collectTests();
+            
+            // Filter exclusions
             String exclusionFilter = System.getProperty(EXCLUSION_FILTER);
             Collection<ModelledSTSSuite> filtered;
             if (exclusionFilter != null) {
@@ -36,7 +45,18 @@ public class ModelledSTSRunner extends ParentRunner<ModelledSTSSuiteRunner> {
             } else {
                 filtered = suites;
             }
+            // Filter inclusions
+//            String inclusionFilter = System.getProperty(INCLUSION_FILTER);
+//            Collection<ModelledSTSSuite> 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<ModelledSTSSuite> sorted = included.stream().sorted((o1, o2) -> Integer.compare(o1.getPriority(), o2.getPriority())).collect(Collectors.toList());
             List<ModelledSTSSuite> sorted = filtered.stream().sorted((o1, o2) -> Integer.compare(o1.getPriority(), o2.getPriority())).collect(Collectors.toList());
             
             
@@ -82,7 +102,12 @@ public class ModelledSTSRunner extends ParentRunner<ModelledSTSSuiteRunner> {
 
     @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<ModelledSTSSuiteRunner> {
 
     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());
     }
 }
index 11931d824c3990c432aece73020949d1bb058491..0bfb1f1ceaf02ab61476398c4075e2dead9e165b 100644 (file)
@@ -25,11 +25,40 @@ public class ModelledSTSSuiteRunner extends ParentRunner<ModelledSTSTestRunner>
         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<ModelledSTSTestRunner>
                 }
                 notifier.fireTestStarted(description);
                 List<CommandSessionVariable> 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));
index 33e4c25e2fc6b2f121bd3e6264a1ede8b3f09068..c0ed9b191420604d49cfc73edd636d9f00928920 100644 (file)
@@ -94,6 +94,7 @@ public class ModelledSTSTest {
     
     public List<CommandSessionVariable> run(List<CommandSessionVariable> 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());
index 758074d32dbfd0c6d83348ec3d3b49341264c8b1..8f587d508aeedb2a0beff3cb32ee7d77a7adb41f 100644 (file)
@@ -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 }
index c59c02dbb2b3a65cefd61c6266e5a3d94b71043d..6803c113ed039d418a2c0ce7f86df32c1b8de69c 100644 (file)
@@ -1,4 +1,4 @@
-module { export = [main], chr }
+module { export = [main], features = [chr] }
 import "StandardLibrary"
 
 ruleset IntegerSet where
index f1e28d08a157bfb9ca324cd7ef6ce58c1aee1d93..76f0408a0a5773001fd9b1f4168b52d5c8d62a53 100644 (file)
@@ -1,4 +1,4 @@
-module { export = [main], chr }
+module { export = [main], features = [chr] }
 import "StandardLibrary"
 
 ruleset RS where
index b10257ca89a4144dcfbb75fbf001c6e129d918b4..6e878ebf45ac8c32ae3c705ce9800019f29452ea 100644 (file)
@@ -1,4 +1,4 @@
-module { export = [main], chr }
+module { export = [main], features = [chr] }
 import "StandardLibrary"
 
 ruleset RS where
index c3a88f58a7199f59ccde3a512046d978ad3fe7bd..dd915ebb5d10b971f5ec7cccc8cc3d7440a16cca 100644 (file)
@@ -1,4 +1,4 @@
-module { export = [main], chr }
+module { export = [main], features = [chr] }
 import "StandardLibrary"
 
 main = ()
index 07514821a38342bc720b20a17aa6c58e2753794d..427b8df6b765032204c955f6bf405e359963c9db 100644 (file)
@@ -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"