Merge "(refs #7307) Added features field to SCL module header"
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Thu, 15 Jun 2017 07:45:30 +0000 (10:45 +0300)
committerGerrit Code Review <gerrit2@www.simantics.org>
Thu, 15 Jun 2017 07:45:30 +0000 (10:45 +0300)
31 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.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.spreadsheet.graph/src/org/simantics/spreadsheet/graph/ExcelImport.java
bundles/org.simantics.tests.modelled.ui/plugin.xml
bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSEditorAdapter.java
bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerAdapter.java [new file with mode: 0644]
bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerEditor.java [new file with mode: 0644]
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

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 08dd63ce0e25c4bf11084bc8402eb802cd51a49d..198ee41b77e060ad4cdf205e46a10038cbaa494b 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);
     }
 
 }
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..23ce5e56c1258033749ad5695ad4d6635b048b39 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;
@@ -43,7 +49,11 @@ public class PrettyPrintTG {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(PrettyPrintTG.class);
     
+    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+)");
@@ -52,9 +62,11 @@ public class PrettyPrintTG {
        final Map<String,String> ontologies = new HashMap<>(knownOntologies);
        final Set<String> referencedOntologies = new TreeSet<>();
 
+    private boolean ignoreIdentifiers;
+
        static class ResourceInfo {
                final boolean hasURI;
-               final String name;
+               String name;
                final int resource;
                boolean newResource = false;
                
@@ -88,15 +100,17 @@ public class PrettyPrintTG {
                }
        }
 
-       public PrettyPrintTG(StringBuilder b) throws NoSuchAlgorithmException {
+       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());
+               this(new StringBuilder(), false);
        }
 
+       TreeMap<String, ResourceInfo> orderedInfos = new TreeMap<>();
        TIntObjectHashMap<ResourceInfo> infos = new TIntObjectHashMap<>();
 
        String tgNodeName(String name) {
@@ -106,39 +120,71 @@ public class PrettyPrintTG {
 
        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);
+               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) {
-                       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);
-                       }
+//             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);
+//                    existing = new ResourceInfo(false, "blank" + makeHash(statementHash.toString().getBytes()), object, resource);
+                               
+                               String resourceURI = TransferableGraphUtils.getURI(graph, resource);
+                               String objectURI = TransferableGraphUtils.getURI(graph, object);
+                               
+    //                         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) {
-           if (LOGGER.isDebugEnabled())
-               LOGGER.debug("Discovering owners for " + 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) {
@@ -147,14 +193,19 @@ public class PrettyPrintTG {
                        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);
-                            }
+                           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("    " + existing + " owns " + info + " with " + predicateUri);
+//                             }
+                           } else {
+//                             System.out.println("asd");
                            }
                        }
                }
@@ -304,10 +355,27 @@ public class PrettyPrintTG {
                    return null;
                
                StringBuilder output = new StringBuilder();
-               indent(output, indent);
-               output.append(predicateURI2 + " " + info.name + "\n");
+               
+               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);
@@ -318,10 +386,21 @@ public class PrettyPrintTG {
                return output.toString();
        }
 
-       static long longStm(int predicate, int object) {
-               return (predicate<<32) | (object & 0xffffffffL); 
-       }
+    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);
@@ -362,43 +441,79 @@ public class PrettyPrintTG {
 
                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) {
-                       long stmId = longStm(info.owned.get(i), info.owned.get(i+1));
+                   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) {
-                       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));
+                   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;
+                       }
+                       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, rawStatements.get(i+1));
+                               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 {
-                               addStatement(statements, predicateURI, objectInfo.name);
+                String objectName = objectInfo.name;
+                if (objectName.startsWith("blank")) {
+                    objectName = getBlankRewrite(objectName);
+                }
+                           if (DEBUG)
+                               System.out.println("  adding statement " + predicateURI + " " + objectName);
+                               addStatement(statements, predicateURI, objectName);
                        }
                }
 
-               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;
-            }
-        });
-
+               if (DEBUG)
+                   System.out.println("statements size for " + info.name + " : " + statements.size() + " " + statements.keySet());
+               
                StringBuilder output = new StringBuilder();
                
                if(indent == 0 || inline) {
@@ -407,9 +522,11 @@ public class PrettyPrintTG {
                        } else if (info.aliasURI != null) {
                                output.append(info.name + " = <" + info.aliasURI + ">");
                        } else {
-                           if (inline)
-                               System.out.println("asdasd");
-                               output.append(inline ? "_" : info.name);
+                           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) {
@@ -437,10 +554,21 @@ public class PrettyPrintTG {
 
                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) {
@@ -454,13 +582,27 @@ public class PrettyPrintTG {
                        }
                }
 
+               TreeMap<String, Integer> ownedOrdered = new TreeMap<>();
+               
                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));
+                       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)
+                       if (blank != null) {
                            output.append(blank);
-               }
+                       }
+               }               
                
                return output.toString();
        }
@@ -503,37 +645,32 @@ public class PrettyPrintTG {
 
        
        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");
+           log("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);
+                                   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;
-                                       infos.put(id.resource, info);
-                    if (LOGGER.isDebugEnabled())
-                        LOGGER.debug("    which parent is external " + parent + " and has an aliasURI " + info.aliasURI) ;
+                                       orderedInfos.put(name, info);
+//                                     infos.put(id.resource, info);
+                                       log("    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");
+                                       log("    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);
+                                   log("Detected an external shared library " + ext);
                                    
                                        int index = ext.name.indexOf('@');
                                        String prefix = ext.name.substring(0, index);
@@ -541,35 +678,36 @@ public class PrettyPrintTG {
                                        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);
+                                       log("    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);
+                                   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=" + uri + " and prefix " + prefix);
                             ontologies.put(uri, prefix);
                                        }
                                }
                                }
                        }
                }
+               
                // Discover other resources
-               if (LOGGER.isDebugEnabled())
-                   LOGGER.debug("Discovering other resources..");
+               log("Discovering other resources..");
                
                TIntArrayList todo = new TIntArrayList();
-               for(ResourceInfo info : infos.valueCollection())
+               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);
@@ -614,23 +752,153 @@ public class PrettyPrintTG {
             }
         }
         
+        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) {
-                       String uri = printURI(graph, info, false, 0, false);
-                       if (uri != null)
-                           output.append(uri);
+                       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);
@@ -645,10 +913,64 @@ public class PrettyPrintTG {
                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) throws Exception {
+    public static String print(TransferableGraph1 tg, boolean ignoreIdentifiers) throws Exception {
                StringBuilder b = new StringBuilder();
-               new PrettyPrintTG(b).prettyPrint(tg);
+               new PrettyPrintTG(b, ignoreIdentifiers).prettyPrint(tg);
                return b.toString();
        }
 
@@ -664,4 +986,9 @@ public class PrettyPrintTG {
                }
        }
 
+    private static void log(String string) {
+        if (LOGGER.isDebugEnabled() && DEBUG)
+            LOGGER.debug(string);
+    }
+
 }
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 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 81fd2cfd4fb183277c7ea047819c6a66edd343a0..8b2d9af4f520530f2686ee34dadf6b2415ce4233 100644 (file)
@@ -56,7 +56,7 @@ public class ExcelImport {
        private static final double POINT_TO_PIXEL_RATIO = 1.33;
        
        public static void importBook(Resource container, File file) {
-           importBook(container, file);
+           importBookR(container, file);
        }
        
     public static Resource importBookR(Resource container, File file) {
index 150c2939cae1a1a25d10e10b90fc5124d27ffc7c..a97b43046f4de5b47cfbc69f5e2fe53573197662 100644 (file)
@@ -9,6 +9,12 @@
             class="org.simantics.tests.modelled.ui.STSTestEditor"
             id="org.simantics.tests.ui.stsTestEditor">
       </editor>
+      <editor
+            default="false"
+            name="STS Variable Viewer"
+            class="org.simantics.tests.modelled.ui.STSVariableViewerEditor"
+            id="org.simantics.tests.ui.stsVariableViewer">
+      </editor>
    </extension>
    <extension
          point="org.eclipse.core.expressions.definitions">
             id="org.simantics.tests.ui.stsTestEditor"
             priority="10">
       </adapterClass>
+      <adapterClass
+            class="org.simantics.tests.modelled.ui.STSVariableViewerAdapter"
+            id="org.simantics.tests.ui.stsVariableViewer"
+            priority="11">
+      </adapterClass>
    </extension>
    <extension
          point="org.eclipse.ui.elementFactories">
             class="org.simantics.tests.modelled.ui.STSEditorInputFactory"
             id="org.simantics.tests.modelled.ui.stseditor.inputFactory">
       </factory>
+      <!--<factory
+            class="org.simantics.tests.modelled.ui.STSVariableViewerInputFactory"
+            id="org.simantics.tests.modelled.ui.stsVariableViewer.inputFactory">
+      </factory>-->
    </extension>
    <extension
          point="org.eclipse.ui.views">
index 363087f76304678bccc4ea92160a255329714923..fd3ec1ba42c36d3ee0c1a5c17932b113d3168fad 100644 (file)
@@ -22,7 +22,7 @@ public class STSEditorAdapter extends AbstractResourceEditorAdapter implements E
     private static final Logger LOGGER = LoggerFactory.getLogger(STSEditorAdapter.class);
     
     public STSEditorAdapter() {
-        super("SCL Module Editor", null, 20);
+        super("STS Test Editor", null, 20);
     }
     
     @Override
diff --git a/bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerAdapter.java b/bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerAdapter.java
new file mode 100644 (file)
index 0000000..9ab16f1
--- /dev/null
@@ -0,0 +1,120 @@
+package org.simantics.tests.modelled.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+import org.simantics.tests.modelled.ontology.TestsResource;
+import org.simantics.ui.workbench.editor.AbstractResourceEditorAdapter;
+import org.simantics.ui.workbench.editor.EditorAdapter;
+import org.simantics.utils.ui.workbench.WorkbenchUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class STSVariableViewerAdapter extends AbstractResourceEditorAdapter implements EditorAdapter {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(STSVariableViewerAdapter.class);
+    
+    public STSVariableViewerAdapter() {
+        super("STS Variable Viewer", null, 20);
+    }
+    
+    @Override
+    public boolean canHandle(ReadGraph g, Object input)
+            throws DatabaseException {
+        if(input instanceof IStructuredSelection)
+            input = ((IStructuredSelection)input).getFirstElement();
+        if(!(input instanceof Resource)) {
+            if(input instanceof IAdaptable) {
+                input = ((IAdaptable)input).getAdapter(Resource.class);
+                if(input == null)
+                    return false;
+            }
+            else
+                return false;
+        }
+        Resource resource = (Resource)input;
+        return g.isInstanceOf(resource, TestsResource.getInstance(g).STSVariable);
+    }
+    
+    protected void openEditor(Resource input) throws Exception {
+        IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+        if(page == null)
+            return;
+        Simantics.getSession().asyncRequest(new ReadRequest() {
+            @Override
+            public void run(ReadGraph graph) throws DatabaseException {
+                String variableName = graph.getRelatedValue2(input, Layer0.getInstance(graph).HasName, Bindings.STRING);
+                String contents = graph.getRelatedValue2(input, TestsResource.getInstance(graph).STSVariable_definition, Bindings.STRING);
+                PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            WorkbenchUtils.openEditor("org.simantics.tests.ui.stsVariableViewer", new STSVariableViewerEditorInput(variableName, contents));
+//                            WorkbenchUtils.openEditor("org.simantics.tests.ui.stsVariableViewer", new STSTestEditorInput(uri));
+                        } catch (PartInitException e) {
+                            LOGGER.error("Could not initialize part", e);
+                        }
+                    }
+                });
+            }
+        });
+    }
+    
+    public static class STSVariableViewerEditorInput implements IEditorInput {
+
+        private String name;
+        private String contents;
+
+        public STSVariableViewerEditorInput(String name, String contents) {
+            this.name = name;
+            this.contents = contents;
+        }
+        
+        @Override
+        public <T> T getAdapter(Class<T> adapter) {
+            return null;
+        }
+
+        @Override
+        public boolean exists() {
+            return true;
+        }
+
+        @Override
+        public ImageDescriptor getImageDescriptor() {
+            return null;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public IPersistableElement getPersistable() {
+            return null;
+        }
+
+        @Override
+        public String getToolTipText() {
+            return null;
+        }
+
+        public String getContents() {
+            return contents;
+        }
+    }
+
+}
diff --git a/bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerEditor.java b/bundles/org.simantics.tests.modelled.ui/src/org/simantics/tests/modelled/ui/STSVariableViewerEditor.java
new file mode 100644 (file)
index 0000000..9347c4e
--- /dev/null
@@ -0,0 +1,42 @@
+package org.simantics.tests.modelled.ui;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.AbstractDocumentProvider;
+import org.simantics.tests.modelled.ui.STSVariableViewerAdapter.STSVariableViewerEditorInput;
+
+public class STSVariableViewerEditor extends TextEditor {
+
+    public STSVariableViewerEditor() {
+        setDocumentProvider(new STSVariableViewerDocumentProvider());
+    }
+
+    private static class STSVariableViewerDocumentProvider extends AbstractDocumentProvider {
+
+        @Override
+        protected IDocument createDocument(Object element) throws CoreException {
+            STSVariableViewerEditorInput input = (STSVariableViewerEditorInput) element;
+            return new Document(input.getContents());
+        }
+
+        @Override
+        protected IAnnotationModel createAnnotationModel(Object element) throws CoreException {
+            return null;
+        }
+
+        @Override
+        protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException {
+        }
+
+        @Override
+        protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
+            return null;
+        }
+
+    }
+}
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..31077a080d75d8e2c18352dab1a2dbdc264d70f4 100644 (file)
@@ -19,6 +19,7 @@ import org.simantics.tests.modelled.utils.STSSuiteTestCollector;
 
 public class ModelledSTSRunner extends ParentRunner<ModelledSTSSuiteRunner> {
 
+    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;
@@ -28,6 +29,8 @@ public class ModelledSTSRunner extends ParentRunner<ModelledSTSSuiteRunner> {
         try {
             initialize0();
             Collection<ModelledSTSSuite> suites = STSSuiteTestCollector.collectTests();
+            
+            // Filter exclusions
             String exclusionFilter = System.getProperty(EXCLUSION_FILTER);
             Collection<ModelledSTSSuite> filtered;
             if (exclusionFilter != null) {
@@ -36,7 +39,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());
             
             
@@ -96,11 +110,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..ac42653e57d5536ce776cfd47092413b3ca8ef86 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 = false;
+            if (exclusionFilter != null) {
+                String[] filters = exclusionFilter.split(",");
+                if (!startsWithAny(test, filters)) {
+                    add = true;
+                }
+            }
+            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());